svn update: 48676 (latest:48959)
authorYoumin Ha <youmin.ha@samsung.com>
Tue, 18 May 2010 07:17:11 +0000 (16:17 +0900)
committerYoumin Ha <youmin.ha@samsung.com>
Tue, 18 May 2010 07:17:11 +0000 (16:17 +0900)
113 files changed:
AUTHORS [new file with mode: 0644]
COPYING [new file with mode: 0644]
COPYING-PLAIN [new file with mode: 0644]
ChangeLog [new file with mode: 0644]
INSTALL [new file with mode: 0644]
Makefile.am [new file with mode: 0644]
NEWS [new file with mode: 0644]
README [new file with mode: 0644]
autogen.sh [new file with mode: 0755]
configure.ac [new file with mode: 0644]
data/.cvsignore [new file with mode: 0644]
data/Makefile.am [new file with mode: 0644]
data/edc.vba [new file with mode: 0644]
data/edc.vim [new file with mode: 0644]
data/edje-mode.el [new file with mode: 0644]
data/edje.xml [new file with mode: 0644]
data/include/.cvsignore [new file with mode: 0644]
data/include/Makefile.am [new file with mode: 0644]
data/include/edje.inc [new file with mode: 0644]
debian/SVN_REV [new file with mode: 0644]
debian/_original/changelog [new file with mode: 0644]
debian/_original/compat [new file with mode: 0644]
debian/_original/control [new file with mode: 0644]
debian/_original/copyright [new file with mode: 0644]
debian/_original/edje_cc.1 [new file with mode: 0644]
debian/_original/edje_decc.1 [new file with mode: 0644]
debian/_original/edje_recc.1 [new file with mode: 0644]
debian/_original/libedje-bin.install [new file with mode: 0644]
debian/_original/libedje-bin.manpages [new file with mode: 0644]
debian/_original/libedje-dev.install [new file with mode: 0644]
debian/_original/libedje-doc.dirs [new file with mode: 0644]
debian/_original/libedje-doc.doc-base [new file with mode: 0644]
debian/_original/libedje-svn-01.install [new file with mode: 0644]
debian/_original/libedje-svn-01.shlibs [new file with mode: 0644]
debian/_original/rules [new file with mode: 0755]
doc/.cvsignore [new file with mode: 0644]
doc/Doxyfile [new file with mode: 0644]
doc/Makefile.am [new file with mode: 0644]
doc/e.css [new file with mode: 0644]
doc/edje.dox.in [new file with mode: 0644]
doc/examples/lua_set_state.edc [new file with mode: 0644]
doc/examples/lua_set_text.edc [new file with mode: 0644]
doc/examples/lua_timer.edc [new file with mode: 0644]
doc/foot.html [new file with mode: 0644]
doc/head.html [new file with mode: 0644]
doc/img/e.png [new file with mode: 0644]
doc/img/edoxy.css [new file with mode: 0644]
doc/img/elementary.png [new file with mode: 0644]
doc/img/foot_bg.png [new file with mode: 0644]
doc/img/head_bg.png [new file with mode: 0644]
doc/img/header_menu_background.png [new file with mode: 0644]
doc/img/header_menu_background_last.png [new file with mode: 0644]
doc/img/header_menu_current_background.png [new file with mode: 0644]
doc/img/header_menu_unselected_background.png [new file with mode: 0644]
doc/img/logo.png [new file with mode: 0644]
edje.pc.in [new file with mode: 0644]
edje.spec.in [new file with mode: 0644]
edje.supp [new file with mode: 0644]
m4/ac_attribute.m4 [new file with mode: 0644]
m4/efl_binary.m4 [new file with mode: 0644]
m4/efl_doxygen.m4 [new file with mode: 0644]
m4/efl_path_max.m4 [new file with mode: 0644]
src/.cvsignore [new file with mode: 0644]
src/Makefile.am [new file with mode: 0644]
src/bin/.cvsignore [new file with mode: 0644]
src/bin/Makefile.am [new file with mode: 0644]
src/bin/edje_cc.c [new file with mode: 0644]
src/bin/edje_cc.h [new file with mode: 0644]
src/bin/edje_cc_handlers.c [new file with mode: 0644]
src/bin/edje_cc_mem.c [new file with mode: 0644]
src/bin/edje_cc_out.c [new file with mode: 0644]
src/bin/edje_cc_parse.c [new file with mode: 0644]
src/bin/edje_cc_sources.c [new file with mode: 0644]
src/bin/edje_decc.c [new file with mode: 0644]
src/bin/edje_decc.h [new file with mode: 0644]
src/bin/edje_player.c [new file with mode: 0644]
src/bin/edje_prefix.c [new file with mode: 0644]
src/bin/edje_prefix.h [new file with mode: 0644]
src/bin/edje_recc [new file with mode: 0644]
src/lib/.cvsignore [new file with mode: 0644]
src/lib/Edje.h [new file with mode: 0644]
src/lib/Edje_Edit.h [new file with mode: 0644]
src/lib/Makefile.am [new file with mode: 0644]
src/lib/edje_cache.c [new file with mode: 0644]
src/lib/edje_calc.c [new file with mode: 0644]
src/lib/edje_callbacks.c [new file with mode: 0644]
src/lib/edje_container.c [new file with mode: 0644]
src/lib/edje_container.h [new file with mode: 0644]
src/lib/edje_data.c [new file with mode: 0644]
src/lib/edje_edit.c [new file with mode: 0644]
src/lib/edje_embryo.c [new file with mode: 0644]
src/lib/edje_entry.c [new file with mode: 0644]
src/lib/edje_external.c [new file with mode: 0644]
src/lib/edje_load.c [new file with mode: 0644]
src/lib/edje_lua.c [new file with mode: 0644]
src/lib/edje_lua2.c [new file with mode: 0644]
src/lib/edje_lua_script_only.c [new file with mode: 0644]
src/lib/edje_main.c [new file with mode: 0644]
src/lib/edje_match.c [new file with mode: 0644]
src/lib/edje_message_queue.c [new file with mode: 0644]
src/lib/edje_misc.c [new file with mode: 0644]
src/lib/edje_module.c [new file with mode: 0644]
src/lib/edje_private.h [new file with mode: 0644]
src/lib/edje_program.c [new file with mode: 0644]
src/lib/edje_script_only.c [new file with mode: 0644]
src/lib/edje_smart.c [new file with mode: 0644]
src/lib/edje_text.c [new file with mode: 0644]
src/lib/edje_textblock_styles.c [new file with mode: 0644]
src/lib/edje_util.c [new file with mode: 0644]
src/lib/edje_var.c [new file with mode: 0644]
utils/Makefile.am [new file with mode: 0644]
utils/gimp-edje-export.py [new file with mode: 0755]
utils/inkscape2edc [new file with mode: 0755]

diff --git a/AUTHORS b/AUTHORS
new file mode 100644 (file)
index 0000000..5bf9a86
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,7 @@
+The Rasterman (Carsten Haitzler) <raster@rasterman.com>
+Tilman Sauerbeck (tilman at code-monkey de)
+ZigsMcKenzie <zigsmckenzie@gmail.com>
+Cedric BAIL <cedric.bail@free.fr>
+Brian Mattern <rephorm@rephorm.com>
+Mathieu Taillefumier <mathieu.taillefumier@free.fr>
+Tristan <blunderer@gmail.com>
diff --git a/COPYING b/COPYING
new file mode 100644 (file)
index 0000000..9690c3f
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,32 @@
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to
+deal in the Software without restriction, including without limitation the
+rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies of the Software and its Copyright notices. In addition publicly
+documented acknowledgment must be given that this software has been used if no
+source code of this software is made available publicly. Making the source
+available publicly means including the source for this software with the
+distribution, or a method to get this software via some reasonable mechanism
+(electronic transfer via a network or media) as well as making an offer to
+supply the source on request. This Copyright notice serves as an offer to
+supply the source on on request as well. Instead of this, supplying
+acknowledgments of use of this software in either Copyright notices, Manuals,
+Publicity and Marketing documents or any documentation provided with any
+product containing this software. This License does not apply to any software
+that links to the libraries provided by this software (statically or
+dynamically), but only to the software provided.
+
+Please see the COPYING-PLAIN for a plain-english explanation of this notice
+and its intent.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/COPYING-PLAIN b/COPYING-PLAIN
new file mode 100644 (file)
index 0000000..376875e
--- /dev/null
@@ -0,0 +1,33 @@
+Plain English Copyright Notice
+
+This file is not intended to be the actual License. The reason this file
+exists is that we here are programmers and engineers. We aren't lawyers. We
+provide licenses that we THINK say the right things, but we have our own
+intentions at heart. This is a plain-english explanation of what those
+intentions are, and if you follow them you will be within the "spirit" of
+the license.
+
+The intent is for us to enjoy writing software that is useful to us (the
+AUTHORS) and allow others to use it freely and also benefit from the work we
+put into making it. We don't want to restrict others using it. They should
+not *HAVE* to make the source code of the applications they write that
+simply link to these libraries (be that statically or dynamically), or for
+them to be limited as to what license they choose to use (be it open, closed
+or anything else). But we would like to know you are using these libraries.
+We simply would like to know that it has been useful to someone. This is why
+we ask for acknowledgement of some sort.
+
+You can do what you want with the source of this software - it doesn't
+matter. We still have it here for ourselves and it is open and free to use
+and download and play with. It can't be taken away. We don't really mind what
+you do with the source to your software. We would simply like to know that
+you are using it - especially if it makes it to a commerical product. If you
+simply e-mail all the AUTHORS (see COPYING and AUTHORS files) telling us, and
+then make sure you include a paragraph or page in the manual for the product
+with the copyright notice and state that you used this software, we will be
+very happy. If you want to contribute back modifications and fixes you may have
+made we will welcome those too with open arms (generally). If you want help
+with changes needed, ports needed or features to be added, arrangements can
+be easily made with some dialogue.
+
+Carsten Haitzler <raster@rasterman.com>
diff --git a/ChangeLog b/ChangeLog
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/INSTALL b/INSTALL
new file mode 100644 (file)
index 0000000..c7bf98a
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,14 @@
+COMPILING and INSTALLING:
+
+If you got a official release tar archive do:
+    ./configure
+    
+( otherwise if you got this from enlightenment cvs do: ./autogen.sh )
+    
+Then to compile:
+    make
+
+To install (run this as root, or the user who handles installs):
+    make install
+
+NOTE: You MUST make install Edje for it to run properly.
diff --git a/Makefile.am b/Makefile.am
new file mode 100644 (file)
index 0000000..ea89bbf
--- /dev/null
@@ -0,0 +1,40 @@
+ACLOCAL_AMFLAGS = -I m4
+
+SUBDIRS = data src utils doc
+
+MAINTAINERCLEANFILES = Makefile.in aclocal.m4 config.guess \
+                       config.h.in config.sub configure install-sh \
+                      ltconfig ltmain.sh missing mkinstalldirs \
+                      stamp-h.in edje_docs.tar edje_docs.tar.gz edje.c \
+                      edje.spec depcomp compile edje.pc
+
+### this is all fine and great - but edje should not be going and installing
+### data in another software's data dir - it's just wrong. not to mention this
+### also breaks make distcheck...
+#      if test "x${vimdir}" != "x"; then \
+#        $(mkinstalldirs) $(DESTDIR)$(vimdir)/syntax; \
+#        cp -p $(srcdir)/data/edc.vim $(DESTDIR)$(vimdir)/syntax/; \
+#      fi
+
+bin_SCRIPTS = 
+
+EXTRA_DIST = \
+AUTHORS \
+COPYING \
+COPYING-PLAIN \
+autogen.sh \
+edje.pc.in \
+edje.spec \
+edje.spec.in \
+README
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = edje.pc
+
+.PHONY: doc
+
+# Documentation
+
+doc:
+       @echo "entering doc/"
+       make -C doc doc
diff --git a/NEWS b/NEWS
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..839bbcb
--- /dev/null
+++ b/README
@@ -0,0 +1,82 @@
+Edje 0.5.0
+
+Requirements:
+-------------
+
+Must:
+  libc libm eet ecore ecore-evas ecore-job ecore-file embryo evas
+
+A graphical layout and animation library for animated resizable, compressed and
+scalable themes.
+
+It's current under development and isn't complete. See src/lib/edje_private.h
+for a list of FIXME's to do. Hopefully it will be complete in a few weeks.
+
+Quick start-up guide:
+
+1. You need eet from the HEAD cvs branch (must be up-to-date)
+
+  cvs co e17/libs/eet
+  cd e17/libs/eet
+  ./autogen.sh
+  make
+  sudo make install
+  cd
+
+2. You need evas from the HEAD branch built with eet loader support.
+
+  cvs co e17/libs/evas
+  cd e17/libs/evas
+  ./autogen.sh
+  make
+  sudo make install
+  cd
+  
+3. You need ecore from the HEAD cvs branch
+
+  cvs co e17/libs/ecore
+  cd e17/libs/ecore
+  ./autogen.sh
+  make
+  sudo make install
+  cd
+
+4. You need embryo from the HEAD cvs branch
+
+  cvs co e17/libs/embryo
+  cd e17/libs/embryo
+  ./autogen.sh
+  make
+  sudo make install
+  cd
+
+5. You already have Edje. now build it:
+
+   ./autogen.sh
+   make
+   sudo make install
+
+You now want to go test it out. first you'll need to make an Edje EET file.
+   
+   cd data
+   ./e_logo.sh
+   
+Now you can view the Edje you just built:
+   
+   edje ./e_logo.edj
+   
+You can view multiple files at once with the Edje test program:
+   
+   edje ./e_logo.edj ./e_logo.edj ./e_logo.edj
+   
+to view the same one 3 times.
+   
+You can read the source file that builds the Edje EET file by looking at:
+
+   data/src/e_logo.edc
+
+Another test file is also there:
+
+   data/src/test.edc
+   
+The test file doesn't build anything useful at the moment.
diff --git a/autogen.sh b/autogen.sh
new file mode 100755 (executable)
index 0000000..995ff2f
--- /dev/null
@@ -0,0 +1,16 @@
+#!/bin/sh
+
+rm -rf autom4te.cache
+rm -f aclocal.m4 ltmain.sh
+
+touch README
+
+echo "Running aclocal..." ; aclocal $ACLOCAL_FLAGS -I m4 || exit 1
+echo "Running autoheader..." ; autoheader || exit 1
+echo "Running autoconf..." ; autoconf || exit 1
+echo "Running libtoolize..." ; (libtoolize --copy --automake || glibtoolize --automake) || exit 1
+echo "Running automake..." ; automake --add-missing --copy --gnu || exit 1
+
+if [ -z "$NOCONFIGURE" ]; then
+       ./configure "$@"
+fi
diff --git a/configure.ac b/configure.ac
new file mode 100644 (file)
index 0000000..2aee24c
--- /dev/null
@@ -0,0 +1,355 @@
+# get rid of that stupid cache mechanism
+rm -f config.cache
+
+AC_INIT([edje], [0.9.93.063], [enlightenment-devel@lists.sourceforge.net])
+release="ver-pre-svn-05"
+AC_PREREQ([2.52])
+AC_CONFIG_SRCDIR([configure.ac])
+AC_CONFIG_MACRO_DIR([m4])
+AC_CANONICAL_BUILD
+AC_CANONICAL_HOST
+AC_ISC_POSIX
+
+AM_INIT_AUTOMAKE([1.6 dist-bzip2])
+AM_CONFIG_HEADER([config.h])
+m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
+
+AC_LIBTOOL_WIN32_DLL
+define([AC_LIBTOOL_LANG_CXX_CONFIG], [:])dnl
+define([AC_LIBTOOL_LANG_F77_CONFIG], [:])dnl
+AC_PROG_LIBTOOL
+
+VMAJ=`echo $PACKAGE_VERSION | awk -F. '{printf("%s", $1);}'`
+VMIN=`echo $PACKAGE_VERSION | awk -F. '{printf("%s", $2);}'`
+VMIC=`echo $PACKAGE_VERSION | awk -F. '{printf("%s", $3);}'`
+SNAP=`echo $PACKAGE_VERSION | awk -F. '{printf("%s", $4);}'`
+version_info=`expr $VMAJ + $VMIN`":$VMIC:$VMIN"
+AC_SUBST(version_info)
+
+case "$host_os" in
+   mingw32ce* | cegcc*)
+      ;;
+   *)
+      release_info="-release $release"
+      ;;
+esac
+AC_SUBST(release_info)
+
+AC_DEFINE_UNQUOTED([SHARED_LIB_SUFFIX], ["$shrext_cmds"], [Suffix for shared objects])
+
+EFL_CHECK_PATH_MAX
+
+### Default options with respect to host
+
+case "$host_os" in
+   mingw32ce* | cegcc*)
+      install_vim="no"
+      have_edje_cc="no"
+      ;;
+   *)
+      install_vim="yes"
+      have_edje_cc="yes"
+      ;;
+esac
+
+requirement_edje=""
+
+
+### Additional options to configure
+
+AC_ARG_ENABLE([amalgamation],
+   [AC_HELP_STRING([--enable-amalgamation], [enable generation of one single file with all source code in it, helps compiler optimizations.])],
+   [if test "x${enableval}" = "xyes"; then
+       do_amalgamation="yes"
+    else
+       do_amalgamation="no"
+    fi
+   ],
+   [do_amalgamation="no"]
+)
+AM_CONDITIONAL([EDJE_AMALGAMATION], [test "x${do_amalgamation}" = "xyes"])
+
+EFL_ENABLE_BIN([edje-cc])
+EFL_ENABLE_BIN([edje-decc])
+EFL_ENABLE_BIN([edje-recc])
+EFL_ENABLE_BIN([edje-player])
+
+# Optional EDJE_PROGRAM_CACHE (use much more ram, but increase speed in some cases)
+want_edje_program_cache="no"
+
+AC_ARG_ENABLE([edje-program-cache],
+   [AC_HELP_STRING(
+       [--enable-edje-program-cache],
+       [enable EDJE_PROGRAM_CACHE support. [[default=disabled]]]
+    )],
+   [want_edje_program_cache=$enableval]
+)
+AM_CONDITIONAL([EDJE_PROGRAM_CACHE], [test "x${want_edje_program_cache}" = "xyes"])
+
+if test "x${want_edje_program_cache}" = "xyes" ; then
+   AC_DEFINE([EDJE_PROGRAM_CACHE], [1], [Cache result of program glob matches - this uses up extra ram with the gain of faster program matching])
+fi
+
+# Optional EDJE_CALC_CACHE (use more ram, but increase speed by reducing the need to recalculate static stuff)
+want_edje_calc_cache="yes"
+
+AC_ARG_ENABLE([edje-calc-cache],
+   [AC_HELP_STRING(
+       [--enable-edje-calc-cache],
+       [enable EDJE_CALC_CACHE support. [[default=disabled]]]
+    )],
+   [want_edje_calc_cache=$enableval]
+)
+AM_CONDITIONAL([EDJE_CALC_CACHE], [test "x${want_edje_calc_cache}" = "xyes"])
+
+if test "x${want_edje_calc_cache}" = "xyes" ; then
+   AC_DEFINE([EDJE_CALC_CACHE], [1], [Cache result of edje_part_recalc - this uses up extra ram with the gain of reducing CPU usage when edje object are not resized])
+fi
+
+# Enable Fixed Point use
+want_fixed_point="no"
+
+AC_ARG_ENABLE([fixed-point],
+   [AC_HELP_STRING(
+       [--enable-fixed-point],
+       [reduce use of FPU by using Fixed Point provided by Eina and Eet, [[default=disabled]]]
+    )],
+    [want_fixed_point=$enableval]
+)
+AM_CONDITIONAL([BUILD_EDJE_FP], [test "x${want_fixed_point}" = "xyes"])
+
+if test "x${want_fixed_point}" = "xyes" ; then
+   AC_DEFINE([BUILD_EDJE_FP], [1], [Use Fixed Point instead of FPU])
+fi
+
+install_vim="yes"
+AC_ARG_WITH([vim],
+    [AC_HELP_STRING([--with-vim=DIR], [Location of Vim data files [[autodetect]]])],
+    [
+     if test -d "${withval}"; then
+        vimdir="${withval}"
+     fi
+    ]
+)
+
+if test "x${vimdir}" = "x" ; then
+   if test -d "${prefix}/share/vim"; then
+      vimdir="${prefix}/share/vim"
+   elif test -d "/usr/share/vim"; then
+      vimdir="/usr/share/vim"
+   elif test -d "/usr/local/share/vim"; then
+      vimdir="/usr/local/share/vim"
+   elif test -d "/opt/share/vim"; then
+      vimdir="/opt/share/vim"
+   else
+      install_vim="no"
+   fi
+fi
+
+AC_MSG_CHECKING([for location of Vim data files])
+
+if test "${install_vim}" = "yes"; then
+   AC_MSG_RESULT([$vimdir])
+else
+   AC_MSG_RESULT([Not found, EDC syntax file will not be installed])
+fi
+
+AC_SUBST(vimdir)
+
+### Checks for programs
+AC_PROG_CC
+
+# doxygen program for documentation building
+
+EFL_CHECK_DOXYGEN([build_doc="yes"], [build_doc="no"])
+
+# python
+
+AM_PATH_PYTHON([2.5], , [:])
+AM_CONDITIONAL([HAVE_PYTHON], [test "$PYTHON" != : ])
+
+# pkg-config
+
+PKG_PROG_PKG_CONFIG
+
+# Check whether pkg-config supports Requires.private
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.22; then
+   pkgconfig_requires_private="Requires.private"
+else
+   pkgconfig_requires_private="Requires"
+fi
+AC_SUBST(pkgconfig_requires_private)
+
+
+### Checks for libraries
+
+# Evil library for compilation on Windows
+
+EFL_EDJE_BUILD=""
+case "$host_os" in
+   mingw* | cegcc*)
+      PKG_CHECK_MODULES([EVIL], [evil])
+      AC_DEFINE([HAVE_EVIL], [1], [Set to 1 if Evil library is installed])
+      requirement_edje="evil ${requirement_edje}"
+      EFL_EDJE_BUILD="-DEFL_EDJE_BUILD"
+   ;;
+esac
+AC_SUBST(EFL_EDJE_BUILD)
+
+# Dependencies for the library
+
+# Lua pkg-config hack for different naming conventions
+requirement_lua=""
+PKG_CHECK_MODULES([LUA], [lua >= 5.1.0], requirement_lua="lua",
+       [PKG_CHECK_MODULES([LUA], [lua5.1 >= 5.1.0], requirement_lua="lua5.1",
+               [PKG_CHECK_MODULES([LUA], [lua-5.1 >= 5.1.0], requirement_lua="lua-5.1",
+                       [PKG_CHECK_MODULES([LUA], [lua51 >= 5.1.0], requirement_lua="lua51",
+                               AC_MSG_ERROR([unable to find Lua >= 5.1.0])
+                       )
+               ])
+       ])
+])
+
+PKG_CHECK_MODULES([EDJE],
+   [
+    eina-0
+    eet >= 1.2.3
+    evas >= 0.9.9
+    ecore >= 0.9.9
+    ecore-file >= 0.9.9
+    embryo >= 0.9.1
+   ])
+
+EDJE_LIBS="$EDJE_LIBS $LUA_LIBS"
+EDJE_CFLAGS="$EDJE_CFLAGS $LUA_CFLAGS"
+
+requirement_edje="embryo ecore evas eet eina-0 ${requirement_edje}"
+requirement_edje="${requirement_lua} ${requirement_edje}"
+
+have_ecore_imf="no"
+PKG_CHECK_MODULES([ECORE_IMF],
+   [
+    ecore-imf >= 0.9.9
+    ecore-imf-evas >= 0.9.9
+   ],
+   [
+    AC_DEFINE([HAVE_ECORE_IMF], [1], [Input Method Support for Edje Entry])
+    have_ecore_imf="yes"
+    requirement_edje="ecore-imf-evas ecore-imf ${requirement_edje}"
+   ],
+   [have_ecore_imf="no"])
+
+# Dependencies for the binaries
+
+if test "x$have_edje_cc" = "xyes"; then
+   PKG_CHECK_MODULES([ECORE_FILE], [ecore-file >= 0.9.9])
+   PKG_CHECK_MODULES([ECORE_EVAS], [ecore-evas >= 0.9.9])
+fi
+
+if test "x$have_edje_player" = "xyes"; then
+   PKG_CHECK_MODULES([ECORE_EVAS], [ecore-evas >= 0.9.9])
+fi
+
+
+### Checks for header files
+AC_CHECK_HEADERS([locale.h])
+
+
+### Checks for types
+
+
+### Checks for structures
+
+
+### Checks for compiler characteristics
+AM_PROG_CC_C_O
+AC_C_CONST
+AC_PROG_CC_STDC
+AC_HEADER_STDC
+AC_C___ATTRIBUTE__
+
+case "$host_os" in
+   mingw32ce*)
+      EDJE_CFLAGS="${EDJE_CFLAGS} -D_WIN32_WCE=0x0420"
+      ;;
+   cegcc*)
+      EDJE_CFLAGS="${EDJE_CFLAGS} -mwin32 -D_WIN32_WCE=0x0420"
+      ;;
+esac
+
+
+### Checks for linker characteristics
+
+lt_enable_auto_import=""
+case "$host_os" in
+   mingw* | cegcc*)
+      lt_enable_auto_import="-Wl,--enable-auto-import"
+      ;;
+esac
+AC_SUBST(lt_enable_auto_import)
+
+
+### Checks for library functions
+AC_FUNC_ALLOCA
+
+case "$host_os" in
+   mingw* | cegcc*)
+      AC_DEFINE([HAVE_REALPATH], [1], [Define to 1 if you have the `realpath' function.])
+      ;;
+   *)
+      AC_CHECK_FUNCS([realpath])
+      ;;
+esac
+
+
+AC_SUBST(requirement_edje)
+
+AC_OUTPUT([
+edje.pc
+edje.spec
+Makefile
+data/Makefile
+data/include/Makefile
+doc/Makefile
+doc/edje.dox
+src/Makefile
+src/lib/Makefile
+src/bin/Makefile
+utils/Makefile
+])
+
+
+#####################################################################
+## Info
+
+echo
+echo
+echo
+echo "------------------------------------------------------------------------"
+echo "$PACKAGE $VERSION"
+echo "------------------------------------------------------------------------"
+echo
+echo "Configuration Options Summary:"
+echo
+echo "  Amalgamation.........: ${do_amalgamation}"
+echo "  Ecore IMF............: $have_ecore_imf"
+echo "  EDJE_PROGRAM_CACHE...: $want_edje_program_cache"
+echo "  EDJE_CALC_CACHE......: $want_edje_calc_cache"
+echo "  Fixed point..........: $want_fixed_point"
+echo
+echo "  Build edje_cc........: $have_edje_cc"
+echo "  Build edje_decc......: $have_edje_decc"
+echo "  Build edje_recc......: $have_edje_recc"
+echo "  Build edje_player....: $have_edje_player"
+echo
+echo "  Documentation........: ${build_doc}"
+echo
+echo "Compilation............: make (or gmake)"
+echo "  CPPFLAGS.............: $CPPFLAGS"
+echo "  CFLAGS...............: $CFLAGS"
+echo "  LDFLAGS..............: $LDFLAGS"
+echo
+echo "Installation...........: make install (as root if needed, with 'su' or 'sudo')"
+echo "  prefix...............: $prefix"
+echo
diff --git a/data/.cvsignore b/data/.cvsignore
new file mode 100644 (file)
index 0000000..282522d
--- /dev/null
@@ -0,0 +1,2 @@
+Makefile
+Makefile.in
diff --git a/data/Makefile.am b/data/Makefile.am
new file mode 100644 (file)
index 0000000..bd673a0
--- /dev/null
@@ -0,0 +1,10 @@
+
+MAINTAINERCLEANFILES = Makefile.in
+
+SUBDIRS = include
+
+mimedir = $(datadir)/mime/packages
+mime_DATA = edje.xml
+
+EXTRA_DIST = edc.vim edje-mode.el $(mime_DATA)
+
diff --git a/data/edc.vba b/data/edc.vba
new file mode 100644 (file)
index 0000000..e048fe7
--- /dev/null
@@ -0,0 +1,1447 @@
+" Vimball Archiver by Charles E. Campbell, Jr., Ph.D.
+UseVimball
+finish
+ftplugin/edc.vim       [[[1
+24
+" Vim filetype plugin file
+" Language:         EDC
+" Maintainer:       Viktor Kojouharov
+" Latest Revision:  2006-10-29
+
+if exists("b:did_ftplugin")
+  finish
+endif
+let b:did_ftplugin = 1
+
+let b:undo_ftplugin = "setl com< cms< inc< fo< efm< mp<"
+
+setlocal comments=sO:*\ -,mO:*\ \ ,exO:*/,s1:/*,mb:*,ex:*/,://
+setlocal commentstring=/*%s*/
+setlocal formatoptions-=t formatoptions+=croql
+setlocal include=^\s*#\s*include
+setlocal efm=edje_cc:%s.\ %f:%l\ %m
+setlocal mp=edje_cc\ %
+
+if exists('&ofu')
+  setlocal ofu=edccomplete#Complete
+  setlocal cfu=edccomplete#Complete
+endif
+
+syntax/edc.vim [[[1
+235
+" Vim syntax file
+" Language:    EDC
+" Maintainer:  Viktor Kojouharov
+" Last Change: 2007 02 24
+
+" For version 5.x: Clear all syntax items
+" For version 6.x: Quit when a syntax file was already loaded
+if version < 600
+  syntax clear
+elseif exists("b:current_syntax")
+  finish
+endif
+
+" A bunch of useful keywords
+syn keyword    edcBlock        images data fonts collections group contained
+syn keyword    edcBlock        part parts dragable description contained
+syn keyword    edcBlock        text font fill origin size image contained
+syn keyword    edcBlock        programs program styles style contained
+syn keyword    edcBlock        gradient spectra spectrum contained
+syn keyword    edcBlock        color_classes color_class rel1 rel2 contained
+syn keyword    edcBlock        items item file params externals contained
+syn keyword    edcBlock        map rotation perspective script lua_script contained
+
+syn keyword    edcLabel        item name alias min max type effect contained
+syn keyword    edcLabel        mouse_events repeat_events clip_to contained
+syn keyword    edcLabel        x y z confine events scale contained
+syn keyword    edcLabel        ignore_flags precise_is_inside contained
+syn keyword    edcLabel        use_alternate_font_metrics entry_mode contained
+syn keyword    edcLabel        source source2 source3 source4 contained
+syn keyword    edcLabel        source5 source6 multiline pointer_mode contained
+syn keyword    edcLabel        state visible step aspect fixed middle contained
+syn keyword    edcLabel        aspect_preference elipsis image contained
+syn keyword    edcLabel        relative offset to to_x to_y contained
+syn keyword    edcLabel        border border_scale scale_hint color color2 color3 font size contained
+syn keyword    edcLabel        signal action transition in filter contained
+syn keyword    edcLabel        target after fit align contained
+syn keyword    edcLabel        text smooth inherit tag base style contained
+syn keyword    edcLabel        text_source color_class text_class contained
+syn keyword    edcLabel        spectrum angle spread normal tween contained
+syn keyword    edcLabel        padding prefer weight aspect_mode contained
+syn keyword    edcLabel        options layout position span contained
+syn keyword    edcLabel        homogeneous contained
+syn keyword    edcLabel        on perspective light perspective_on contained
+syn keyword    edcLabel        backface_cull alpha center focus zplane contained
+syn keyword    edcLabel        int double string external script_only contained
+
+syn keyword    edcConstant     COMP RAW LOSSY NONE ON_HOLD AUTOGRAB NOGRAB
+syn keyword    edcConstant     TEXT IMAGE RECT TEXTBLOCK SWALLOW GRADIENT GROUP
+syn keyword    edcConstant     NONE PLAIN OUTLINE SOFT_OUTLINE SHADOW
+syn keyword    edcConstant     SOFT_SHADOW OUTLINE_SHADOW OUTLINE_SOFT_SHADOW
+syn keyword    edcConstant     GLOW FAR_SHADOW FAR_SOFT_SHADOW
+syn keyword    edcConstant     STATE_SET ACTION_STOP SIGNAL_EMIT FOCUS_SET
+syn keyword    edcConstant     DRAG_VAL_SET DRAG_VAL_STEP DRAG_VAL_PAGE
+syn keyword    edcConstant     LINEAR SINUSOIDAL ACCELERATE DECELERATE
+syn keyword    edcConstant     VERTICAL HORIZONTAL BOTH BOX TABLE
+syn keyword    edcConstant     EDITABLE PASSWORD "default"
+
+syn keyword    edcTodo         contained TODO FIXME XXX
+
+syn match      edcLabelMatch   "\w\+:" contains=edcLabel
+syn match      edcBlockMatch   "\w\+\_s*{" contains=edcBlock
+syn match      edcBlockMatch   "\w\+\.\a"me=e-2 contains=edcBlock
+" edcCommentGroup allows adding matches for special things in comments
+syn cluster    edcCommentGroup contains=edcTodo
+
+" String and Character constants
+" Highlight special characters (those which have a backslash) differently
+syn match      edcSpecial      display contained "\\\(x\x\+\|\o\{1,3}\|.\|$\)"
+syn region     edcString       start=+L\="+ skip=+\\\\\|\\"+ end=+"+ contains=edcSpecial
+syn match      edcFormat       display "%\(\d\+\$\)\=[-+' #0*]*\(\d*\|\*\|\*\d\+\$\)\(\.\(\d*\|\*\|\*\d\+\$\)\)\=\([hlL]\|ll\)\=\([diuoxXfeEgGcCsSpn]\|\[\^\=.[^]]*\]\)" contained
+syn match      edcFormat       display "%%" contained
+syn region     edcString       start=+L\="+ skip=+\\\\\|\\"+ end=+"+ contains=cSpecial,cFormat
+
+syn match      edcCharacter    "L\='[^\\]'"
+syn match      edcCharacter    "L'[^']*'" contains=edcSpecial
+syn match      edcSpecialError "L\='\\[^'\"?\\abfnrtv]'"
+syn match      edcSpecialCharacter "L\='\\['\"?\\abfnrtv]'"
+syn match      edcSpecialCharacter display "L\='\\\o\{1,3}'"
+syn match      edcSpecialCharacter display "'\\x\x\{1,2}'"
+syn match      edcSpecialCharacter display "L'\\x\x\+'"
+
+"when wanted, highlight trailing white space
+if exists("edc_space_errors")
+  if !exists("edc_no_trail_space_error")
+    syn match  edcSpaceError   display excludenl "\s\+$"
+  endif
+  if !exists("edc_no_tab_space_error")
+    syn match  edcSpaceError   display " \+\t"me=e-1
+  endif
+endif
+
+"catch errors caused by wrong parenthesis and brackets
+syn cluster    edcParenGroup   contains=edcParenError,edcIncluded,edcSpecial,edcCommentSkip,edcCommentString,edcComment2String,@edcCommentGroup,edcCommentStartError,edcUserCont,edcUserLabel,edcBitField,edcCommentSkip,edcOctalZero,edcFormat,edcNumber,edcFloat,edcOctal,edcOctalError,edcNumbersCom
+if exists("edc_no_bracket_error")
+  syn region   edcParen        transparent start='(' end=')' contains=ALLBUT,@edcParenGroup
+  syn match    edcParenError   display ")"
+  syn match    edcErrInParen   display contained "[{}]"
+else
+  syn region   edcParen        transparent start='(' end=')' contains=ALLBUT,@edcParenGroup,edcErrInBracket
+  syn match    edcParenError   display "[\])]"
+  syn match    edcErrInParen   display contained "[\]{}]"
+  syn region   edcBracket      transparent start='\[' end=']' contains=ALLBUT,@edcParenGroup,edcErrInParen
+  syn match    edcErrInBracket display contained "[);{}]"
+endif
+
+"integer number, or floating point number without a dot and with "f".
+syn case ignore
+syn match      edcNumbers      display transparent "\<\d\|\.\d" contains=edcNumber,edcFloat,edcOctalError,edcOctal
+" Same, but without octal error (for comments)
+syn match      edcNumbersCom   display contained transparent "\<\d\|\.\d" contains=edcNumber,edcFloat,edcOctal
+syn match      edcNumber       display contained "\d\+\(u\=l\{0,2}\|ll\=u\)\>"
+"hex number
+syn match      edcNumber       display contained "0x\x\+\(u\=l\{0,2}\|ll\=u\)\>"
+" Flag the first zero of an octal number as something special
+syn match      edcOctal        display contained "0\o\+\(u\=l\{0,2}\|ll\=u\)\>" contains=edcOctalZero
+syn match      edcOctalZero    display contained "\<0"
+syn match      edcFloat        display contained "\d\+f"
+"floating point number, with dot, optional exponent
+syn match      edcFloat        display contained "\d\+\.\d*\(e[-+]\=\d\+\)\=[fl]\="
+"floating point number, starting with a dot, optional exponent
+syn match      edcFloat        display contained "\.\d\+\(e[-+]\=\d\+\)\=[fl]\=\>"
+"floating point number, without dot, with exponent
+syn match      edcFloat        display contained "\d\+e[-+]\=\d\+[fl]\=\>"
+" flag an octal number with wrong digits
+syn match      edcOctalError   display contained "0\o*[89]\d*"
+syn case match
+
+if exists("edc_comment_strings")
+  " A comment can contain edcString, edcCharacter and edcNumber.
+  " But a "*/" inside a edcString in a edcComment DOES end the comment!  So we
+  " need to use a special type of edcString: edcCommentString, which also ends
+  " on "*/", and sees a "*" at the start of the line as comment again.
+  " Unfortunately this doesn't very well work for // type of comments :-(
+  syntax match edcCommentSkip          contained "^\s*\*\($\|\s\+\)"
+  syntax region edcCommentString       contained start=+L\=\\\@<!"+ skip=+\\\\\|\\"+ end=+"+ end=+\*/+me=s-1 contains=edcSpecial,edcCommentSkip
+  syntax region edcComment2String      contained start=+L\=\\\@<!"+ skip=+\\\\\|\\"+ end=+"+ end="$" contains=edcSpecial
+  syntax region edcCommentL            start="//" skip="\\$" end="$" keepend contains=@edcCommentGroup,edcComment2String,edcCharacter,edcNumbersCom,edcSpaceError
+  syntax region edcComment             matchgroup=edcCommentStart start="/\*" matchgroup=NONE end="\*/" contains=@edcCommentGroup,edcCommentStartError,edcCommentString,edcCharacter,edcNumbersCom,edcSpaceError
+else
+  syn region   edcCommentL             start="//" skip="\\$" end="$" keepend contains=@edcCommentGroup,edcSpaceError
+  syn region   edcComment              matchgroup=edcCommentStart start="/\*" matchgroup=NONE end="\*/" contains=@edcCommentGroup,edcCommentStartError,edcSpaceError
+endif
+" keep a // comment separately, it terminates a preproc. conditional
+syntax match   edcCommentError         display "\*/"
+syntax match   edcCommentStartError    display "/\*"me=e-1 contained
+
+syn region     edcPreCondit    start="^\s*#\s*\(if\|ifdef\|ifndef\|elif\)\>" skip="\\$" end="$" end="//"me=s-1 contains=edcComment,edcCharacter,edcParenError,edcNumbers,edcCommentError,edcSpaceError
+syn match      edcPreCondit    display "^\s*#\s*\(else\|endif\)\>"
+syn region     edcIncluded     display contained start=+"+ skip=+\\\\\|\\"+ end=+"+
+syn match      edcIncluded     display contained "<[^>]*>"
+syn match      edcInclude      display "^\s*#\s*include\>\s*["<]" contains=edcIncluded
+syn cluster    edcPreProcGroup contains=edcPreCondit,edcIncluded,edcInclude,edcDefine,edcErrInParen,edcErrInBracket,edcCommentSkip,edcCommentString,edcComment2String,@edcCommentGroup,edcCommentStartError,edcParen,edcBracket,edcMulti,edcUserLabel
+syn cluster    edcAlphaNum     contains=edcSpecial,edcOctalZero,edcFormat,edcNumber,edcFloat,edcOctal,edcOctalError,edcNumbersCom,edcString
+syn region     edcDefine       start="^\s*#\s*\(define\|undef\)\>" skip="\\$" end="$" end="//"me=s-1 contains=ALLBUT,@edcPreProcGroup
+syn region     edcPreProc      start="^\s*#\s*\(pragma\>\|line\>\|warning\>\|warn\>\|error\>\)" skip="\\$" end="$" keepend contains=ALLBUT,@edcPreProcGroup
+
+syn match      edcUserLabel    display "\I\i*" contained
+
+syn include    @edcEmbryo      syntax/embryo.vim
+unlet b:current_syntax
+syn region     edcScript       matchgroup=edcScriptTag start="\<script\_s*{" end="}" contains=@edcEmbryo,edcScriptTag
+syn keyword     edcScriptTag    contained script
+
+syn include    @edcLua         syntax/lua.vim
+unlet b:current_syntax
+syn region     edcLuaScript    matchgroup=edcLuaScriptTag start="\<lua_script\_s*{" end="}" contains=@edcLua,edcLuaScriptTag
+syn keyword     edcLuaScriptTag contained script
+
+if exists("edc_minlines")
+  let b:edc_minlines = edc_minlines
+else
+  let b:edc_minlines = 50      " #if 0 constructs can be long
+endif
+exec "syn sync ccomment edcComment minlines=" . b:edc_minlines
+"syn sync fromstart
+
+" Define the default highlighting.
+" For version 5.7 and earlier: only when not done already
+" For version 5.8 and later: only when an item doesn't have highlighting yet
+if version >= 508 || !exists("did_edc_syn_inits")
+  if version < 508
+    let did_edc_syn_inits = 1
+    command -nargs=+ HiLink hi link <args>
+  else
+    command -nargs=+ HiLink hi def link <args>
+  endif
+
+  HiLink edcFormat             edcSpecial
+  HiLink edcCommentL           edcComment
+  HiLink edcCommentStart       edcComment
+  HiLink edcLabel              Label
+  HiLink edcUserLabel          Label
+  HiLink edcConditional                Conditional
+  HiLink edcRepeat             Repeat
+  HiLink edcCharacter          Character
+  HiLink edcSpecialCharacter   cSpecial
+  HiLink edcNumber             Number
+  HiLink edcOctal              Number
+  HiLink edcOctalZero          PreProc  " link this to Error if you want
+  HiLink edcFloat              Float
+  HiLink edcOctalError         edcError
+  HiLink edcParenError         edcError
+  HiLink edcErrInParen         edcError
+  HiLink edcErrInBracket       edcError
+  HiLink edcCommentError       edcError
+  HiLink edcCommentStartError  edcError
+  HiLink edcSpaceError         edcError
+  HiLink edcSpecialError       edcError
+  HiLink edcOperator           Operator
+  HiLink edcStructure          Structure
+  HiLink edcStorageClass       StorageClass
+  HiLink edcInclude            Include
+  HiLink edcPreProc            PreProc
+  HiLink edcDefine             Macro
+  HiLink edcIncluded           edcString
+  HiLink edcError              Error
+  HiLink edcBlock              Function
+  HiLink edcScriptTag          Function
+  HiLink edcLuaScriptTag       Function
+  HiLink edcPreCondit          PreCondit
+  HiLink edcConstant           Constant
+  HiLink edcCommentString      edcString
+  HiLink edcComment2String     edcString
+  HiLink edcCommentSkip                edcComment
+  HiLink edcString             String
+  HiLink edcComment            Comment
+  HiLink edcSpecial            SpecialChar
+  HiLink edcTodo               Todo
+
+  delcommand HiLink
+endif
+
+let b:current_syntax = "edc"
+
+" vim: ts=8
+indent/edc.vim [[[1
+83
+" Vim indent file
+" Language:         EDC
+" Maintainer:       Viktor Kojouharov
+" Latest Revision:  2007 02 24
+
+if exists("b:did_indent")
+  finish
+endif
+let b:did_indent = 1
+
+setlocal indentexpr=GetEDCIndent()
+setlocal indentkeys=0{,0},!^F,o,O
+
+if exists("*GetEDCIndent")
+  finish
+endif
+
+function s:prevnonblanknoncomment(lnum)
+  let lnum = a:lnum
+  while lnum > 1
+    let lnum = prevnonblank(lnum)
+    let line = getline(lnum)
+    if line =~ '\*/'
+      while lnum > 1 && line !~ '/\*'
+       let lnum -= 1
+      endwhile
+      if line =~ '^\s*/\*'
+       let lnum -= 1
+      else
+       break
+      endif
+    elseif line =~ '^\s*//'
+      let lnum -= 1
+    else
+      break
+    endif
+  endwhile
+  return lnum
+endfunction
+
+function s:count_braces(lnum, count_open)
+  let n_open = 0
+  let n_close = 0
+  let line = getline(a:lnum)
+  let pattern = '[{}]'
+  let i = match(line, pattern)
+  while i != -1
+    if synIDattr(synID(a:lnum, i + 1, 0), 'name') !~ 'c\%(CommentL\|Comment\|StringQ\{1,2}\)'
+      if line[i] == '{'
+       let n_open += 1
+      elseif line[i] == '}'
+       if n_open > 0
+         let n_open -= 1
+       else
+         let n_close += 1
+       endif
+      endif
+    endif
+    let i = match(line, pattern, i + 1)
+  endwhile
+  return a:count_open ? n_open : n_close
+endfunction
+
+function GetEDCIndent()
+  let line = getline(v:lnum)
+  if line =~ '^\s*\*' || line =~ '^\s*//' || line =~ '^\s*}'
+    return cindent(v:lnum)
+  endif
+
+  let pnum = s:prevnonblanknoncomment(v:lnum - 1)
+  if pnum == 0
+    return 0
+  endif
+
+  let ind = indent(pnum) + s:count_braces(pnum, 1) * &sw
+
+  let pline = getline(pnum)
+  if pline =~ '}\s*$'
+    let ind -= (s:count_braces(pnum, 0) - (pline =~ '^\s*}' ? 1 : 0)) * &sw
+  endif
+
+  return ind
+endfunction
+ftdetect/edc.vim       [[[1
+3
+au BufRead,BufNewFile *.edc    set filetype=edc
+au BufRead,BufNewFile *.sma    set filetype=embryo
+au BufRead,BufNewFile *.embryo set filetype=embryo
+autoload/edccomplete.vim       [[[1
+892
+" Vim completion script
+" Language:    EDC
+" Maintainer:  Viktor Kojouharov
+" Last Change: 2007 02 24
+
+function! edccomplete#Complete(findstart, base)
+  if a:findstart
+    " locate the start of the word
+    let line = getline('.')
+    let start = col('.') - 1
+    let compl_begin = col('.') - 2
+    let lastword = -1
+    if line =~ ':' && line !~ '\.'
+      while start > 0 && (line[start - 1] =~ '\k' || line[start - 1] =~ '"')
+       let start -= 1
+      endwhile
+    else
+      while start > 0
+       if line[start - 1] =~ '\k'
+         let start -= 1
+       elseif line[start - 1] =~ '\.'
+         if lastword == -1
+           let lastword = start - 2
+         endif
+         let start -= 1
+       else
+         break
+       endif
+      endwhile
+    endif
+    let b:compl_context = getline('.')[0:compl_begin]
+
+    if lastword == -1
+      let ppe = searchpos('\.', 'bcn')
+      let pps = searchpos('\w\+\.', 'bcn')
+      let b:sparent = ''
+      if ppe != [0, 0] && pps[0] == ppe[0] && pps[1] <= ppe[1] && pps[0] == line('.')
+       let b:scontext = line[pps[1] -1 : ppe[1] - 2]
+        call edccomplete#FindParent(pps[0], pps[1])
+       return start
+      endif
+
+      let startpos = searchpair('{', '', '}', 'bnW')
+      let lnum = startpos
+      let line = getline(lnum)
+
+      if line !~ '\a\+'
+        let lnum = prevnonblank(lnum - 1)
+       let line = getline(lnum)
+      endif
+
+      call edccomplete#FindParent(lnum, 1)
+      let b:scontext = matchstr(line, '\w\+')
+
+      return start
+    else
+      let b:scontext = line[start : lastword]
+
+      return lastword + 2
+    endif
+  else
+    " find months matching with "a:base"
+    let res = []
+    if exists("b:compl_context")
+      let line = b:compl_context
+      unlet! b:compl_context
+    else
+      let line = a:base
+    endif
+
+    if b:scontext == 'part'
+      call edccomplete#AddLabel(res, line, a:base, s:partLabel)
+      call edccomplete#AddStatement(res, line, a:base, s:partStatement)
+      if line =~ 'type:\s*'
+        call edccomplete#AddKeyword(res, a:base, s:partTypes)
+      elseif line =~ 'effect:\s*'
+        call edccomplete#AddKeyword(res, a:base, s:partEffects)
+      elseif line =~ 'select_mode:\s*'
+       call edccomplete#AddKeyword(res, a:base, s:partSelectMode)
+      elseif line =~ 'ignore_flags:\s*'
+       call edccomplete#AddKeyword(res, a:base, s:partIgnoreFlags)
+      elseif line =~ 'pointer_mode:\s*'
+       call edccomplete#AddKeyword(res, a:base, s:partPointerMode)
+      elseif line =~ 'editable_mode:\s*'
+       call edccomplete#AddKeyword(res, a:base, s:partEditableMode)
+      endif
+      if line =~ 'image:\s*".\{-}"'
+       call edccomplete#AddKeyword(res, a:base, s:imageStorageMethod)
+      endif
+
+    elseif b:scontext == 'dragable'
+      call edccomplete#AddLabel(res, line, a:base, s:dragableLabel)
+
+    elseif b:scontext == 'description'
+      call edccomplete#AddLabel(res, line, a:base, s:descriptionLabel)
+      call edccomplete#AddStatement(res, line, a:base, s:descriptionStatement)
+      if line =~ 'aspect_preference:\s*'
+       call edccomplete#AddKeyword(res, a:base, s:aspectPrefTypes)
+      elseif line =~ 'inherit:\s*"\?'
+       call edccomplete#FindStates(res, a:base, 1)
+      endif
+
+    elseif b:scontext == 'rel1' || b:scontext == 'rel2'
+      call edccomplete#AddLabel(res, line, a:base, s:relLabel)
+      if line =~ 'to\%(_[xy]\)\?:\s*"\?'
+        call edccomplete#FindNamesIn(res, a:base, 'parts')
+      endif
+
+    elseif b:scontext == 'map'
+      call edccomplete#AddLabel(res, line, a:base, s:mapLabel)
+      call edccomplete#AddStatement(res, line, a:base, s:mapStatement)
+
+    elseif b:scontext == 'rotation'
+      call edccomplete#AddLabel(res, line, a:base, s:rotationLabel)
+
+    elseif b:scontext == 'perspective'
+      call edccomplete#AddLabel(res, line, a:base, s:perspectiveLabel)
+
+    elseif b:scontext == 'params'
+      call edccomplete#AddLabel(res, line, a:base, s:paramsLabel)
+
+    elseif b:scontext == 'image'
+      call edccomplete#AddLabel(res, line, a:base, s:imageLabel)
+      if line =~ 'image:\s*".\{-}"'
+        call edccomplete#AddKeyword(res, a:base, s:imageStorageMethod)
+      elseif line =~ 'middle:\s*'
+        call edccomplete#AddKeyword(res, a:base, s:imageMiddleTypes)
+      elseif line =~ 'scale_hint:\s*'
+        call edccomplete#AddKeyword(res, a:base, s:imageScaleHint)
+      endif
+
+    elseif b:scontext == 'fill'
+      call edccomplete#AddLabel(res, line, a:base, s:fillLabel)
+      call edccomplete#AddStatement(res, line, a:base, s:fillStatement)
+      if line =~ 'type:\s*'
+       call edccomplete#AddKeyword(res, a:base, s:fillTypes)
+      endif
+
+    elseif b:scontext == 'origin' || b:scontext == 'size'
+      call edccomplete#AddLabel(res, line, a:base, s:fillInnerStatement)
+
+    elseif b:scontext == 'text'
+      call edccomplete#AddLabel(res, line, a:base, s:textLabel)
+      call edccomplete#AddStatement(res, line, a:base, s:textStatement)
+
+    elseif b:scontext == 'program'
+      call edccomplete#AddLabel(res, line, a:base, s:programLabel)
+      call edccomplete#AddStatement(res, line, a:base, s:programStatement)
+      if line =~ 'transition:\s*'
+       call edccomplete#AddKeyword(res, a:base, s:transitionTypes)
+      elseif line =~ 'STATE_SET\s*"\?'
+       call edccomplete#FindStates(res, a:base, 0)
+      elseif line =~ 'action:\s*'
+       call edccomplete#AddKeyword(res, a:base, s:actionTypes)
+      elseif line =~ 'target:\s*"\?'
+       call edccomplete#FindNamesIn(res, a:base, 'parts')
+      elseif line =~ 'after:\s*"\?'
+       call edccomplete#FindNamesIn(res, a:base, 'programs')
+      endif
+
+    elseif b:scontext == 'programs'
+      call edccomplete#AddLabel(res, line, a:base, s:programsLabel)
+      call edccomplete#AddStatement(res, line, a:base, s:programsStatement)
+      if line =~ 'image:\s*".\{-}"'
+       call edccomplete#AddKeyword(res, a:base, s:imageStorageMethod)
+      endif
+
+    elseif b:scontext == 'box' && b:sparent == 'part'
+      call edccomplete#AddStatement(res, line, a:base, s:boxStatement)
+
+    elseif b:scontext == 'items'
+      call edccomplete#AddStatement(res, line, a:base, s:boxItemsStatement)
+
+    elseif b:scontext == 'item'
+      call edccomplete#AddLabel(res, line, a:base, s:boxItemLabel)
+      if line =~ 'type:\s*'
+       call edccomplete#AddKeyword(res, a:base, s:boxItemTypes)
+      elseif line =~ 'aspect_mode:\s*"\?'
+       call edccomplete#AddKeyword(res, a:base, s:boxItemAspectMode)
+      endif
+
+    elseif b:scontext == 'box' && b:sparent == 'description'
+      call edccomplete#AddLabel(res, line, a:base, s:boxDescLabel)
+      if line =~ 'layout:\s*'
+       call edccomplete#AddKeyword(res, a:base, s:boxLayout)
+      endif
+
+    elseif b:scontext == 'table' && b:sparent == 'description'
+      call edccomplete#AddLabel(res, line, a:base, s:tableDescLabel)
+      if line =~ 'homogeneous:\s*'
+       call edccomplete#AddKeyword(res, a:base, s:tableHomogeneousMode)
+      endif
+
+    elseif b:scontext == 'group'
+      call edccomplete#AddLabel(res, line, a:base, s:groupLabel)
+      call edccomplete#AddStatement(res, line, a:base, s:groupStatement)
+      if line =~ 'image:\s*".\{-}"'
+       call edccomplete#AddKeyword(res, a:base, s:imageStorageMethod)
+      endif
+
+    elseif b:scontext == 'parts'
+      call edccomplete#AddLabel(res, line, a:base, s:partsLabel)
+      call edccomplete#AddStatement(res, line, a:base, s:partsStatement)
+      if line =~ 'image:\s*".\{-}"'
+       call edccomplete#AddKeyword(res, a:base, s:imageStorageMethod)
+      endif
+
+    elseif b:scontext == 'data'
+      call edccomplete#AddLabel(res, line, a:base, s:dataLabel)
+
+    elseif b:scontext == 'fonts'
+      call edccomplete#AddLabel(res, line, a:base, s:fontsLabel)
+
+    elseif b:scontext == 'spectra'
+      call edccomplete#AddStatement(res, line, a:base, s:spectraStatement)
+
+    elseif b:scontext == 'spectrum'
+      call edccomplete#AddLabel(res, line, a:base, s:spectrumLabel)
+
+    elseif b:scontext == 'gradient'
+      call edccomplete#AddLabel(res, line, a:base, s:gradientLabel)
+      call edccomplete#AddStatement(res, line, a:base, s:gradientStatement)
+      if line =~ 'type:\s*'
+       call edccomplete#AddKeyword(res, a:base, s:gradientTypes)
+      endif
+
+    elseif b:scontext == 'styles'
+      call edccomplete#AddStatement(res, line, a:base, s:stylesStatement)
+
+    elseif b:scontext == 'style'
+      call edccomplete#AddLabel(res, line, a:base, s:styleLabel)
+
+    elseif b:scontext == 'color_classes'
+      call edccomplete#AddStatement(res, line, a:base, s:color_classesStatement)
+
+    elseif b:scontext == 'color_class'
+      call edccomplete#AddLabel(res, line, a:base, s:color_classLabel)
+
+    elseif b:scontext == 'images'
+      call edccomplete#AddLabel(res, line, a:base, s:imagesLabel)
+      if line =~ 'image:\s*".\{-}"'
+       call edccomplete#AddKeyword(res, a:base, s:imageStorageMethod)
+      endif
+
+    elseif b:scontext == 'collections'
+      call edccomplete#AddLabel(res, line, a:base, s:collectionsLabel)
+      call edccomplete#AddStatement(res, line, a:base, s:collectionsStatement)
+      if line =~ 'image:\s*".\{-}"'
+       call edccomplete#AddKeyword(res, a:base, s:imageStorageMethod)
+      endif
+
+    elseif b:scontext == 'externals'
+      call edccomplete#AddLabel(res, line, a:base, s:externalsLabel)
+
+    elseif strlen(b:scontext) == 0
+      call edccomplete#AddStatement(res, line, a:base, s:topStatement)
+    endif
+
+    unlet! b:scontext
+
+    return res
+  endif
+endfunction
+
+function! edccomplete#AddLabel(res, line, base, label)
+  if a:line =~ ':'
+    return
+  endif
+
+  for m in sort(keys(a:label))
+    if m =~ '^' . a:base
+      call add(a:res, {'word': m . ':', 'menu': a:label[m]})
+    endif
+  endfor
+endfunction
+
+function! edccomplete#AddKeyword(res, base, label)
+  for m in sort(keys(a:label))
+    if m =~ '^' . a:base
+      call add(a:res, {'word': m, 'menu': a:label[m]})
+    endif
+  endfor
+endfunction
+
+function! edccomplete#AddStatement(res, line, base, statement)
+  if a:line =~ ':'
+    return
+  endif
+
+  for m in sort(a:statement)
+    if m =~ '^' . a:base
+      call add(a:res, m . ' {')
+    endif
+  endfor
+endfunction
+
+function! edccomplete#FindStates(res, base, in_part)
+  let curpos = getpos('.')
+  call remove(curpos, 0, 0)
+
+  let states_list = []
+  if a:in_part == 1    " in the current part only
+    let part_start = search('^[ \t}]*\<part\>[ \t{]*$', 'bnW')
+    if part_start != 0  " found it
+      let line = getline(part_start)
+      if line !~ '{'
+       let part_start = nextnonblank(part_start)
+      endif
+      call cursor(part_start, 0)
+      let part_end = searchpair('{', '', '}', 'nW')
+    endif
+  else                         " in the current parts group
+    let part_start = search('^[ \t}]*\<parts\>[ \t{]*$', 'bnW')
+    if part_start != 0  " found it
+      let line = getline(part_start)
+      if line !~ '{'
+       let part_start = nextnonblank(part_start)
+      endif
+      call cursor(part_start, 0)
+      let part_end = searchpair('{', '', '}', 'nW')
+    endif
+  endif
+
+  let state_num = search('\%(state:\s*\)"\w\+"', 'W', part_end)
+  while state_num
+    let state = matchstr(getline(state_num), '\%(state:\s*\)\@<="\w\+"')
+    call extend(states_list, [state])
+    let state_num = search('\%(state:\s*\)"\w\+"', 'W', part_end)
+  endwhile
+  call cursor(curpos)
+
+  for m in sort(states_list)
+    if m =~ '^' . a:base
+      call add(a:res, m)
+    endif
+  endfor
+endfunction
+
+function! edccomplete#FindNamesIn(res, base, str)
+  let curpos = getpos('.')
+  call remove(curpos, 0, 0)
+
+  let names_list = []
+  let part_start = search('^[ \t}]*\<' . a:str . '\>[ \t{]*$', 'bnW')
+  if part_start != 0  " found it
+    let line = getline(part_start)
+    if line !~ '{'
+      let part_start = nextnonblank(part_start)
+    endif
+    call cursor(part_start, 0)
+    let part_end = searchpair('{', '', '}', 'nW')
+  endif
+
+  let name_num = search('\%(name:\s*\)"\w\+"', 'W', part_end)
+  while name_num
+    let name = matchstr(getline(name_num), '\%(name:\s*\)\@<="\w\+"')
+    call extend(names_list, [name])
+    let name_num = search('\%(name:\s*\)"\w\+"', 'W', part_end)
+  endwhile
+  call cursor(curpos)
+
+  for m in sort(names_list)
+    if m =~ '^' . a:base
+      call add(a:res, m)
+    endif
+  endfor
+endfunction
+
+function! edccomplete#FindParent(lnum, cnum)
+  call setpos('.', [0, a:lnum, a:cnum, 0])
+  let ppe = searchpos('\.', 'bcn')
+  let pps = searchpos('\w\+\.', 'bcn')
+  if ppe != [0, 0] && pps[0] == ppe[0] && pps[1] <= ppe[1] && pps[0] == line('.')
+    let b:sparent = line[pps[1] -1 : ppe[1] - 2]
+    return
+  endif
+
+  let startpos = searchpair('{', '', '}', 'bnW')
+  let lnum = startpos
+  let line = getline(lnum)
+
+  if line !~ '\a\+'
+    let line = getline(prevnonblank(lnum - 1))
+  endif
+
+  let b:sparent = matchstr(line, '\w\+')
+endfunction
+
+" part
+let s:partLabel = {
+      \ 'name':                        '"name"',
+      \ 'type':                                'keyword',
+      \ 'effect':                      'keyword',
+      \ 'clip_to':                     '"part_name"',
+      \ 'scale':                       '0-1',
+      \ 'mouse_events':                        '0-1',
+      \ 'repeat_events':               '0-1',
+      \ 'ignore_flags':                        'keyword ...',
+      \ 'pointer_mode':                        'keyword',
+      \ 'select_mode':                 'keyword',
+      \ 'precise_is_inside':           '0-1',
+      \ 'use_alternate_font_metrics':  '0-1',
+      \ 'image':                       '"filename" keyword',
+      \ 'font':                                '"filename" "name"',
+      \ 'entry_mode':                  'keyword',
+      \ 'multiline':                   '0-1 (TEXTBLOCK only)',
+      \ 'source':                      '"group_name" (GROUP or TEXTBLOCK only)',
+      \ 'source2':                     '"group_name" (TEXTBLOCK only)',
+      \ 'source3':                     '"group_name" (TEXTBLOCK only)',
+      \ 'source4':                     '"group_name" (TEXTBLOCK only)',
+      \ 'source5':                     '"group_name" (TEXTBLOCK only)',
+      \ 'source6':                     '"group_name" (TEXTBLOCK only)',
+      \ }
+let s:partStatement = [
+      \ 'dragable',
+      \ 'images',
+      \ 'fonts',
+      \ 'description',
+      \ 'styles',
+      \ 'color_classes',
+      \ 'program',
+      \ 'programs',
+      \ 'box',
+      \ ]
+
+" dragable
+let s:dragableLabel = {
+      \ 'x':           '0-1 int int',
+      \ 'y':           '0-1 int int',
+      \ 'confine':     '"part_name"',
+      \ 'events':      '"draggable_part_name"',
+      \ }
+
+" description
+let s:descriptionLabel = {
+      \ 'state':               '"name" index (float)',
+      \ 'inherit':             '"description" index (float)',
+      \ 'visible':             '0-1',
+      \ 'align':               'x y (float)',
+      \ 'fixed':               'width height (0-1)',
+      \ 'min':                 'width height (int)',
+      \ 'max':                 'width height (int)',
+      \ 'step':                        'width height (int)',
+      \ 'aspect':              'min max (float)',
+      \ 'aspect_preference':   'keyword',
+      \ 'color_class':         '"name"',
+      \ 'color':               '0-255 0-255 0-255 0-255',
+      \ 'color2':              '0-255 0-255 0-255 0-255',
+      \ 'color3':              '0-255 0-255 0-255 0-255',
+      \ 'font':                '"filename" "name"',
+      \ }
+let s:descriptionStatement = [
+      \ 'rel1',
+      \ 'rel2',
+      \ 'image',
+      \ 'fill',
+      \ 'text',
+      \ 'gradient',
+      \ 'images',
+      \ 'fonts',
+      \ 'styles',
+      \ 'color_classes',
+      \ 'program',
+      \ 'programs',
+      \ 'box',
+      \ 'map',
+      \ ]
+
+" rel
+let s:relLabel = {
+      \ 'relative':    'x y (float)',
+      \ 'offset':      'x y (int)',
+      \ 'to':          '"part_name"',
+      \ 'to_x':                '"part_name"',
+      \ 'to_y':                '"part_name"',
+      \ }
+" map
+let s:mapLabel = {
+      \ 'on':          '0-1',
+      \ 'perspective': '"part_name"',
+      \ 'light':       '"part_name"',
+      \ 'smooth':      '0-1',
+      \ 'pespective_on':'0-1',
+      \ 'backface_cull':'0-1',
+      \ 'alpha':       '0-1',
+      \ }
+let s:mapStatement = [
+      \ 'rotation',
+      \ ]
+
+let s:rotationLabel = {
+      \ 'center':      '"part_name"',
+      \ 'x':           '"degrees (float)"',
+      \ 'y':           '"degrees (float)"',
+      \ 'z':           '"degrees (float)"',
+      \ }
+
+" params
+let s:paramsLabel = {
+      \ 'int':         '"name" int',
+      \ 'double':       '"name" double',
+      \ 'string':       '"name" "string"',
+      \ }
+
+" perspective
+let s:perspectiveLabel = {
+      \ 'zplane':      'int',
+      \ 'focal':        'int',
+      \ }
+
+
+" image
+let s:imageLabel = {
+      \ 'image':       '"filename" keyword',
+      \ 'normal':      '"filename"',
+      \ 'tween':       '"filename"',
+      \ 'border':      'left right top bottom (int)',
+      \ 'middle':      'keyword',
+      \ 'border_scale': '0-1',
+      \ 'scale_hint':  'keyword',
+      \ }
+
+" fill
+let s:fillLabel = {
+      \ 'smooth':      '0-1',
+      \ 'angle':       '0-360 (GRADIENT)',
+      \ 'spread':      '0-1',
+      \ 'type':                'keyword',
+      \ }
+let s:fillStatement = [
+      \ 'origin',
+      \ 'size',
+      \ ]
+" fill origin/size
+let s:fillInnerStatement = {
+      \ 'relative':    'width height (float)',
+      \ 'offset':      'x y (int)',
+      \ }
+" fill types
+let s:fillTypes = {
+      \ 'SCALE':    '',
+      \ 'TILE':            '',
+      \ }
+
+" text
+let s:textLabel = {
+      \ 'text':                '"string"',
+      \ 'font':                '"font_name"',
+      \ 'size':                'size (int)',
+      \ 'text_class':  '"class_name"',
+      \ 'fit':         'x y (0-1)',
+      \ 'min':         'x y (0-1)',
+      \ 'max':         'x y (0-1)',
+      \ 'align':       'x y (float)',
+      \ 'source':      '"part_name"',
+      \ 'text_source': '"text_part_name"',
+      \ 'style':       '"style_name"',
+      \ 'elipsis':     '0.0-1.0',
+      \ 'repch':       '"string" (PASSWORD mode)',
+      \ }
+let s:textStatement = [
+      \ 'fonts',
+      \ ]
+
+" program
+let s:programLabel = {
+      \ 'name':                '"name"',
+      \ 'signal':      '"signal_name"',
+      \ 'source':      '"part_name"',
+      \ 'action':      'keyword ...',
+      \ 'transition':  'keyword time (float)',
+      \ 'filter':      '"part_name" "state_name"',
+      \ 'in':          'from range (float)',
+      \ 'target':      '"part_name"',
+      \ 'after':       '"program_name"',
+      \ }
+let s:programStatement = [
+      \ 'script',
+      \ 'lua_script',
+      \ ]
+
+
+" programs
+let s:programsLabel = {
+      \ 'image':       '"filename" keyword',
+      \ 'font':                '"filename" "name"',
+      \ }
+let s:programsStatement = [
+      \ 'images',
+      \ 'fonts',
+      \ 'program',
+      \ ]
+
+" box and table
+let s:boxStatement = [
+      \ 'items',
+      \ ]
+let s:boxItemsStatement = [
+      \ 'item',
+      \ ]
+let s:boxItemLabel = {
+      \ 'type':                'keyword',
+      \ 'name':                '"name"',
+      \ 'source':      '"group_name"',
+      \ 'min':         'width height (int)',
+      \ 'prefer':      'width height (int)',
+      \ 'max':         'width height (int)',
+      \ 'padding':      'left right top bottom (int)',
+      \ 'align':       'x y (float)',
+      \ 'weight':      'x y (float)',
+      \ 'aspect':      'w h (float)',
+      \ 'aspect_mode':  'keyword',
+      \ 'options':      '"extra options"',
+      \ }
+let s:boxDescLabel = {
+      \ 'layout':       '"string" ["string"]',
+      \ 'align':       'float float',
+      \ 'padding':      'int int',
+      \ }
+let s:tableItemLabel = {
+      \ 'position':     'col row (int)',
+      \ 'span':                'col row (int)',
+      \ }
+let s:tableDescLabel = {
+      \ 'homogeneous': 'keyword',
+      \ 'align':       'float float',
+      \ 'padding':      'int int',
+      \ }
+
+" group
+let s:groupLabel = {
+      \ 'name':                '"name"',
+      \ 'alias':       '"alias"',
+      \ 'min':         'width height',
+      \ 'max':         'width height',
+      \ 'image':       '"filename" keyword',
+      \ 'font':                '"filename" "name"',
+      \ 'script_only': '0-1',
+      \ }
+let s:groupStatement = [
+      \ 'data',
+      \ 'script',
+      \ 'lua_script',
+      \ 'parts',
+      \ 'images',
+      \ 'fonts',
+      \ 'styles',
+      \ 'color_classes',
+      \ 'program',
+      \ 'programs',
+      \ 'externals',
+      \ ]
+
+" parts
+let s:partsStatement = [
+      \ 'images',
+      \ 'fonts',
+      \ 'part',
+      \ 'styles',
+      \ 'color_classes',
+      \ 'program',
+      \ 'programs',
+      \ ]
+let s:partsLabel = {
+      \ 'image':       '"filename" keyword',
+      \ 'font':                '"filename" "name"',
+      \ }
+
+" data
+let s:dataLabel = {
+      \ 'item':                '"key" "value"',
+      \ 'file':                '"key" "filename"',
+      \ }
+
+" fonts
+let s:fontsLabel = {
+      \ 'font':                '"filename" "name"',
+      \ }
+
+"images
+let s:imagesLabel = {
+      \ 'image':       '"filename" keyword',
+      \ }
+
+"collections
+let s:collectionsStatement = [
+      \ 'group',
+      \ 'images',
+      \ 'fonts',
+      \ 'styles',
+      \ 'color_classes',
+      \ 'externals',
+      \ ]
+let s:collectionsLabel = {
+      \ 'image':       '"filename" keyword',
+      \ 'font':                '"filename" "name"',
+      \ }
+
+" externals
+let s:externalsLabel = {
+      \ 'external':            '"name"',
+      \ }
+
+" spectra
+let s:spectraStatement = [
+      \ 'spectrum',
+      \ ]
+" spectrum
+let s:spectrumLabel = {
+      \ 'name':                '"name"',
+      \ 'color':       '0-255 0-255 0-255 0-255',
+      \ }
+" gradient
+let s:gradientLabel = {
+      \ 'type':                '"keyword"',
+      \ 'spectrum':    '"spectrum_name"',
+      \ }
+let s:gradientStatement = [
+      \ 'rel1',
+      \ 'rel2',
+      \ ]
+" gradient types
+let s:gradientTypes = {
+      \ '"linear"':            '',
+      \ '"radial"':            '',
+      \ '"rectangular"':       '',
+      \ '"angular"':           '',
+      \ '"sinusoidal"':                '',
+      \ }
+
+" styles
+let s:stylesStatement = [
+      \ 'style',
+      \ ]
+" style
+let s:styleLabel = {
+      \ 'name':                '"name"',
+      \ 'base':        '".. default style properties .."',
+      \ 'tag':                 '"tagname" "style properties"',
+      \ }
+
+" color_classes
+let s:color_classesStatement = [
+      \ 'color_class',
+      \ ]
+" color_class
+let s:color_classLabel = {
+      \ 'name':                '"name"',
+      \ 'color':       '0-255 0-255 0-255 0-255',
+      \ 'color2':      '0-255 0-255 0-255 0-255',
+      \ 'color3':      '0-255 0-255 0-255 0-255',
+      \ }
+
+" toplevel
+let s:topStatement = [
+      \ 'fonts',
+      \ 'images',
+      \ 'data',
+      \ 'collections',
+      \ 'spectra',
+      \ 'styles',
+      \ 'color_classes',
+      \ 'externals',
+      \ ]
+
+" images image storage method
+let s:imageStorageMethod = {
+      \ 'COMP':                '',
+      \ 'RAW':         '',
+      \ 'USER':                '',
+      \ 'LOSSY':       '0-100',
+      \ }
+" image middle types
+let s:imageMiddleTypes = {
+      \ '0':           '',
+      \ '1':           '',
+      \ 'NONE':                '',
+      \ 'DEFAULT':     '',
+      \ 'SOLID':       '',
+      \ }
+" image scale hint
+let s:imageScaleHint = {
+      \ '0':           '',
+      \ 'NONE':                '',
+      \ 'DYNAMIC':     '',
+      \ 'STATIC':      '',
+      \ }
+
+" part types
+let s:partTypes = {
+      \ 'TEXT':                '',
+      \ 'IMAGE':       '',
+      \ 'RECT':                '',
+      \ 'TEXTBLOCK':   '',
+      \ 'SWALLOW':     '',
+      \ 'GRADIENT':    '',
+      \ 'GROUP':       '',
+      \ 'BOX':         '',
+      \ 'TABLE':        '',
+      \ 'EXTERNAL':     '',
+      \ }
+" part effects
+let s:partEffects = {
+      \ 'NONE':                        '',
+      \ 'PLAIN':               '',
+      \ 'OUTLINE':             '',
+      \ 'SOFT_OUTLINE':                '',
+      \ 'SHADOW':              '',
+      \ 'SOFT_SHADOW':         '',
+      \ 'OUTLINE_SHADOW':      '',
+      \ 'OUTLINE_SOFT_SHADOW': '',
+      \ 'FAR_SHADOW':  '',
+      \ 'FAR_SOFT_SHADOW':     '',
+      \ 'GLOW':        '',
+      \ }
+" part select_mode
+let s:partSelectMode = {
+      \ 'DEFAULT':             '',
+      \ 'EXPLICIT':            '',
+      \ }
+" part ignore flags 
+let s:partIgnoreFlags = {
+      \ 'NONE':                '',
+      \ 'ON_HOLD':     '',
+      \ }
+" part pointer mode
+let s:partPointerMode = {
+      \ 'AUTOGRAB':     '',
+      \ 'NOGRAB':      '',
+      \ }
+" part editable_mode
+let s:partEditableMode = {
+      \ 'NONE':                '',
+      \ 'PLAIN':       '',
+      \ 'EDITABLE':    '',
+      \ 'PASSWORD':    '',
+      \ }
+
+" aspect_preference types
+let s:aspectPrefTypes = {
+      \ 'VERTICAL':    '',
+      \ 'HORIZONTAL':  '',
+      \ 'BOTH':                '',
+      \        }
+
+" program transition types
+let s:transitionTypes = {
+      \ 'LINEAR':      '0.0 - 1.0',
+      \ 'SINUSOIDAL':  '0.0 - 1.0',
+      \ 'ACCELERATE':  '0.0 - 1.0',
+      \ 'DECELERATE':  '0.0 - 1.0',
+      \ }
+" program action types
+let s:actionTypes = {
+      \ 'STATE_SET':           '"string" "0.0 - 1.0"',
+      \ 'ACTION_STOP':         '',
+      \ 'SIGNAL_EMIT':         '"string" "string"',
+      \ 'DRAG_VAL_SET':                'float float',
+      \ 'DRAG_VAL_STEP':       'float float',
+      \ 'DRAG_VAL_PAGE':       'float float',
+      \ 'FOCUS_SET':           '',
+      \ }
+" box item types
+let s:boxItemTypes = {
+      \ 'GROUP':       '',
+      \ }
+" box item aspect mode
+let s:boxItemAspectMode = {
+      \ 'NONE':                '',
+      \ 'NEITHER':     '',
+      \ 'VERTICAL':    '',
+      \ 'HORIZONTAL':  '',
+      \ 'BOTH':                '',
+      \        }
+" box layout
+let s:boxLayout = {
+      \ '"horizontal"':                '',
+      \ '"horizontal_homogeneous"':    '',
+      \ '"horizontal_max"':    '',
+      \ '"horizontal_flow"':   '',
+      \ '"vertical"':          '',
+      \ '"vertical_homogeneous"':      '',
+      \ '"vertical_max"':      '',
+      \ '"vertical_flow"':     '',
+      \ '"stack"':             '',
+      \        }
+" table homogeneous mode
+let s:tableHomogeneousMode = {
+      \ 'NONE':                '',
+      \ 'TABLE':       '',
+      \ 'ITEM':                '',
+      \        }
+syntax/embryo.vim      [[[1
+195
+" Vim syntax file
+" Language:    Embryo
+" Maintainer:  Viktor Kojouharov
+" Last Change: 2006 10 06
+
+" For version 5.x: Clear all syntax items
+" For version 6.x: Quit when a syntax file was already loaded
+if version < 600
+  syntax clear
+elseif exists("b:current_syntax")
+  finish
+endif
+
+" A bunch of useful keywords
+syn keyword embryoConditional  if else switch
+syn keyword embryoRepeat       while for do in
+syn keyword embryoBranch       break continue
+syn keyword embryoOperator     new
+syn keyword embryoType         Float State_Param Msg_Type enum
+syn keyword embryoStatement    return with native stock forward
+syn keyword embryoLabel                case default
+syn keyword embryoReserved     public
+syn keyword embryoEdjeKey      PART PROGRAM
+
+syn keyword    embryoTodo              contained TODO FIXME XXX
+
+" embryoCommentGroup allows adding matches for special things in comments
+syn cluster    embryoCommentGroup      contains=embryoTodo
+
+" String and Character constants
+" Highlight special characters (those which have a backslash) differently
+syn match      embryoSpecial   display contained "\\\(x\x\+\|\o\{1,3}\|.\|$\)"
+syn region     embryoString    start=+L\="+ skip=+\\\\\|\\"+ end=+"+ contains=embryoSpecial
+syn match      embryoFormat    display "%\(\d\+\$\)\=[-+' #0*]*\(\d*\|\*\|\*\d\+\$\)\(\.\(\d*\|\*\|\*\d\+\$\)\)\=\([hlL]\|ll\)\=\([diuoxXfeEgGcCsSpn]\|\[\^\=.[^]]*\]\)" contained
+syn match      embryoFormat    display "%%" contained
+syn region     embryoString    start=+L\="+ skip=+\\\\\|\\"+ end=+"+ contains=cSpecial,cFormat
+
+syn match      embryoCharacter "L\='[^\\]'"
+syn match      embryoCharacter "L'[^']*'" contains=embryoSpecial
+syn match      embryoSpecialError      "L\='\\[^'\"?\\abfnrtv]'"
+syn match      embryoSpecialCharacter "L\='\\['\"?\\abfnrtv]'"
+syn match      embryoSpecialCharacter display "L\='\\\o\{1,3}'"
+syn match      embryoSpecialCharacter display "'\\x\x\{1,2}'"
+syn match      embryoSpecialCharacter display "L'\\x\x\+'"
+
+"when wanted, highlight trailing white space
+if exists("embryo_space_errors")
+  if !exists("embryo_no_trail_space_error")
+    syn match  embryoSpaceError        display excludenl "\s\+$"
+  endif
+  if !exists("embryo_no_tab_space_error")
+    syn match  embryoSpaceError        display " \+\t"me=e-1
+  endif
+endif
+
+"catch errors caused by wrong parenthesis and brackets
+syn cluster    embryoParenGroup        contains=embryoParenError,embryoIncluded,embryoSpecial,embryoCommentSkip,embryoCommentString,embryoComment2String,@embryoCommentGroup,embryoCommentStartErr,embryoUserCont,embryoUserLabel,embryoBitField,embryoCommentSkip,embryoOctalZero,embryoFormat,embryoNumber,embryoFloat,embryoOctal,embryoOctalError,embryoNumbersCom
+if exists("embryo_no_bracket_error")
+  syn region   embryoParen     transparent start='(' end=')' contains=ALLBUT,@embryoParenGroup
+  syn match    embryoParenError        display ")"
+  syn match    embryoErrInParen        display contained "[{}]"
+else
+  syn region   embryoParen     transparent start='(' end=')' contains=ALLBUT,@embryoParenGroup,embryoErrInBracket
+  syn match    embryoParenError        display "[\])]"
+  syn match    embryoErrInParen        display contained "[\]{}]"
+  syn region   embryoBracket   transparent start='\[' end=']' contains=ALLBUT,@embryoParenGroup,embryoErrInParen
+  syn match    embryoErrInBracket      display contained "[);{}]"
+endif
+
+syn region embryoBrace start='{' end='}' transparent keepend
+"integer number, or floating point number without a dot and with "f".
+syn case ignore
+syn match      embryoNumbers   display transparent "\<\d\|\.\d" contains=embryoNumber,embryoFloat,embryoOctalError,embryoOctal
+" Same, but without octal error (for comments)
+syn match      embryoNumbersCom        display contained transparent "\<\d\|\.\d" contains=embryoNumber,embryoFloat,embryoOctal
+syn match      embryoNumber    display contained "\d\+\(u\=l\{0,2}\|ll\=u\)\>"
+"hex number
+syn match      embryoNumber    display contained "0x\x\+\(u\=l\{0,2}\|ll\=u\)\>"
+" Flag the first zero of an octal number as something special
+syn match      embryoOctal     display contained "0\o\+\(u\=l\{0,2}\|ll\=u\)\>" contains=embryoOctalZero
+syn match      embryoOctalZero display contained "\<0"
+syn match      embryoFloat     display contained "\d\+f"
+"floating point number, with dot, optional exponent
+syn match      embryoFloat     display contained "\d\+\.\d*\(e[-+]\=\d\+\)\=[fl]\="
+"floating point number, starting with a dot, optional exponent
+syn match      embryoFloat     display contained "\.\d\+\(e[-+]\=\d\+\)\=[fl]\=\>"
+"floating point number, without dot, with exponent
+syn match      embryoFloat     display contained "\d\+e[-+]\=\d\+[fl]\=\>"
+" flag an octal number with wrong digits
+syn match      embryoOctalError        display contained "0\o*[89]\d*"
+syn case match
+
+if exists("embryo_comment_strings")
+  " A comment can contain embryoString, embryoCharacter and embryoNumber.
+  " But a "*/" inside a embryoString in a embryoComment DOES end the comment!  So we
+  " need to use a special type of embryoString: embryoCommentString, which also ends
+  " on "*/", and sees a "*" at the start of the line as comment again.
+  " Unfortunately this doesn't very well work for // type of comments :-(
+  syntax match embryoCommentSkip               contained "^\s*\*\($\|\s\+\)"
+  syntax region embryoCommentString    contained start=+L\=\\\@<!"+ skip=+\\\\\|\\"+ end=+"+ end=+\*/+me=s-1 contains=embryoSpecial,embryoCommentSkip
+  syntax region embryoComment2String   contained start=+L\=\\\@<!"+ skip=+\\\\\|\\"+ end=+"+ end="$" contains=embryoSpecial
+  syntax region embryoCommentL         start="//" skip="\\$" end="$" keepend contains=@embryoCommentGroup,embryoComment2String,embryoCharacter,embryoNumbersCom,embryoSpaceError
+  syntax region embryoComment          matchgroup=embryoCommentStart start="/\*" matchgroup=NONE end="\*/" contains=@embryoCommentGroup,embryoCommentStartErr,embryoCommentString,embryoCharacter,embryoNumbersCom,embryoSpaceError
+else
+  syn region   embryoCommentL          start="//" skip="\\$" end="$" keepend contains=@embryoCommentGroup,embryoSpaceError
+  syn region   embryoComment           matchgroup=embryoCommentStart start="/\*" matchgroup=NONE end="\*/" contains=@embryoCommentGroup,embryoCommentStartErr,embryoSpaceError
+endif
+" keep a // comment separately, it terminates a preproc. conditional
+syntax match   embryoCommentError              display "\*/"
+syntax match   embryoCommentStartErr   display "/\*"me=e-1 contained
+
+syn region     embryoPreCondit start="^\s*#\s*\(if\|ifdef\|ifndef\|elif\)\>" skip="\\$" end="$" end="//"me=s-1 contains=embryoComment,embryoCharacter,embryoParenError,embryoNumbers,embryoCommentError,embryoSpaceError
+syn match      embryoPreCondit display "^\s*#\s*\(else\|endif\)\>"
+syn region     embryoIncluded  display contained start=+"+ skip=+\\\\\|\\"+ end=+"+
+syn match      embryoIncluded  display contained "<[^>]*>"
+syn match      embryoInclude   display "^\s*#\s*include\>\s*["<]" contains=embryoIncluded
+syn cluster    embryoPreProcGroup      contains=embryoPreCondit,embryoIncluded,embryoInclude,embryoDefine,embryoErrInParen,embryoErrInBracket,embryoCommentSkip,embryoCommentString,embryoComment2String,@embryoCommentGroup,embryoCommentStartErr,embryoParen,embryoBracket,embryoMulti,embryoUserLabel
+syn cluster    embryoAlphaNum  contains=embryoSpecial,embryoOctalZero,embryoFormat,embryoNumber,embryoFloat,embryoOctal,embryoOctalError,embryoNumbersCom,embryoString
+syn region     embryoDefine    start="^\s*#\s*\(define\|undef\)\>" skip="\\$" end="$" end="//"me=s-1 contains=ALLBUT,@embryoPreProcGroup
+syn region     embryoPreProc   start="^\s*#\s*\(pragma\>\|line\>\|warning\>\|warn\>\|error\>\)" skip="\\$" end="$" keepend contains=ALLBUT,@embryoPreProcGroup
+
+syn match      embryoUserLabel display "\I\i*" contained
+
+syn match      embryoFunctionName      "\h\w*\s*\%((\@=\)"
+
+if exists("embryo_minlines")
+  let b:embryo_minlines = embryo_minlines
+else
+  let b:embryo_minlines = 50   " #if 0 constructs can be long
+endif
+exec "syn sync ccomment embryoComment minlines=" . b:embryo_minlines
+"syn sync fromstart
+
+" Define the default highlighting.
+" For version 5.7 and earlier: only when not done already
+" For version 5.8 and later: only when an item doesn't have highlighting yet
+if version >= 508 || !exists("did_embryo_syn_inits")
+  if version < 508
+    let did_embryo_syn_inits = 1
+    command -nargs=+ HiLink hi link <args>
+  else
+    command -nargs=+ HiLink hi def link <args>
+  endif
+
+  HiLink embryoFormat          embryoSpecial
+  HiLink embryoCommentL                embryoComment
+  HiLink embryoCommentStart    embryoComment
+  HiLink embryoLabel           Label
+  HiLink embryoUserLabel       Label
+  HiLink embryoConditional     Conditional
+  HiLink embryoRepeat          Repeat
+  HiLink embryoBranch          Conditional
+  HiLink embryoReserved                Keyword
+  HiLink embryoCharacter       Character
+  HiLink embryoSpecialCharacter        cSpecial
+  HiLink embryoNumber          Number
+  HiLink embryoOctal           Number
+  HiLink embryoOctalZero       PreProc  " link this to Error if you want
+  HiLink embryoFloat           Float
+  HiLink embryoOctalError      embryoError
+  HiLink embryoParenError      embryoError
+  HiLink embryoErrInParen      embryoError
+  HiLink embryoErrInBracket    embryoError
+  HiLink embryoCommentError    embryoError
+  HiLink embryoCommentStartErr embryoError
+  HiLink embryoSpaceError      embryoError
+  HiLink embryoSpecialError    embryoError
+  HiLink embryoOperator                Operator
+  HiLink embryoStructure       Structure
+  HiLink embryoEdjeKey         Structure
+  HiLink embryoStorageClass    StorageClass
+  HiLink embryoInclude         Include
+  HiLink embryoPreProc         PreProc
+  HiLink embryoDefine          Macro
+  HiLink embryoIncluded                embryoString
+  HiLink embryoError           Error
+  HiLink embryoStatement       Statement
+  HiLink embryoPreCondit       PreCondit
+  HiLink embryoType            Type
+  HiLink embryoConstant                Constant
+  HiLink embryoCommentString   embryoString
+  HiLink embryoComment2String  embryoString
+  HiLink embryoCommentSkip     embryoComment
+  HiLink embryoString          String
+  HiLink embryoComment         Comment
+  HiLink embryoSpecial         SpecialChar
+  HiLink embryoTodo            Todo
+  HiLink embryoFunctionName    Function
+
+  delcommand HiLink
+endif
+
+let b:current_syntax = "embryo"
+
+" vim: ts=8
diff --git a/data/edc.vim b/data/edc.vim
new file mode 100644 (file)
index 0000000..1d9be9c
--- /dev/null
@@ -0,0 +1,340 @@
+" Vim syntax file
+" Language:    EDC
+" Maintainer:  billiob <billiob@gmail.com>
+" Last Change: 04/21/2010
+
+" For version 5.x: Clear all syntax items
+" For version 6.x: Quit when a syntax file was already loaded
+if version < 600
+  syntax clear
+elseif exists("b:current_syntax")
+  finish
+endif
+
+" A bunch of useful C keywords
+syn keyword    cStructure      images data fonts collections group externals
+syn keyword    cStructure      part parts dragable description rel1 rel2
+syn keyword    cStatement      text image font fill origin size tag
+syn keyword    cStructure      programs program script script_only lua_script lua_script_only styles style base
+syn keyword    cStructure      spectra spectrum box
+syn match      cType           "+ + +;" contained
+
+syn keyword    cLabel          item name min max type effect
+syn keyword    cLabel          mouse_events repeat_events clip_to
+syn keyword    cLabel          color_class text_class x y confine
+syn keyword    cLabel          state visible align step aspect aspect_preference fixed
+syn keyword    cLabel          relative offset to to_x to_y normal tween
+syn keyword    cLabel          border color color2 color3 font size fit align
+syn keyword    cLabel          signal source action transition in target after
+syn keyword    cLabel          text smooth inherit scale middle ignore_flags
+syn keyword    cLabel          alias events entry_mode select_mode multiline
+syn keyword    cLabel          source1 source2 source3 source4 source5 source6
+syn keyword    cLabel          text_source transitions layout padding
+syn keyword    cLabel          size_w size_h size_max_w size_max_h size_min_w size_min_w
+syn keyword    cLabel          spread scale_hint elipsis pointer_mode prefer
+syn keyword    cLabel          precise_is_inside use_alternate_font_metrics options
+syn keyword    cLabel          aspect_mode position span angle repch api
+syn keyword    cLabel          external
+
+syn keyword    cConditional    if else switch
+syn keyword    cRepeat         while for do
+syn keyword    cConstant       COMP RAW LOSSY USER
+syn keyword    cConstant       RECT TEXT IMAGE SWALLOW TEXTBLOCK GRADIENT
+syn keyword    cConstant       GROUP BOX TABLE EXTERNAL ITEM
+syn keyword    cConstant       SOLID AUTOGRAB NOGRAB
+syn keyword    cConstant       NONE PLAIN OUTLINE SOFT_OUTLINE SHADOW
+syn keyword    cConstant       SOFT_SHADOW OUTLINE_SHADOW OUTLINE_SOFT_SHADOW
+syn keyword    cConstant       FAR_SOFT_SHADOW FAR_SHADOW GLOW
+syn keyword    cConstant       STATE_SET ACTION_STOP SIGNAL_EMIT
+syn keyword    cConstant       SCRIPT LUA_SCRIPT
+syn keyword    cConstant       DRAG_VAL_SET DRAG_VAL_STEP DRAG_VAL_PAGE
+syn keyword    cConstant       LINEAR SINUSOIDAL ACCELERATE DECELERATE
+syn keyword    cConstant       VERTICAL HORIZONTAL ON_HOLD BOTH EDITABLE EXPLICIT
+syn keyword    cConstant       FOCUS_SET "default" NEITHER
+syn keyword    cConstant       DYNAMIC STATIC
+
+syn keyword    cTodo           contained TODO FIXME XXX
+
+" cCommentGroup allows adding matches for special things in comments
+syn cluster    cCommentGroup   contains=cTodo
+
+" String and Character constants
+" Highlight special characters (those which have a backslash) differently
+syn match      cSpecial        display contained "\\\(x\x\+\|\o\{1,3}\|.\|$\)"
+if !exists("c_no_utf")
+  syn match    cSpecial        display contained "\\\(u\x\{4}\|U\x\{8}\)"
+endif
+if exists("c_no_cformat")
+  syn region   cString         start=+L\="+ skip=+\\\\\|\\"+ end=+"+ contains=cSpecial
+  " cCppString: same as cString, but ends at end of line
+  syn region   cCppString      start=+L\="+ skip=+\\\\\|\\"\|\\$+ excludenl end=+"+ end='$' contains=cSpecial
+else
+  syn match    cFormat         display "%\(\d\+\$\)\=[-+' #0*]*\(\d*\|\*\|\*\d\+\$\)\(\.\(\d*\|\*\|\*\d\+\$\)\)\=\([hlL]\|ll\)\=\([diuoxXfeEgGcCsSpn]\|\[\^\=.[^]]*\]\)" contained
+  syn match    cFormat         display "%%" contained
+  syn region   cString         start=+L\="+ skip=+\\\\\|\\"+ end=+"+ contains=cSpecial,cFormat
+  " cCppString: same as cString, but ends at end of line
+  syn region   cCppString      start=+L\="+ skip=+\\\\\|\\"\|\\$+ excludenl end=+"+ end='$' contains=cSpecial,cFormat
+endif
+
+syn match      cCharacter      "L\='[^\\]'"
+syn match      cCharacter      "L'[^']*'" contains=cSpecial
+if exists("c_gnu")
+  syn match    cSpecialError   "L\='\\[^'\"?\\abefnrtv]'"
+  syn match    cSpecialCharacter "L\='\\['\"?\\abefnrtv]'"
+else
+  syn match    cSpecialError   "L\='\\[^'\"?\\abfnrtv]'"
+  syn match    cSpecialCharacter "L\='\\['\"?\\abfnrtv]'"
+endif
+syn match      cSpecialCharacter display "L\='\\\o\{1,3}'"
+syn match      cSpecialCharacter display "'\\x\x\{1,2}'"
+syn match      cSpecialCharacter display "L'\\x\x\+'"
+
+"when wanted, highlight trailing white space
+if exists("c_space_errors")
+  if !exists("c_no_trail_space_error")
+    syn match  cSpaceError     display excludenl "\s\+$"
+  endif
+  if !exists("c_no_tab_space_error")
+    syn match  cSpaceError     display " \+\t"me=e-1
+  endif
+endif
+
+"catch errors caused by wrong parenthesis and brackets
+syn cluster    cParenGroup     contains=cParenError,cIncluded,cSpecial,cCommentSkip,cCommentString,cComment2String,@cCommentGroup,cCommentStartError,cUserCont,cUserLabel,cBitField,cCommentSkip,cOctalZero,cCppOut,cCppOut2,cCppSkip,cFormat,cNumber,cFloat,cOctal,cOctalError,cNumbersCom
+if exists("c_no_bracket_error")
+  syn region   cParen          transparent start='(' end=')' contains=ALLBUT,@cParenGroup,cCppParen,cCppString
+  " cCppParen: same as cParen but ends at end-of-line; used in cDefine
+  syn region   cCppParen       transparent start='(' skip='\\$' excludenl end=')' end='$' contained contains=ALLBUT,@cParenGroup,cParen,cString
+  syn match    cParenError     display ")"
+  syn match    cErrInParen     display contained "[{}]"
+else
+  syn region   cParen          transparent start='(' end=')' contains=ALLBUT,@cParenGroup,cCppParen,cErrInBracket,cCppBracket,cCppString
+  " cCppParen: same as cParen but ends at end-of-line; used in cDefine
+  syn region   cCppParen       transparent start='(' skip='\\$' excludenl end=')' end='$' contained contains=ALLBUT,@cParenGroup,cErrInBracket,cParen,cBracket,cString
+  syn match    cParenError     display "[\])]"
+  syn match    cErrInParen     display contained "[\]{}]"
+  syn region   cBracket        transparent start='\[' end=']' contains=ALLBUT,@cParenGroup,cErrInParen,cCppParen,cCppBracket,cCppString
+  " cCppBracket: same as cParen but ends at end-of-line; used in cDefine
+  syn region   cCppBracket     transparent start='\[' skip='\\$' excludenl end=']' end='$' contained contains=ALLBUT,@cParenGroup,cErrInParen,cParen,cBracket,cString
+  syn match    cErrInBracket   display contained "[);{}]"
+endif
+
+"integer number, or floating point number without a dot and with "f".
+syn case ignore
+syn match      cNumbers        display transparent "\<\d\|\.\d" contains=cNumber,cFloat,cOctalError,cOctal
+" Same, but without octal error (for comments)
+syn match      cNumbersCom     display contained transparent "\<\d\|\.\d" contains=cNumber,cFloat,cOctal
+syn match      cNumber         display contained "\d\+\(u\=l\{0,2}\|ll\=u\)\>"
+"hex number
+syn match      cNumber         display contained "0x\x\+\(u\=l\{0,2}\|ll\=u\)\>"
+" Flag the first zero of an octal number as something special
+syn match      cOctal          display contained "0\o\+\(u\=l\{0,2}\|ll\=u\)\>" contains=cOctalZero
+syn match      cOctalZero      display contained "\<0"
+syn match      cFloat          display contained "\d\+f"
+"floating point number, with dot, optional exponent
+syn match      cFloat          display contained "\d\+\.\d*\(e[-+]\=\d\+\)\=[fl]\="
+"floating point number, starting with a dot, optional exponent
+syn match      cFloat          display contained "\.\d\+\(e[-+]\=\d\+\)\=[fl]\=\>"
+"floating point number, without dot, with exponent
+syn match      cFloat          display contained "\d\+e[-+]\=\d\+[fl]\=\>"
+" flag an octal number with wrong digits
+syn match      cOctalError     display contained "0\o*[89]\d*"
+syn case match
+
+if exists("c_comment_strings")
+  " A comment can contain cString, cCharacter and cNumber.
+  " But a "*/" inside a cString in a cComment DOES end the comment!  So we
+  " need to use a special type of cString: cCommentString, which also ends on
+  " "*/", and sees a "*" at the start of the line as comment again.
+  " Unfortunately this doesn't very well work for // type of comments :-(
+  syntax match cCommentSkip    contained "^\s*\*\($\|\s\+\)"
+  syntax region cCommentString contained start=+L\=\\\@<!"+ skip=+\\\\\|\\"+ end=+"+ end=+\*/+me=s-1 contains=cSpecial,cCommentSkip
+  syntax region cComment2String        contained start=+L\=\\\@<!"+ skip=+\\\\\|\\"+ end=+"+ end="$" contains=cSpecial
+  syntax region  cCommentL     start="//" skip="\\$" end="$" keepend contains=@cCommentGroup,cComment2String,cCharacter,cNumbersCom,cSpaceError
+  syntax region cComment       matchgroup=cCommentStart start="/\*" matchgroup=NONE end="\*/" contains=@cCommentGroup,cCommentStartError,cCommentString,cCharacter,cNumbersCom,cSpaceError
+else
+  syn region   cCommentL       start="//" skip="\\$" end="$" keepend contains=@cCommentGroup,cSpaceError
+  syn region   cComment        matchgroup=cCommentStart start="/\*" matchgroup=NONE end="\*/" contains=@cCommentGroup,cCommentStartError,cSpaceError
+endif
+" keep a // comment separately, it terminates a preproc. conditional
+syntax match   cCommentError   display "\*/"
+syntax match   cCommentStartError display "/\*"me=e-1 contained
+
+syn keyword    cOperator       sizeof
+if exists("c_gnu")
+  syn keyword  cStatement      __asm__
+  syn keyword  cOperator       typeof __real__ __imag__
+endif
+syn keyword    cType           int long short char void
+syn keyword    cType           signed unsigned float double
+if !exists("c_no_ansi") || exists("c_ansi_typedefs")
+  syn keyword   cType          size_t wchar_t ptrdiff_t sig_atomic_t fpos_t
+  syn keyword   cType          clock_t time_t va_list jmp_buf FILE DIR div_t ldiv_t
+  syn keyword   cType          mbstate_t wctrans_t wint_t wctype_t
+endif
+if !exists("c_no_c99") " ISO C99
+  syn keyword  cType           bool complex
+  syn keyword  cType           int8_t int16_t int32_t int64_t
+  syn keyword  cType           uint8_t uint16_t uint32_t uint64_t
+  syn keyword  cType           int_least8_t int_least16_t int_least32_t int_least64_t
+  syn keyword  cType           uint_least8_t uint_least16_t uint_least32_t uint_least64_t
+  syn keyword  cType           int_fast8_t int_fast16_t int_fast32_t int_fast64_t
+  syn keyword  cType           uint_fast8_t uint_fast16_t uint_fast32_t uint_fast64_t
+  syn keyword  cType           intptr_t uintptr_t
+  syn keyword  cType           intmax_t uintmax_t
+endif
+if exists("c_gnu")
+  syn keyword  cType           __label__ __complex__ __volatile__
+endif
+
+syn keyword    cStructure      struct union enum typedef
+syn keyword    cStorageClass   static register auto volatile extern const
+if exists("c_gnu")
+  syn keyword  cStorageClass   inline __attribute__
+endif
+
+if !exists("c_no_ansi") || exists("c_ansi_constants") || exists("c_gnu")
+  if exists("c_gnu")
+    syn keyword cConstant __GNUC__ __FUNCTION__ __PRETTY_FUNCTION__
+  endif
+  syn keyword cConstant __LINE__ __FILE__ __DATE__ __TIME__ __STDC__
+  syn keyword cConstant __STDC_VERSION__
+  syn keyword cConstant CHAR_BIT MB_LEN_MAX MB_CUR_MAX
+  syn keyword cConstant UCHAR_MAX UINT_MAX ULONG_MAX USHRT_MAX
+  syn keyword cConstant CHAR_MIN INT_MIN LONG_MIN SHRT_MIN
+  syn keyword cConstant CHAR_MAX INT_MAX LONG_MAX SHRT_MAX
+  syn keyword cConstant SCHAR_MIN SINT_MIN SLONG_MIN SSHRT_MIN
+  syn keyword cConstant SCHAR_MAX SINT_MAX SLONG_MAX SSHRT_MAX
+  syn keyword cConstant FLT_RADIX FLT_ROUNDS
+  syn keyword cConstant FLT_DIG FLT_MANT_DIG FLT_EPSILON
+  syn keyword cConstant DBL_DIG DBL_MANT_DIG DBL_EPSILON
+  syn keyword cConstant LDBL_DIG LDBL_MANT_DIG LDBL_EPSILON
+  syn keyword cConstant FLT_MIN FLT_MAX FLT_MIN_EXP FLT_MAX_EXP
+  syn keyword cConstant FLT_MIN_10_EXP FLT_MAX_10_EXP
+  syn keyword cConstant DBL_MIN DBL_MAX DBL_MIN_EXP DBL_MAX_EXP
+  syn keyword cConstant DBL_MIN_10_EXP DBL_MAX_10_EXP
+  syn keyword cConstant LDBL_MIN LDBL_MAX LDBL_MIN_EXP LDBL_MAX_EXP
+  syn keyword cConstant LDBL_MIN_10_EXP LDBL_MAX_10_EXP
+  syn keyword cConstant HUGE_VAL CLOCKS_PER_SEC NULL
+  syn keyword cConstant LC_ALL LC_COLLATE LC_CTYPE LC_MONETARY
+  syn keyword cConstant LC_NUMERIC LC_TIME
+  syn keyword cConstant SIG_DFL SIG_ERR SIG_IGN
+  syn keyword cConstant SIGABRT SIGFPE SIGILL SIGHUP SIGINT SIGSEGV SIGTERM
+  " Add POSIX signals as well...
+  syn keyword cConstant SIGABRT SIGALRM SIGCHLD SIGCONT SIGFPE SIGHUP
+  syn keyword cConstant SIGILL SIGINT SIGKILL SIGPIPE SIGQUIT SIGSEGV
+  syn keyword cConstant SIGSTOP SIGTERM SIGTRAP SIGTSTP SIGTTIN SIGTTOU
+  syn keyword cConstant SIGUSR1 SIGUSR2
+  syn keyword cConstant _IOFBF _IOLBF _IONBF BUFSIZ EOF
+  syn keyword cConstant FOPEN_MAX FILENAME_MAX L_tmpnam
+  syn keyword cConstant SEEK_CUR SEEK_END SEEK_SET
+  syn keyword cConstant TMP_MAX stderr stdin stdout
+  syn keyword cConstant EXIT_FAILURE EXIT_SUCCESS RAND_MAX
+  " Add POSIX errors as well
+  syn keyword cConstant E2BIG EACCES EAGAIN EBADF EBADMSG EBUSY
+  syn keyword cConstant ECANCELED ECHILD EDEADLK EDOM EEXIST EFAULT
+  syn keyword cConstant EFBIG EILSEQ EINPROGRESS EINTR EINVAL EIO EISDIR
+  syn keyword cConstant EMFILE EMLINK EMSGSIZE ENAMETOOLONG ENFILE ENODEV
+  syn keyword cConstant ENOENT ENOEXEC ENOLCK ENOMEM ENOSPC ENOSYS
+  syn keyword cConstant ENOTDIR ENOTEMPTY ENOTSUP ENOTTY ENXIO EPERM
+  syn keyword cConstant EPIPE ERANGE EROFS ESPIPE ESRCH ETIMEDOUT EXDEV
+  " math.h
+  syn keyword cConstant M_E M_LOG2E M_LOG10E M_LN2 M_LN10 M_PI M_PI_2 M_PI_4
+  syn keyword cConstant M_1_PI M_2_PI M_2_SQRTPI M_SQRT2 M_SQRT1_2
+endif
+if !exists("c_no_c99") " ISO C99
+  syn keyword cConstant true false
+endif
+
+syn region     cPreCondit      start="^\s*#\s*\(if\|ifdef\|ifndef\|elif\)\>" skip="\\$" end="$" end="//"me=s-1 contains=cComment,cCppString,cCharacter,cCppParen,cParenError,cNumbers,cCommentError,cSpaceError
+syn match      cPreCondit      display "^\s*#\s*\(else\|endif\)\>"
+if !exists("c_no_if0")
+  syn region   cCppOut         start="^\s*#\s*if\s\+0\+\>" end=".\|$" contains=cCppOut2
+  syn region   cCppOut2        contained start="0" end="^\s*#\s*\(endif\>\|else\>\|elif\>\)" contains=cSpaceError,cCppSkip
+  syn region   cCppSkip        contained start="^\s*#\s*\(if\>\|ifdef\>\|ifndef\>\)" skip="\\$" end="^\s*#\s*endif\>" contains=cSpaceError,cCppSkip
+endif
+syn region     cIncluded       display contained start=+"+ skip=+\\\\\|\\"+ end=+"+
+syn match      cIncluded       display contained "<[^>]*>"
+syn match      cInclude        display "^\s*#\s*include\>\s*["<]" contains=cIncluded
+"syn match cLineSkip   "\\$"
+syn cluster    cPreProcGroup   contains=cPreCondit,cIncluded,cInclude,cDefine,cErrInParen,cErrInBracket,cUserLabel,cSpecial,cOctalZero,cCppOut,cCppOut2,cCppSkip,cFormat,cNumber,cFloat,cOctal,cOctalError,cNumbersCom,cString,cCommentSkip,cCommentString,cComment2String,@cCommentGroup,cCommentStartError,cParen,cBracket,cMulti
+syn region     cDefine         start="^\s*#\s*\(define\|undef\)\>" skip="\\$" end="$" end="//"me=s-1 contains=ALLBUT,@cPreProcGroup
+syn region     cPreProc        start="^\s*#\s*\(pragma\>\|line\>\|warning\>\|warn\>\|error\>\)" skip="\\$" end="$" keepend contains=ALLBUT,@cPreProcGroup
+
+syn match      cUserLabel      display "\I\i*" contained
+
+
+
+if exists("c_minlines")
+  let b:c_minlines = c_minlines
+else
+  if !exists("c_no_if0")
+    let b:c_minlines = 50      " #if 0 constructs can be long
+  else
+    let b:c_minlines = 15      " mostly for () constructs
+  endif
+endif
+exec "syn sync ccomment cComment minlines=" . b:c_minlines
+
+" Define the default highlighting.
+" For version 5.7 and earlier: only when not done already
+" For version 5.8 and later: only when an item doesn't have highlighting yet
+if version >= 508 || !exists("did_c_syn_inits")
+  if version < 508
+    let did_c_syn_inits = 1
+    command -nargs=+ HiLink hi link <args>
+  else
+    command -nargs=+ HiLink hi def link <args>
+  endif
+
+  HiLink cFormat               cSpecial
+  HiLink cCppString            cString
+  HiLink cCommentL             cComment
+  HiLink cCommentStart         cComment
+  HiLink cLabel                        Label
+  HiLink cUserLabel            Label
+  HiLink cConditional          Conditional
+  HiLink cRepeat               Repeat
+  HiLink cCharacter            Character
+  HiLink cSpecialCharacter     cSpecial
+  HiLink cNumber               Number
+  HiLink cOctal                        Number
+  HiLink cOctalZero            PreProc  " link this to Error if you want
+  HiLink cFloat                        Float
+  HiLink cOctalError           cError
+  HiLink cParenError           cError
+  HiLink cErrInParen           cError
+  HiLink cErrInBracket         cError
+  HiLink cCommentError         cError
+  HiLink cCommentStartError    cError
+  HiLink cSpaceError           cError
+  HiLink cSpecialError         cError
+  HiLink cOperator             Operator
+  HiLink cStructure            Structure
+  HiLink cStorageClass         StorageClass
+  HiLink cInclude              Include
+  HiLink cPreProc              PreProc
+  HiLink cDefine               Macro
+  HiLink cIncluded             cString
+  HiLink cError                        Error
+  HiLink cStatement            Statement
+  HiLink cPreCondit            PreCondit
+  HiLink cType                 Type
+  HiLink cConstant             Constant
+  HiLink cCommentString                cString
+  HiLink cComment2String       cString
+  HiLink cCommentSkip          cComment
+  HiLink cString               String
+  HiLink cComment              Comment
+  HiLink cSpecial              SpecialChar
+  HiLink cTodo                 Todo
+  HiLink cCppSkip              cCppOut
+  HiLink cCppOut2              cCppOut
+  HiLink cCppOut               Comment
+
+  delcommand HiLink
+endif
+
+let b:current_syntax = "edc"
+
+" vim: ts=8
diff --git a/data/edje-mode.el b/data/edje-mode.el
new file mode 100644 (file)
index 0000000..33c6fe6
--- /dev/null
@@ -0,0 +1,512 @@
+;;; edje-mode-el -- Major mode for editing Edje files
+
+;; Author: Gustavo Sverzut Barbieri <barbieri@gmail.com>
+;; Created: 2007-07-23
+;; Keywords: Edje major-mode
+;; Url: http://barbieri-playground.googlecode.com/svn/dot-files/edje-mode.el
+;;      (if you find this file have problems, check that Url and request update)
+
+;; Copyright (C) 2007 Gustavo Sverzut Barbieri <barbieri@gmail.com>
+
+;; This program is free software; you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License as
+;; published by the Free Software Foundation; either version 2 of
+;; the License, or (at your option) any later version.
+
+;; This program is distributed in the hope that it will be
+;; useful, but WITHOUT ANY WARRANTY; without even the implied
+;; warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+;; PURPOSE.  See the GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public
+;; License along with this program; if not, write to the Free
+;; Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+;; MA 02111-1307 USA
+
+;;; Commentary:
+;;
+;; This mode is based on tutorial from Scott Andrew Borton:
+;; http://two-wugs.net/emacs/mode-tutorial.html
+
+
+(defvar edje-mode-hook nil)
+
+(defun number-or-nil-to-string (v &optional default)
+  (cond ((numberp v) (number-to-string v))
+        ((stringp v) (if (string= v "") (number-to-string default) v))
+        (t           (number-to-string default))))
+
+(defun non-empty-string (s)
+  (and (not (eq 'nil s))
+       (not (string= "" s))))
+
+(defun edje-new-program-action-signal-emit (source emission)
+  "Insert new program SIGNAL_EMIT"
+  (interactive "ssource: \nsemission: ")
+  (insert
+   (concat
+    "               action: SIGNAL_EMIT \"" source "\" \"" emission "\";\n"
+    )))
+
+(defun edje-new-program-action-state-set (state value target)
+  "Insert new program STATE_SET"
+  (interactive "sstate: \nsvalue (0.0): \nstarget: ")
+  (insert
+   (concat
+    "               action: STATE_SET \"" state "\" "
+       (number-or-nil-to-string value 0.0) ";\n"
+    "               target: \"" target "\";\n"
+    )))
+
+(defun edje-new-program-action (action)
+  "Insert new program action"
+  (interactive "saction: ")
+  (setq action (upcase action))
+  (cond ((string= action "STATE_SET")
+         (edje-new-program-action-state-set "" 0.0 ""))
+        ((string= action "SIGNAL_EMIT")
+         (edje-new-program-action-signal-emit "" ""))
+        ))
+
+(defun edje-new-program (name signal source action)
+  "Insert new program block"
+  (interactive "sname: \nssignal: \nssource: \nsaction: ")
+  (insert
+   (concat
+    "\n"
+    "            program {\n"
+    "               name: \"" name "\";\n"
+
+    (if (non-empty-string signal)
+        (concat "               signal: \"" signal "\";\n"))
+
+    (if (non-empty-string source)
+        (concat "               source: \"" source "\";\n"))
+    ))
+
+  (edje-new-program-action action)
+
+  (insert
+   (concat
+    "            }\n"
+    "\n"
+    )))
+
+(defun edje-new-desc-relative (x y &optional defx defy)
+  "Insert new part description 'relative' line"
+  (interactive "sx: \nsy: ")
+  (insert
+   (concat
+    "                  relative: "
+    (number-or-nil-to-string x defx) " "
+    (number-or-nil-to-string y defy) ";\n"
+    )))
+
+(defun edje-new-desc-offset (x y &optional defx defy)
+  "Insert new part description 'offset' line"
+  (interactive "sx: \nsy: ")
+  (insert
+   (concat
+    "                  offset: "
+    (number-or-nil-to-string x defx) " "
+    (number-or-nil-to-string y defy) ";\n"
+    )))
+
+(defun edje-new-desc-inherit (name val)
+  "Insert new part description 'inherit' line"
+  (interactive "sname: \nsvalue: ")
+  (insert
+   (concat
+    "               inherit: \"" name "\" "
+    (number-or-nil-to-string val 0.0) ";\n"
+    )))
+
+(defun edje-new-desc-text (font size text)
+  "Insert new part description 'text' block"
+  (interactive "sfont: \nssize: \nstext: ")
+  (insert
+   (concat
+    "               text {\n"
+    "                  font: \"" font "\";\n"
+    "                  size: " (number-or-nil-to-string size) ";\n"
+    "                  text: \"" text "\";\n"
+    "               }\n"
+    )))
+
+(defun edje-new-desc-image (name)
+  "Insert new part description 'image' block"
+  (interactive "sname: ")
+  (insert
+   (concat
+    "               image {\n"
+    "                  normal: \"" name "\";\n"
+    "               }\n"
+    )))
+
+(defun edje-new-desc-color (r g b a &optional defr defg defb defa)
+  "Insert new part description 'color' line"
+  (interactive "sred: \nsgreen: \nsblue: \nsalpha: ")
+  (insert
+   (concat
+    "               color: "
+    (number-or-nil-to-string r defr) " "
+    (number-or-nil-to-string g defg) " "
+    (number-or-nil-to-string b defb) " "
+    (number-or-nil-to-string a defa) ";\n"
+    )))
+
+(defun edje-new-desc (name val &optional
+                           r1_rx r1_ry
+                           r2_rx r2_ry
+                           r1_ox r1_oy
+                           r2_ox r2_oy
+                           part_type)
+  "Insert new part description block"
+  (interactive "sName: \nsValue: ")
+  (insert
+   (concat
+    "            description {\n"
+    "               state: \"" name "\" " (number-or-nil-to-string val 0.0) ";\n"))
+  (if (string= part_type "RECT") (edje-new-desc-color 255 255 255 255))
+  (insert "               rel1 {\n")
+  (edje-new-desc-relative r1_rx r1_ry 0.0 0.0)
+  (edje-new-desc-offset r1_ox r1_oy 0 0)
+  (insert
+   (concat
+    "               }\n"
+    "               rel2 {\n"
+    ))
+  (edje-new-desc-relative r2_rx r2_ry 1.0 1.0)
+  (edje-new-desc-offset r2_ox r2_oy -1 -1)
+  (insert "               }\n")
+  (cond ((string= part_type "IMAGE") (edje-new-desc-image ""))
+        ((string= part_type "TEXT") (edje-new-desc-text "" 10 "contents"))
+        )
+  (insert "            }\n")
+  )
+
+(defun edje-new-part (name type &optional
+                           r1_rx r1_ry
+                           r2_rx r2_ry
+                           r1_ox r1_oy
+                           r2_ox r2_oy)
+  "Insert new part"
+  (interactive "sName: \nsType: ")
+  (setq type (upcase type))
+  (insert
+   (concat
+    "\n"
+    "         part {\n"
+    "            name: \"" name "\";\n"
+    "            type: " type ";\n"
+    "            mouse_events: 0;\n"
+    ))
+  (edje-new-desc "default" 0.0 r1_rx r1_ry r2_rx r2_ry r1_ox r1_oy r2_ox r2_oy type)
+  (insert
+   (concat
+    "         }\n"
+    )))
+
+(defun edje-setup-compile ()
+  (set (make-local-variable 'compile-command)
+       (concat "edje_cc " (buffer-file-name))
+  ))
+
+(defun edje-cc ()
+  "Runs edje_cc with current buffer."
+  (interactive)
+  (compile (edje-setup-compile)))
+
+(defvar edje-mode-map
+  (let ((edje-mode-map (make-sparse-keymap)))
+    (define-key edje-mode-map "\C-j" 'newline-and-indent)
+    (define-key edje-mode-map "\C-cp" 'edje-new-part)
+    (define-key edje-mode-map "\C-cd" 'edje-new-desc)
+    (define-key edje-mode-map "\C-cr" 'edje-new-desc-relative)
+    (define-key edje-mode-map "\C-co" 'edje-new-desc-offset)
+    (define-key edje-mode-map "\C-ch" 'edje-new-desc-inherit)
+    (define-key edje-mode-map "\C-cc" 'edje-new-desc-color)
+    (define-key edje-mode-map "\C-ci" 'edje-new-desc-image)
+    (define-key edje-mode-map "\C-ct" 'edje-new-desc-text)
+    (define-key edje-mode-map "\C-cg" 'edje-new-program)
+    (define-key edje-mode-map "\C-ca" 'edje-new-program-action)
+    (define-key edje-mode-map "\C-cs" 'edje-new-program-action-state-set)
+    (define-key edje-mode-map "\C-ce" 'edje-new-program-action-signal-emit)
+    edje-mode-map)
+  "Keymap for Edje major mode")
+
+(add-hook 'c-mode-hook 'edje-setup-compile)
+(add-to-list 'auto-mode-alist '("\\.edc$" . edje-mode))
+
+(defconst edje-font-lock-keywords-1
+  (eval-when-compile
+    (list
+     (list (concat "[ \t]*\\<"
+                   (regexp-opt
+                    '(
+                      "collections"
+                      "data"
+                      "description"
+                      "dragable"
+                      "fill"
+                      "fonts"
+                      "group"
+                      "image"
+                      "images"
+                      "origin"
+                      "part"
+                      "parts"
+                      "program"
+                      "programs"
+                      "rel1"
+                      "rel2"
+                      "script"
+                      "spectra"
+                      "style"
+                      "styles"
+                      "text"
+                      ) t) "\\>\\([ \t]*{\\|\\.\\)")
+           '(1 font-lock-function-name-face))
+
+     ))
+  "Major keywords")
+
+(defconst edje-font-lock-keywords-2
+  (eval-when-compile
+    (append edje-font-lock-keywords-1
+            (list
+             (list
+              (concat "^\\([ \t]*\\|[ \t]*[a-z]+\\.\\|\\)\\<"
+                      (regexp-opt
+                       '("action"
+                         "after"
+                         "alias"
+                         "align"
+                         "angle"
+                         "aspect"
+                         "aspect_preference"
+                         "base"
+                         "border"
+                         "clip_to"
+                         "collections"
+                         "color"
+                         "color2"
+                         "color3"
+                         "color_class"
+                         "color_classes"
+                         "confine"
+                         "data"
+                         "description"
+                         "dragable"
+                         "effect"
+                         "elipsis"
+                         "events"
+                         "fill"
+                         "fit"
+                         "fixed"
+                         "font"
+                         "fonts"
+                         "gradient"
+                         "group"
+                         "ignore_flags"
+                         "image"
+                         "images"
+                         "in"
+                         "inherit"
+                         "item"
+                         "max"
+                         "middle"
+                         "min"
+                         "mouse_events"
+                         "name"
+                         "normal"
+                         "offset"
+                         "origin"
+                         "part"
+                         "parts"
+                         "pointer_mode"
+                         "precise_is_inside"
+                         "program"
+                         "programs"
+                         "rel1"
+                         "rel2"
+                         "relative"
+                         "repeat_events"
+                         "signal"
+                         "size"
+                         "smooth"
+                         "source"
+                         "spectra"
+                         "spectrum"
+                         "spread"
+                         "state"
+                         "step"
+                         "style"
+                         "styles"
+                         "tag"
+                         "target"
+                         "text"
+                         "text_class"
+                         "text_source"
+                         "to"
+                         "to_x"
+                         "to_y"
+                         "transition"
+                         "tween"
+                         "type"
+                         "use_alternate_font_metrics"
+                         "visible"
+                         "x"
+                         "y"
+                         ) t) "\\>[ \t]*[:,]")
+              '(2 font-lock-keyword-face))
+             )))
+  "Minor keywords")
+
+(defconst edje-font-lock-keywords-3
+  (eval-when-compile
+    (append edje-font-lock-keywords-2
+            (list
+             (list
+              (concat "\\<"
+                      (regexp-opt
+                       '(; image options (st_images_image)
+                         "RAW"
+                         "COMP"
+                         "LOSSY"
+                         "USER"
+                         ; part types (st_collections_group_parts_part_type)
+                         "NONE"
+                         "RECT"
+                         "TEXT"
+                         "IMAGE"
+                         "SWALLOW"
+                         "TEXTBLOCK"
+                         "GRADIENT"
+                         "GROUP"
+                         ; ignore flags (st_collections_group_parts_part_ignore_flags)
+                         ;"NONE"
+                         "ON_HOLD"
+                         ; pointer mode (st_collections_group_parts_part_pointer_mode)
+                         "AUTOGRAB"
+                         "NOGRAB"
+                         ; aspect (st_collections_group_parts_part_description_aspect_preference)
+                         "NONE"
+                         "VERTICAL"
+                         "HORIZONTAL"
+                         "BOTH"
+                         ; text effect (st_collections_group_parts_part_effect)
+                         "NONE"
+                         "PLAIN"
+                         "OUTLINE"
+                         "SOFT_OUTLINE"
+                         "SHADOW"
+                         "SOFT_SHADOW"
+                         "OUTLINE_SHADOW"
+                         "OUTLINE_SOFT_SHADOW"
+                         "FAR_SHADOW"
+                         "FAR_SOFT_SHADOW"
+                         "GLOW"
+                         ; image fill (st_collections_group_parts_part_description_fill_type)
+                         "SCALE"
+                         "TILE"
+                         ; program action (st_collections_group_programs_program_action)
+                         "STATE_SET"
+                         "ACTION_STOP"
+                         "SIGNAL_EMIT"
+                         "DRAG_VAL_SET"
+                         "DRAG_VAL_STEP"
+                         "DRAG_VAL_PAGE"
+                         "SCRIPT"
+                         ; program transition (st_collections_group_programs_program_transition)
+                         "LINEAR"
+                         "SINUSOIDAL"
+                         "ACCELERATE"
+                         "DECELERATE"
+                         ) t) "\\>")
+              '(1 font-lock-builtin-face))
+             )))
+  "Enumerate values")
+
+(defconst edje-font-lock-keywords-4
+  (eval-when-compile
+    (append edje-font-lock-keywords-3
+            (list
+             (list
+              (concat "[ \t]*#"
+                      (regexp-opt
+                       '("if"
+                         "ifdef"
+                         "ifndef"
+                         "define"
+                         "else"
+                         "endif"
+                         "include"
+                         "undef") t) "[ \t]*")
+              '(1 font-lock-builtin-face))
+             )))
+  "CPP directives")
+
+(defconst edje-font-lock-keywords-5
+  (eval-when-compile
+    (append edje-font-lock-keywords-4
+            (list
+             (list "[ \t]*#undef[ \t]+\\([a-zA-Z_][a-zA-Z0-9_]*\\)"
+                   '(1 font-lock-variable-name-face))
+             (list "[ \t]*#define[ \t]+\\([a-zA-Z_][a-zA-Z0-9_]*\\)("
+                   '(1 font-lock-function-name-face))
+             (list "[ \t]*#define[ \t]+\\([a-zA-Z_][a-zA-Z0-9_]*\\)"
+                   '(1 font-lock-variable-name-face))
+             )))
+  "CPP directives that define constants")
+
+
+(defvar edje-font-lock-keywords edje-font-lock-keywords-5)
+
+(defvar edje-mode-syntax-table
+  (let ((edje-mode-syntax-table (make-syntax-table)))
+    ; This is added so entity names with underscores can be more easily parsed
+    (modify-syntax-entry ?_ "w" edje-mode-syntax-table)
+    (modify-syntax-entry ?/ ". 124b" edje-mode-syntax-table)
+    (modify-syntax-entry ?* ". 23" edje-mode-syntax-table)
+    (modify-syntax-entry ?\n "> b" edje-mode-syntax-table)
+
+    edje-mode-syntax-table)
+  "Syntax table for edje-mode")
+
+(c-add-style
+ "edje"
+ '("gnu"
+   (indent-tabs-mode . nil)
+   (tab-width . 8)
+   (c-basic-offset . 3)
+   (c-backslash-column . 72)
+   (c-hanging-braces-alist  .
+                            ((block-open after)
+                             (brace-list-open after)
+                             (substatement-open after))
+                            )
+   (c-offsets-alist         .
+                            ((statement-block-intro . +)
+                             (defun-open            . 0)
+                             (substatement-open     . 0)
+                             (defun-block-intro     . +)
+                             (block-open            . 0)
+                             (label                 . +)
+                             ))))
+
+
+(define-derived-mode edje-mode c-mode "Edje"
+  "Major mode for editing Edje files"
+  (interactive)
+  (use-local-map edje-mode-map)
+  (set-syntax-table edje-mode-syntax-table)
+  (set (make-local-variable 'font-lock-defaults) '(edje-font-lock-keywords))
+  (set (make-local-variable 'require-final-newline) t)
+  (c-set-style "edje")
+  (run-hooks 'edje-mode-hook)
+  )
+
+(provide 'edje-mode)
+
+;;; edje-mode.el ends here
diff --git a/data/edje.xml b/data/edje.xml
new file mode 100644 (file)
index 0000000..eb299e7
--- /dev/null
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<mime-info xmlns="http://www.freedesktop.org/standards/shared-mime-info">
+       <mime-type type="text/edje">
+               <comment>Edje source file</comment>
+               <glob pattern="*.edc"/>
+       </mime-type>
+       <mime-type type="application/edje">
+               <comment>Edje file</comment>
+               <glob pattern="*.edj"/>
+       </mime-type>
+</mime-info>
diff --git a/data/include/.cvsignore b/data/include/.cvsignore
new file mode 100644 (file)
index 0000000..282522d
--- /dev/null
@@ -0,0 +1,2 @@
+Makefile
+Makefile.in
diff --git a/data/include/Makefile.am b/data/include/Makefile.am
new file mode 100644 (file)
index 0000000..478813c
--- /dev/null
@@ -0,0 +1,10 @@
+
+MAINTAINERCLEANFILES = Makefile.in
+
+FILES = edje.inc
+
+incdir = $(pkgdatadir)/include
+inc_DATA = $(FILES)
+
+EXTRA_DIST = $(FILES)
+
diff --git a/data/include/edje.inc b/data/include/edje.inc
new file mode 100644 (file)
index 0000000..bcae020
--- /dev/null
@@ -0,0 +1,252 @@
+/* ************************** */
+/* This is for script-only objects */
+/* ************************** */
+
+native e_obj_del(obj);
+
+native e_obj_rect_add();
+
+native e_obj_show(obj);
+native e_obj_hide(obj);
+native e_obj_move(obj, x, y);
+native e_obj_resize(obj, w, h);
+native e_obj_geometry_set(obj, x, y, w, h);
+native e_obj_geometry_get(obj, &x, &y, &w, &h);
+native e_obj_color_set(obj, r, g, b, a);
+native e_obj_color_get(obj, &r, &g, &b, &a);
+
+/* threw this in for debug... but need it */
+native e_signal_emit(sig[], src[]);
+
+
+
+
+
+
+
+
+
+
+
+
+
+/* ************************** */
+/* The below is for non-script-only objects. these calls will not work for */
+/* script-only objects. above are for script-only. perhaps this will be */
+/* deprecated sometime? or merged to the above partly? */
+/* ************************** */
+
+/* Edje exported calls */
+
+/************************************************/
+/* Basic data storage/retrieval (it's explicit) */
+/************************************************/
+/* Example:
+ * 
+ * In the "global" script section of a group:
+ * 
+ * script {
+ *   public global_value1;
+ *   public global_value2;
+ *   public global_value3;
+ * }
+ * 
+ * In the program script sections, OR in any global functions/routines:
+ * ( several examples of setting/getting values)
+ * 
+ * set_int(global_value1, 7);
+ * set_float(global_value2, 42.0);
+ * set_str(global_value3, "I am a smelly fish!");
+ * new value1 = get_int(global_value1);
+ * new Float:value2 = get_float(global_value2);
+ * new value3[100]; get_str(global_value3, value3, 100);
+ * set_int(global_value1, value1);
+ * set_float(global_value2, value2);
+ * set_str(global_value3, value3);
+ */
+native       get_int   (id);
+native       set_int   (id, val);
+native Float:get_float (id);
+native       set_float (id, Float:val);
+native       get_strlen(id);
+native       get_str   (id, dst[], maxlen);
+native       set_str   (id, str[]);
+
+/********************/
+/* Edje list calls */
+/********************/
+native       count      (id);
+native       remove     (id, n);
+native       append_int (id, v);
+native       prepend_int(id, v);
+native       insert_int (id, pos, v);
+native       replace_int (id, pos, v);
+native       fetch_int  (id, pos);
+native       append_str (id, str[]);
+native       prepend_str(id, str[]);
+native       insert_str (id, pos, str[]);
+native       replace_str(id, pos, str[]);
+native       fetch_str  (id, pos, dst[], maxlen);
+native       append_float (id, Float:v);
+native       prepend_float(id, Float:v);
+native       insert_float (id, pos, Float:v);
+native       replace_float(id, pos, Float:v);
+native Float:fetch_float  (id, pos);
+
+/********************/
+/* Edje timer calls */
+/********************/
+native       timer       (Float:in, fname[], val);
+native       cancel_timer(id);
+
+/*******************/
+/* Edje anim calls */
+/*******************/
+native       anim       (Float:len, fname[], val);
+native       cancel_anim(id);
+
+/***********************************************************/
+/* Edje utility calls for dealing with edjes/programs etc. */
+/***********************************************************/
+/* Example:
+ * 
+ * emit("this_thing", "clicked");
+ * emit("state", "playing");
+ * 
+ * set_state(PART:"logo", "glowing", 0.0);
+ * set_state(PART:"button", "default", 0.0);
+ * 
+ * set_tween_state(PART:"button", 0.5, "default", 0.0, "clicked", 0.0);
+ * 
+ * run_program(PROGRAM:"program_name");
+ */
+native       emit             (sig[], src[]);
+native       set_state        (part_id, state[], Float:state_val);
+native       get_state        (part_id, dst[], maxlen, &Float:val);
+native       set_tween_state  (part_id, Float:tween, state1[], Float:state1_val, state2[], Float:state2_val);
+native       run_program      (program_id);
+native       get_drag_dir     (part_id);
+native       get_drag         (part_id, &Float:dx, &Float:dy);
+native       set_drag         (part_id, Float:dx, Float:dy);
+native       get_drag_size    (part_id, &Float:dx, &Float:dy);
+native       set_drag_size    (part_id, Float:dx, Float:dy);
+native       get_drag_step    (part_id, &Float:dx, &Float:dy);
+native       set_drag_step    (part_id, Float:dx, Float:dy);
+native       get_drag_page    (part_id, &Float:dx, &Float:dy);
+native       set_drag_page    (part_id, Float:dx, Float:dy);
+native       set_text         (part_id, str[]);
+native       get_text         (part_id, dst[], maxlen);
+native       get_min_size     (&w, &h);
+native       get_max_size     (&w, &h);
+native       get_color_class  (class[], &r, &g, &b, &a);
+native       set_color_class  (class[], r, g, b, a);
+native       set_text_class   (class[], font[], Float:size);
+native       get_text_class   (class[], font[], &Float:size);
+native       get_geometry     (part_id, &x, &y, &w, &h);
+native       get_mouse        (&x, &y);
+native       get_mouse_buttons();
+native       stop_program     (program_id);
+native       stop_programs_on (part_id);
+native       set_min_size     (Float:w, Float:h);
+native       set_max_size     (Float:w, Float:h);
+native       part_swallow     (part_id, GROUP:str[]);
+
+native       external_param_get_int(id, param_name[]);
+native       external_param_set_int(id, param_name[], value);
+native Float:external_param_get_float(id, param_name[]);
+native       external_param_set_float(id, param_name[], Float:value);
+native       external_param_get_strlen(id, param_name[]);
+native       external_param_get_str(id, param_name[], value[], value_maxlen);
+native       external_param_set_str(id, param_name[], value[]);
+native       external_param_get_choice_len(id, param_name[]);
+native       external_param_get_choice(id, param_name[], value[], value_maxlen);
+native       external_param_set_choice(id, param_name[], value[]);
+native       external_param_get_bool(id, param_name[]);
+native       external_param_set_bool(id, param_name[], value);
+
+enum Msg_Type
+{
+   MSG_NONE = 0,
+     MSG_STRING = 2,
+     MSG_INT = 3,
+     MSG_FLOAT = 4,
+     MSG_STRING_SET = 5,
+     MSG_INT_SET = 6,
+     MSG_FLOAT_SET = 7,
+     MSG_STRING_INT = 8,
+     MSG_STRING_FLOAT = 9,
+     MSG_STRING_INT_SET = 10,
+     MSG_STRING_FLOAT_SET = 11
+};
+
+native send_message(Msg_Type:type, id, ...);
+
+/**********************/
+/* Custom state calls */
+/**********************/
+
+/* Example:
+ *
+ * Create the custom state for "my_part", based on the
+ * default description of the same part:
+ *
+ * custom_state(PART:"my_part", "default", 0.0);
+ *
+ * Later, use set_state_val() to change the properties of the custom
+ * state:
+ *
+ * set_state_val(PART:"my_part", STATE_ALIGNMENT, 0.5, 0.5);
+ *
+ * get_state_val() works the same way.
+ */
+
+native custom_state(part_id, state[], Float:state_val = 0.0);
+
+enum State_Param
+{
+       STATE_ALIGNMENT = 1,
+       STATE_MIN = 2,
+       STATE_MAX = 3,
+       STATE_STEP = 4,
+       STATE_ASPECT = 5,
+       STATE_ASPECT_PREF = 6,
+       STATE_COLOR = 7,
+       STATE_COLOR2 = 8,
+       STATE_COLOR3 = 9,
+       STATE_COLOR_CLASS = 10,
+       STATE_REL1 = 11,
+       STATE_REL1_TO = 12,
+       STATE_REL1_OFFSET = 13,
+       STATE_REL2 = 14,
+       STATE_REL2_TO = 15,
+       STATE_REL2_OFFSET = 16,
+       STATE_IMAGE = 17,
+       STATE_BORDER = 18,
+       STATE_FILL_SMOOTH = 19,
+       STATE_FILL_POS = 20,
+       STATE_FILL_SIZE = 21,
+       STATE_TEXT = 22,
+       STATE_TEXT_CLASS = 23,
+       STATE_TEXT_FONT = 24,
+       STATE_TEXT_STYLE = 25,
+       STATE_TEXT_SIZE = 26,
+       STATE_TEXT_FIT = 27,
+       STATE_TEXT_MIN = 28,
+       STATE_TEXT_MAX = 29,
+       STATE_TEXT_ALIGN = 30,
+       STATE_VISIBLE = 31,
+       STATE_MAP_ON = 32,
+       STATE_MAP_PERSP = 33,
+       STATE_MAP_LIGHT = 34,
+       STATE_MAP_ROT_CENTER = 35,
+       STATE_MAP_ROT_X = 36,
+       STATE_MAP_ROT_Y = 37,
+       STATE_MAP_ROT_Z = 38,
+       STATE_MAP_BACK_CULL = 39,
+       STATE_MAP_PERSP_ON = 40,
+       STATE_PERSP_ZPLANE = 41,
+       STATE_PERSP_FOCAL = 42
+};
+
+native set_state_val(part_id, State_Param:p, ...);
+native get_state_val(part_id, State_Param:p, ...);
diff --git a/debian/SVN_REV b/debian/SVN_REV
new file mode 100644 (file)
index 0000000..9f5204d
--- /dev/null
@@ -0,0 +1,2 @@
+Revision 48959
+Last Changed Rev 48676
diff --git a/debian/_original/changelog b/debian/_original/changelog
new file mode 100644 (file)
index 0000000..c19acbf
--- /dev/null
@@ -0,0 +1,11 @@
+edje (0.9.92.060+svnYYYYMMDD-1) unstable; urgency=low
+
+  * Updated version
+
+ -- quaker <quaker66@gmail.com>  Thu, 22 Apr 2009 18:18:23 +0100
+
+edje (0.9.9.050+svnYYYYMMDD-1) unstable; urgency=low
+
+  * Clean up changelog
+
+ -- quaker <quaker66@gmail.com>  Tue, 21 Apr 2009 19:15:44 +0100
diff --git a/debian/_original/compat b/debian/_original/compat
new file mode 100644 (file)
index 0000000..1e8b314
--- /dev/null
@@ -0,0 +1 @@
+6
diff --git a/debian/_original/control b/debian/_original/control
new file mode 100644 (file)
index 0000000..110d95a
--- /dev/null
@@ -0,0 +1,72 @@
+Source: edje
+Section: libs
+Priority: optional
+Maintainer: Debian Pkg-e Team <pkg-e-devel@lists.alioth.debian.org>
+Uploaders: Albin Tonnerre <albin.tonnerre@gmail.com>,
+ Xavier Oswald <x.oswald@free.fr>, Jan Lübbe <jluebbe@debian.org>
+Build-Depends: debhelper (>= 6), cdbs, quilt, libeet-dev, libevas-dev (>= 0.9.9.060+svnYYYYMMDD),
+ libecore-dev (>= 0.9.9.060+svnYYYYMMDD), libembryo-dev, libeina-dev (>= 0.0.2.060+svnYYYYMMDD),
+ doxygen, pkg-config, libtool
+Standards-Version: 3.8.1
+Homepage: http://enlightenment.org
+
+Package: libedje-bin
+Architecture: any
+Section: devel
+Depends: ${misc:Depends}, ${shlibs:Depends}, libembryo-bin (>= 0.9.9.060+svnYYYYMMDD), libevas-engines
+Description: Various binaries for use with libedje
+ Edje is a graphical layout and animation library for animated resizable,
+ compressed and scalable themes. It is the theming engine behind
+ Enlightenment DR 0.17.
+ .
+ This package contains the following binaries:
+  - edje_cc: Compiles EDC files.
+  - edje_decc: Used to decompile compiled edje files.
+  - edje_recc: A convenience script to recompile EDC files.
+
+Package: libedje-svn-01
+Architecture: any
+Depends: ${misc:Depends}, ${shlibs:Depends}
+Suggests: libedje-bin (= ${binary:Version})
+Description: Graphical layout and animation library
+ Edje is a graphical layout and animation library for animated resizable,
+ compressed and scalable themes. It is the theming engine behind
+ Enlightenment DR 0.17.
+
+Package: libedje-doc
+Architecture: all
+Section: doc
+Depends: ${misc:Depends}
+Enhances: libedje-dev
+Description: libedje0 development documentation
+ Edje is a graphical layout and animation library for animated resizable,
+ compressed and scalable themes. It is the theming engine behind
+ Enlightenment DR 0.17.
+ .
+ This package provides development documentation for Edje.
+
+Package: libedje-dev
+Architecture: any
+Section: libdevel
+Depends: ${misc:Depends}, libedje-svn-01 (= ${binary:Version}), libeet-dev, libembryo-dev, libevas-dev (>= 0.9.9.060+svnYYYYMMDD), libecore-dev (>= 0.9.9.060+svnYYYYMMDD), libeina-dev (>= 0.0.2.060+svnYYYYMMDD), pkg-config, libedje-bin
+Description: libedje headers and static libraries
+ Edje is a graphical layout and animation library for animated resizable,
+ compressed and scalable themes. It is the theming engine behind
+ Enlightenment DR 0.17.
+ .
+ This package provides headers and static libraries for Edje.
+
+Package: libedje-dbg
+Architecture: any
+Section: debug
+Priority: extra
+Depends: ${misc:Depends}, libedje-svn-01 (= ${binary:Version})
+Description: Debugging symbols for libedje
+ Edje is a graphical layout and animation library for animated resizable,
+ compressed and scalable themes. It is the theming engine behind
+ Enlightenment DR 0.17.
+ .
+ This package contains unstripped shared libraries. It is provided primarily
+ to provide a backtrace with names in a debugger, this makes it somewhat
+ easier to interpret core dumps. The libraries are installed in
+ /usr/lib/debug and are automatically used by gdb.
diff --git a/debian/_original/copyright b/debian/_original/copyright
new file mode 100644 (file)
index 0000000..b2ee88d
--- /dev/null
@@ -0,0 +1,42 @@
+This package was downloaded from: http://download.enlightenment.org/snapshots/
+
+This package was debianized by Laurence J. Lane <ljlane@debian.org> on
+ Sat, 28 Oct 2000 17:56:46 -0400.
+
+Files: *
+Copyright: Â© 2000 Carsten Haitzler and various contributors (see AUTHORS)
+License: BSD-3
+  Permission is hereby granted, free of charge, to any person obtaining a copy
+  of this software and associated documentation files (the "Software"), to
+  deal in the Software without restriction, including without limitation the
+  rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+  sell copies of the Software, and to permit persons to whom the Software is
+  furnished to do so, subject to the following conditions:
+  .
+  The above copyright notice and this permission notice shall be included in
+  .
+  materials, and acknowledgment shall be given in the documentation, materials
+  and software packages that this Software was used.
+  .
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+  .
+  IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 
+
+Files: data/edje-mode.el
+Copyright: Â© 2007 Gustavo Sverzut Barbieri <barbieri@gmail.com>
+License: GPL-2+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of
+ the License, or (at your option) any later version.
+
+Files: debian/*
+Copyright: Â© 2006-2008 Debian Pkg-e Team <pkg-e-devel@lists.alioth.debian.org>
+License: GPL-2+
+ The Debian packaging information is under the GPL, version 2 or later
+
+On Debian GNU/Linux systems, the complete text of the GNU General
+Public License (version 2) can be found in `/usr/share/common-licenses/GPL-2'.
diff --git a/debian/_original/edje_cc.1 b/debian/_original/edje_cc.1
new file mode 100644 (file)
index 0000000..b02fa89
--- /dev/null
@@ -0,0 +1,47 @@
+.TH EDJE_CC 1 "Jan 29, 2007" "0.5.0.042" "The edje compiler"
+.SH NAME
+edje_cc - an edje compiler
+.SH SYNOPSIS
+.B edje_cc
+.RI [\| OPTIONS \|]
+.B input_file.edc
+.RI [\| output_file.edj \|]
+.SH DESCRIPTION
+edje_cc is a compiler for edje files
+.SH EXAMPLES
+edje_cc \-v file.edc
+.SH OPTIONS
+.BI \-id " \|image/directory
+Add a directory to look in for relative path images
+.P
+.BI \-fd " \|font/directory
+Add a directory to look in for relative path fonts
+.P
+.B \-v
+Verbose output
+.P
+.B \-no\-lossy
+Do NOT allow images to be lossy
+.P
+.B \-no\-comp
+Do NOT allow images to be stored with lossless compression
+.P
+.B \-no\-raw
+Do NOT allow images to be stored with zero compression (raw)
+.P
+.BI \-min\-quality " \|VAL
+Do NOT allow lossy images with quality < VAL (0-100)
+.P
+.BI \-max\-quality " \|VAL
+Do NOT allow lossy images with quality > VAL (0-100)
+.P
+.BI \-Ddefine_val= " \|to
+CPP style define to define input macro definitions to the .edc source
+.SH SEE ALSO
+edje_decc(1)
+.BR
+edje_recc(1)
+.SH BUGS
+Please reports bugs to the Pkg-E Team <pkg-e-devel@lists.alioth.debian.org>
+.SH AUTHOR
+This man page was written by Ronald Claveau for the Debian GNU/Linux system (but may  be  used by others).
diff --git a/debian/_original/edje_decc.1 b/debian/_original/edje_decc.1
new file mode 100644 (file)
index 0000000..d79785a
--- /dev/null
@@ -0,0 +1,16 @@
+.TH EDJE_DECC 1 "Jan 30, 2007" "0.5.0.042" "The edje decompiler"
+.SH NAME
+edje_decc \- an edje decompiler
+.SH SYNOPSIS
+.B edje_decc
+.B input_file.edj
+.SH DESCRIPTION
+edje_decc is a decompiler for edje files.
+.SH SEE ALSO
+edje_cc(1)
+.BR
+edje_recc(1)
+.SH BUGS
+Please reports bugs to the Pkg-E Team <pkg-e-devel@lists.alioth.debian.org>
+.SH AUTHOR
+This man page was written by Ronald Claveau for the Debian GNU/Linux system (but may  be  used by others).
diff --git a/debian/_original/edje_recc.1 b/debian/_original/edje_recc.1
new file mode 100644 (file)
index 0000000..71f4a52
--- /dev/null
@@ -0,0 +1,37 @@
+.TH EDJE_RECC 1 "Jan 30, 2007" "0.5.0.042" "The edje recompiler"
+.SH NAME
+edje_recc - an edje recompiler
+.SH SYNOPSIS
+.B edje_recc
+.RI [\| OPTIONS \|]
+.B input_file.edj
+.SH DESCRIPTION
+edje_recc is a recompiler for edje files.
+.SH EXAMPLES
+edje_recc \-v file.edj
+.SH OPTIONS
+.B \-v
+Verbose output
+.P
+.B \-no\-lossy
+Do NOT allow images to be lossy
+.P
+.B \-no\-comp
+Do NOT allow images to be stored with lossless compression
+.P
+.B \-no\-raw
+Do NOT allow images to be stored with zero compression (raw)
+.P
+.BI \-min\-quality " \|VAL
+Do NOT allow lossy images with quality < VAL (0-100)
+.P
+.BI \-max\-quality " \|VAL
+Do NOT allow lossy images with quality > VAL (0-100)
+.SH SEE ALSO
+edje_cc(1)
+.BR
+edje_decc(1)
+.SH BUGS
+Please reports bugs to the Pkg-E Team <pkg-e-devel@lists.alioth.debian.org>
+.SH AUTHOR
+This man page was written by Ronald Claveau for the Debian GNU/Linux system (but may  be  used by others).
diff --git a/debian/_original/libedje-bin.install b/debian/_original/libedje-bin.install
new file mode 100644 (file)
index 0000000..8f5682f
--- /dev/null
@@ -0,0 +1,4 @@
+debian/tmp/usr/bin/edje_cc
+debian/tmp/usr/bin/edje_decc
+debian/tmp/usr/bin/edje_recc
+debian/tmp/usr/share/edje/include/edje.inc
diff --git a/debian/_original/libedje-bin.manpages b/debian/_original/libedje-bin.manpages
new file mode 100644 (file)
index 0000000..e2b8466
--- /dev/null
@@ -0,0 +1 @@
+debian/edje_*.1
diff --git a/debian/_original/libedje-dev.install b/debian/_original/libedje-dev.install
new file mode 100644 (file)
index 0000000..4ce6cc8
--- /dev/null
@@ -0,0 +1,4 @@
+debian/tmp/usr/include/*
+debian/tmp/usr/lib/lib*.a
+debian/tmp/usr/lib/libedje.so
+debian/tmp/usr/lib/pkgconfig/*
diff --git a/debian/_original/libedje-doc.dirs b/debian/_original/libedje-doc.dirs
new file mode 100644 (file)
index 0000000..419b09b
--- /dev/null
@@ -0,0 +1 @@
+usr/share/doc/libedje-doc
diff --git a/debian/_original/libedje-doc.doc-base b/debian/_original/libedje-doc.doc-base
new file mode 100644 (file)
index 0000000..5e51436
--- /dev/null
@@ -0,0 +1,10 @@
+Document: edje
+Title: Edje Guide
+Author: Carsten Haitzler
+Abstract: This document describes Edje API
+ and provides sample C code.
+Section: Programming/C
+
+Format: HTML
+Index: /usr/share/doc/libedje-doc/html/index.html
+Files: /usr/share/doc/libedje-doc/html/*.html
diff --git a/debian/_original/libedje-svn-01.install b/debian/_original/libedje-svn-01.install
new file mode 100644 (file)
index 0000000..d51c2c3
--- /dev/null
@@ -0,0 +1 @@
+debian/tmp/usr/lib/libedje-*.so.*
diff --git a/debian/_original/libedje-svn-01.shlibs b/debian/_original/libedje-svn-01.shlibs
new file mode 100644 (file)
index 0000000..9cc2416
--- /dev/null
@@ -0,0 +1 @@
+libedje-ver-pre-svn-01 0 libedje-svn-01 (>= 0.9.9.060+svnYYYYMMDD)
diff --git a/debian/_original/rules b/debian/_original/rules
new file mode 100755 (executable)
index 0000000..f8ce80c
--- /dev/null
@@ -0,0 +1,24 @@
+#!/usr/bin/make -f
+
+include /usr/share/cdbs/1/class/autotools.mk
+include /usr/share/cdbs/1/rules/debhelper.mk
+
+DEB_CONFIGURE_SCRIPT := ./autogen.sh
+DEB_MAKE_CLEAN_TARGET := distclean
+DEB_DH_STRIP_ARGS := --dbg-package=libedje-dbg
+DEB_CONFIGURE_EXTRA_FLAGS := --disable-rpath --enable-doc
+DEB_SOURCE_VERSION := $(shell grep AC_INIT $(DEB_SRCDIR)/configure.ac | cut -d, -f2 | tr -d ' []')
+CFLAGS += -fvisibility=hidden -ffast-math
+LDFLAGS += -fvisibility=hidden
+
+build/libedje-doc::
+       cd $(DEB_SRCDIR)/doc && make doc
+
+install/libedje-doc::
+       tar jxf edje-*-doc.tar.bz2 -C $(DEB_SRCDIR)
+       cp -R $(DEB_SRCDIR)/edje-$(DEB_SOURCE_VERSION)-doc/doc/html debian/libedje-doc/usr/share/doc/libedje-doc/
+       rm -rf $(DEB_SRCDIR)/edje-$(DEB_SOURCE_VERSION)-doc/
+
+clean::
+       [ ! -f Makefile ] || make distclean
+       rm -f edje-*.tar.bz2 edje-*.tar.bz2.cdbs-config_list
diff --git a/doc/.cvsignore b/doc/.cvsignore
new file mode 100644 (file)
index 0000000..cc370ed
--- /dev/null
@@ -0,0 +1,3 @@
+html
+latex
+man
diff --git a/doc/Doxyfile b/doc/Doxyfile
new file mode 100644 (file)
index 0000000..2cd7cc9
--- /dev/null
@@ -0,0 +1,1532 @@
+# Doxyfile 1.6.1
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+#       TAG = value [value, ...]
+# For lists items can also be appended using:
+#       TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the
+# iconv built into libc) for the transcoding. See
+# http://www.gnu.org/software/libiconv for the list of possible encodings.
+
+DOXYFILE_ENCODING      = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
+# by quotes) that should identify the project.
+
+PROJECT_NAME           = Edje
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER         =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       = .
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
+# 4096 sub-directories (in 2 levels) under the output directory of each output
+# format and will distribute the generated files over these directories.
+# Enabling this option can be useful when feeding doxygen a huge amount of
+# source files, where putting all generated files in the same directory would
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS         = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
+# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German,
+# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English
+# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian,
+# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak,
+# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.
+
+OUTPUT_LANGUAGE        = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF           = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator
+# that is used to form the text in various listings. Each string
+# in this list, if found as the leading text of the brief description, will be
+# stripped from the text and the result after processing the whole list, is
+# used as the annotated text. Otherwise, the brief description is used as-is.
+# If left blank, the following values are used ("$name" is automatically
+# replaced with the name of the entity): "The $name class" "The $name widget"
+# "The $name file" "is" "provides" "specifies" "contains"
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF       =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES        = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the
+# path to strip.
+
+STRIP_FROM_PATH        =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
+# the path mentioned in the documentation of a class, which tells
+# the reader which header file to include in order to use a class.
+# If left blank only the name of the header file containing the class
+# definition is used. Otherwise one should specify the include paths that
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH    =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful is your file systems
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like regular Qt-style comments
+# (thus requiring an explicit @brief command for a brief description.)
+
+JAVADOC_AUTOBRIEF      = YES
+
+# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
+# interpret the first line (until the first dot) of a Qt-style
+# comment as the brief description. If set to NO, the comments
+# will behave just like regular Qt-style comments (thus requiring
+# an explicit \brief command for a brief description.)
+
+QT_AUTOBRIEF           = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# re-implements.
+
+INHERIT_DOCS           = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
+# a new page for each member. If set to NO, the documentation of a member will
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES  = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE               = 8
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+# Aliases used by edcref
+ALIASES                = block="<tr><td class=\"block\"><b>"
+ALIASES               += context="</b></td><td class=\"context\" colspan=2>\code"
+ALIASES               += description="\endcode</td></tr><tr><td>&nbsp;</td><td class=\"description\" colspan=2>"
+ALIASES               += endblock="</td></tr>"
+ALIASES               += property="<tr><td>&nbsp;</td><td><table class=\"edcref\" border=\"0\"><tr><td class=\"property\"><tt>"
+ALIASES               += parameters="</tt></td><td class=\"parameters\"><tt>"
+ALIASES               += effect="</tt></td></tr><tr><td>&nbsp;</td><td class=\"effect\">"
+ALIASES               += endproperty="</td></tr></table></td></tr>"
+ALIASES               += edcsection{2}="<tr class=\"section\"><td class=\"section\" colspan=\"2\">\anchor sec_\1 \ref sec_quickaccess \"\2\"</td></tr>"
+
+# Aliases used by luaref
+ALIASES               += luaclass{2}="\anchor \1 \n<div class=\"luaclass\">\2</div>"
+ALIASES               += attributes="<div class=\"luaattrib\">Attributes:</div>"
+ALIASES               += methods="<div class=\"luaattrib\">Methods:</div>"
+ALIASES               += events="<div class=\"luaattrib\">Events:</div>"
+ALIASES               += setters="<div class=\"luaattrib\">Setters:</div>"
+ALIASES               += seealso{2}="<b>See also:</b> <a href='\2'>\1</a>\n"
+ALIASES               += seealso{1}="<b>See also:</b> \1\n"
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
+# sources only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C  = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
+# sources only. Doxygen will then generate output that is more tailored for
+# Java. For instance, namespaces will be presented as packages, qualified
+# scopes will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA   = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources only. Doxygen will then generate output that is more tailored for
+# Fortran.
+
+OPTIMIZE_FOR_FORTRAN   = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for
+# VHDL.
+
+OPTIMIZE_OUTPUT_VHDL   = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it parses.
+# With this tag you can assign which parser to use for a given extension.
+# Doxygen has a built-in mapping, but you can override or extend it using this tag.
+# The format is ext=language, where ext is a file extension, and language is one of
+# the parsers supported by doxygen: IDL, Java, Javascript, C#, C, C++, D, PHP,
+# Objective-C, Python, Fortran, VHDL, C, C++. For instance to make doxygen treat
+# .inc files as Fortran files (default is PHP), and .f files as C (default is Fortran),
+# use: inc=Fortran f=C. Note that for custom extensions you also need to set FILE_PATTERNS otherwise the files are not read by doxygen.
+
+EXTENSION_MAPPING      =
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should
+# set this tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
+# func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT    = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+
+CPP_CLI_SUPPORT        = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.
+# Doxygen will parse them like normal C++ but will assume all classes use public
+# instead of private inheritance when no explicit protection keyword is present.
+
+SIP_SUPPORT            = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate getter
+# and setter methods for a property. Setting this option to YES (the default)
+# will make doxygen to replace the get and set methods by a property in the
+# documentation. This will only work if the methods are indeed getting or
+# setting a simple type. If this is not the case, or you want to show the
+# methods anyway, you should set this option to NO.
+
+IDL_PROPERTY_SUPPORT   = NO
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
+# the \nosubgrouping command.
+
+SUBGROUPING            = YES
+
+# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum
+# is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically
+# be useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+
+TYPEDEF_HIDES_STRUCT   = NO
+
+# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to
+# determine which symbols to keep in memory and which to flush to disk.
+# When the cache is full, less often used symbols will be written to disk.
+# For small to medium size projects (<1000 input files) the default value is
+# probably good enough. For larger projects a too small cache size can cause
+# doxygen to be busy swapping symbols to and from disk most of the time
+# causing a significant performance penality.
+# If the system has enough physical memory increasing the cache will improve the
+# performance by keeping more symbols in memory. Note that the value works on
+# a logarithmic scale so increasing the size by one will rougly double the
+# memory usage. The cache size is given by this formula:
+# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0,
+# corresponding to a cache size of 2^16 = 65536 symbols
+
+SYMBOL_CACHE_SIZE      = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL            = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC         = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES  = YES
+
+# This flag is only useful for Objective-C code. When set to YES local
+# methods, which are defined in the implementation section but not in
+# the interface are included in the documentation.
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS  = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base
+# name of the file that contains the anonymous namespace. By default
+# anonymous namespace are hidden.
+
+EXTRACT_ANON_NSPACES   = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS     = YES
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES     = YES
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS  = YES
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS      = YES
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS          = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES       = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES     = NO
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS       = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
+# declaration order.
+
+SORT_BRIEF_DOCS        = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the (brief and detailed) documentation of class members so that constructors and destructors are listed first. If set to NO (the default) the constructors will appear in the respective orders defined by SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the
+# hierarchy of group names into alphabetical order. If set to NO (the default)
+# the group names will appear in their defined order.
+
+SORT_GROUP_NAMES       = YES
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
+# sorted by fully-qualified names, including namespaces. If set to
+# NO (the default), the class list will be sorted only by class name,
+# not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME     = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST      = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST       = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS       =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or define consists of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and defines in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES        = NO
+
+# If the sources in your project are distributed over multiple directories
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
+# in the documentation. The default is NO.
+
+SHOW_DIRECTORIES       = NO
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
+# This will remove the Files entry from the Quick Index and from the
+# Folder Tree View (if specified). The default is YES.
+
+SHOW_FILES             = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the
+# Namespaces page.
+# This will remove the Namespaces entry from the Quick Index
+# and from the Folder Tree View (if specified). The default is YES.
+
+SHOW_NAMESPACES        = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command <command> <input-file>, where <command> is the value of
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
+# provided by doxygen. Whatever the program writes to standard output
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER    =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by
+# doxygen. The layout file controls the global structure of the generated output files
+# in an output format independent way. The create the layout file that represents
+# doxygen's defaults, run doxygen with the -l option. You can optionally specify a
+# file name after the option, if omitted DoxygenLayout.xml will be used as the name
+# of the layout file.
+
+LAYOUT_FILE            =
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET                  = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS               = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR      = YES
+
+# This WARN_NO_PARAMDOC option can be abled to get warnings for
+# functions that are documented, but have no documentation for their parameters
+# or return value. If set to NO (the default) doxygen will only warn about
+# wrong or incomplete parameter documentation, but not about the absence of
+# documentation.
+
+WARN_NO_PARAMDOC       = YES
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text. Optionally the format may contain
+# $version, which will be replaced by the version of the file (if it could
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE           =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT                  = edje.dox ../src/bin/edje_cc_handlers.c ../src/lib
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
+# also the default input encoding. Doxygen uses libiconv (or the iconv built
+# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for
+# the list of possible encodings.
+
+INPUT_ENCODING         = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx
+# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90
+
+FILE_PATTERNS          =
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE              = NO
+
+# The EXCLUDE tag can be used to specify files and/or directories that should
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE                =
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
+# directories that are symbolic links (a Unix filesystem feature) are excluded
+# from the input.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories. Note that the wildcards are matched
+# against the file with absolute path, so to exclude all test directories
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS       =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+
+EXCLUDE_SYMBOLS        =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH           = examples/
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS       =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH             = img
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output.
+# If FILTER_PATTERNS is specified, this tag will be
+# ignored.
+
+INPUT_FILTER           =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis.
+# Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match.
+# The filters are a list of the form:
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
+# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER
+# is applied to all files.
+
+FILTER_PATTERNS        =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES    = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+# Note: To get rid of all source code in the generated output, make sure also
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER         = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES         = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS    = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION    = YES
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
+# link to the source code.
+# Otherwise they will link to the documentation.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code
+# will point to the HTML generated by the htags(1) tool instead of doxygen
+# built-in source browser. The htags tool is part of GNU's global source
+# tagging system (see http://www.gnu.org/software/global/global.html). You
+# will need version 4.8.6 or higher.
+
+USE_HTAGS              = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS       = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX     = YES
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX    = 2
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX          =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML          = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT            = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header.
+
+HTML_HEADER            = head.html
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER            = foot.html
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If the tag is left blank doxygen
+# will generate a default style sheet. Note that doxygen will try to copy
+# the style sheet file to the HTML output directory, so don't put your own
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET        = e.css
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
+# files or namespaces will be aligned in HTML using tables. If set to
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS     = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded. For this to work a browser that supports
+# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox
+# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
+
+HTML_DYNAMIC_SECTIONS  = NO
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files
+# will be generated that can be used as input for Apple's Xcode 3
+# integrated development environment, introduced with OSX 10.5 (Leopard).
+# To create a documentation set, doxygen will generate a Makefile in the
+# HTML output directory. Running make will produce the docset in that
+# directory and running "make install" will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
+# it at startup.
+# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information.
+
+GENERATE_DOCSET        = NO
+
+# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the
+# feed. A documentation feed provides an umbrella under which multiple
+# documentation sets from a single provider (such as a company or product suite)
+# can be grouped.
+
+DOCSET_FEEDNAME        = "Doxygen generated docs"
+
+# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that
+# should uniquely identify the documentation set bundle. This should be a
+# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen
+# will append .docset to the name.
+
+DOCSET_BUNDLE_ID       = org.enlightenment.Edje
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP      = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output directory.
+
+CHM_FILE               =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION           =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI           = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
+# is used to encode HtmlHelp index (hhk), content (hhc) and project file
+# content.
+
+CHM_INDEX_ENCODING     =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND             = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER
+# are set, an additional index file will be generated that can be used as input for
+# Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated
+# HTML documentation.
+
+GENERATE_QHP           = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can
+# be used to specify the file name of the resulting .qch file.
+# The path specified is relative to the HTML output folder.
+
+QCH_FILE               =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#namespace
+
+QHP_NAMESPACE          =
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#virtual-folders
+
+QHP_VIRTUAL_FOLDER     = doc
+
+# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to add.
+# For more information please see
+# http://doc.trolltech.com/qthelpproject.html#custom-filters
+
+QHP_CUST_FILTER_NAME   =
+
+# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the custom filter to add.For more information please see
+# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">Qt Help Project / Custom Filters</a>.
+
+QHP_CUST_FILTER_ATTRS  =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this project's
+# filter section matches.
+# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">Qt Help Project / Filter Attributes</a>.
+
+QHP_SECT_FILTER_ATTRS  =
+
+# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can
+# be used to specify the location of Qt's qhelpgenerator.
+# If non-empty doxygen will try to run qhelpgenerator on the generated
+# .qhp file.
+
+QHG_LOCATION           =
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
+# top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it.
+
+DISABLE_INDEX          = YES
+
+# This tag can be used to set the number of enum values (range [1..20])
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE   = 1
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information.
+# If the tag value is set to YES, a side panel will be generated
+# containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser).
+# Windows users are probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW      = NO
+
+# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories,
+# and Class Hierarchy pages using a tree view instead of an ordered list.
+
+USE_INLINE_TREES       = NO
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH         = 250
+
+# Use this tag to change the font size of Latex formulas included
+# as images in the HTML documentation. The default is 10. Note that
+# when you change the font size after a successful doxygen run you need
+# to manually remove any form_*.png images from the HTML output directory
+# to force them to be regenerated.
+
+FORMULA_FONTSIZE       = 10
+
+# When the SEARCHENGINE tag is enable doxygen will generate a search box for the HTML output. The underlying search engine uses javascript
+# and DHTML and should work on any modern browser. Note that when using HTML help (GENERATE_HTMLHELP) or Qt help (GENERATE_QHP)
+# there is already a search function so this one should typically
+# be disabled.
+
+SEARCHENGINE           = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX         = YES
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT           = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, a4wide, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE             = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES         =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER           =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS         = YES
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX           = NO
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE        = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+LATEX_HIDE_INDICES     = NO
+
+# If LATEX_SOURCE_CODE is set to YES then doxygen will include source code with syntax highlighting in the LaTeX output. Note that which sources are shown also depends on other settings such as SOURCE_BROWSER.
+
+LATEX_SOURCE_CODE      = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimized for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS         = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE    =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE    =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN           = YES
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION          = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS              = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation.
+
+GENERATE_XML           = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT             = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA             =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD                =
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
+# dump the program listings (including syntax highlighting
+# and cross-referencing information) to the XML output. Note that
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING     = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader.
+# This is useful
+# if you want to understand what is going on.
+# On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION        = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF     = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES        = NO
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH           =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS  =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed. To prevent a macro definition from being
+# undefined via #undef or recursively expanded use the := operator
+# instead of the = operator.
+
+PREDEFINED             =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED      =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all function-like macros that are alone
+# on a line, have an all uppercase name, and do not end with a semicolon. Such
+# function macros are typically used for boiler-plate code, and will confuse
+# the parser if not removed.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles.
+# Optionally an initial location of the external documentation
+# can be added for each tagfile. The format of a tag file without
+# this location is as follows:
+#
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+#
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths or
+# URLs. If a location is present for each tag, the installdox tool
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES               =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE       =
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS        = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
+# or super classes. Setting the tag to NO turns the diagrams off. Note that
+# this option is superseded by the HAVE_DOT option below. This is only a
+# fallback. It is recommended to install and use dot, since it yields more
+# powerful graphs.
+
+CLASS_DIAGRAMS         = NO
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see
+# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH            =
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS   = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT               = NO
+
+# By default doxygen will write a font called FreeSans.ttf to the output
+# directory and reference it in all dot files that doxygen generates. This
+# font does not include all possible unicode characters however, so when you need
+# these (or just want a differently looking font) you can specify the font name
+# using DOT_FONTNAME. You need need to make sure dot is able to find the font,
+# which can be done by putting it in a standard location or by setting the
+# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory
+# containing the font.
+
+DOT_FONTNAME           = FreeSans
+
+# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.
+# The default size is 10pt.
+
+DOT_FONTSIZE           = 10
+
+# By default doxygen will tell dot to use the output directory to look for the
+# FreeSans.ttf font (which doxygen will put there itself). If you specify a
+# different font using DOT_FONTNAME you can set the path where dot
+# can find it using this tag.
+
+DOT_FONTPATH           =
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH    = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS           = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+
+UML_LOOK               = NO
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS     = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH          = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH and HAVE_DOT options are set to YES then
+# doxygen will generate a call dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable call graphs
+# for selected functions only using the \callgraph command.
+
+CALL_GRAPH             = NO
+
+# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
+# doxygen will generate a caller dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable caller
+# graphs for selected functions only using the \callergraph command.
+
+CALLER_GRAPH           = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
+# then doxygen will show the dependencies a directory has on other directories
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH        = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT       = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH               =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS           =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
+# nodes that will be shown in the graph. If the number of nodes in a graph
+# becomes larger than this value, doxygen will truncate the graph, which is
+# visualized by representing a node as a red box. Note that doxygen if the
+# number of direct children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
+# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+
+DOT_GRAPH_MAX_NODES    = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
+# graphs generated by dot. A depth value of 3 means that only nodes reachable
+# from the root by following a path via at most 3 edges will be shown. Nodes
+# that lay further from the root node will be omitted. Note that setting this
+# option to 1 or 2 may greatly reduce the computation time needed for large
+# code bases. Also note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not
+# seem to support this out of the box. Warning: Depending on the platform used,
+# enabling this option may lead to badly anti-aliased labels on the edges of
+# a graph (i.e. they become hard to read).
+
+DOT_TRANSPARENT        = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10)
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS      = NO
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP            = YES
diff --git a/doc/Makefile.am b/doc/Makefile.am
new file mode 100644 (file)
index 0000000..45d97a8
--- /dev/null
@@ -0,0 +1,34 @@
+
+MAINTAINERCLEANFILES = Makefile.in edje.dox
+
+.PHONY: doc
+
+PACKAGE_DOCNAME = $(PACKAGE_TARNAME)-$(PACKAGE_VERSION)-doc
+
+if EFL_BUILD_DOC
+
+doc-clean:
+       rm -rf html/ latex/ man/ xml/ $(PACKAGE_DOCNAME).tar*
+
+doc: all doc-clean
+       $(efl_doxygen)
+       cp img/* html/
+       rm -rf $(PACKAGE_DOCNAME).tar*
+       mkdir -p $(PACKAGE_DOCNAME)/doc
+       cp -R html/ latex/ man/ $(PACKAGE_DOCNAME)/doc
+       tar cf $(PACKAGE_DOCNAME).tar $(PACKAGE_DOCNAME)/
+       bzip2 -9 $(PACKAGE_DOCNAME).tar
+       rm -rf $(PACKAGE_DOCNAME)/
+       mv $(PACKAGE_DOCNAME).tar.bz2 $(top_srcdir)
+
+clean-local: doc-clean
+
+else
+
+doc:
+       @echo "Documentation not built. Run ./configure --help"
+
+endif
+
+EXTRA_DIST = Doxyfile e.css foot.html head.html $(wildcard img/*.*) \
+             edje.dox.in $(wildcard examples/*.*)
diff --git a/doc/e.css b/doc/e.css
new file mode 100644 (file)
index 0000000..44a9f25
--- /dev/null
+++ b/doc/e.css
@@ -0,0 +1,295 @@
+/*
+    Author:
+        Andres Blanc <andresblanc@gmail.com>
+       DaveMDS Andreoli <dave@gurumeditation.it>
+
+    Supported Browsers:
+        ie7, opera9, konqueror4 and firefox3
+
+        Please use a different file for ie6, ie5, etc. hacks.
+*/
+
+
+/* Necessary to place the footer at the bottom of the page */
+html, body {
+       height: 100%;
+       margin: 0px;
+       padding: 0px;
+}
+
+#container {
+       min-height: 100%;
+       height: auto !important;
+       height: 100%;
+       margin: 0 auto -53px;
+}
+
+#footer, #push {
+       height: 53px;
+}
+
+
+* html #container {
+       height: 100%;
+}
+
+/* Prevent floating elements overflowing containers */
+.clear {
+       clear: both;
+       width: 0px;
+       height: 0px;
+}
+
+/* Flexible & centered layout from 750 to 960 pixels */
+.layout {
+       max-width: 960px;
+       min-width: 760px;
+       margin-left: auto;
+       margin-right: auto;
+}
+
+body {
+       /*font-family: Lucida Grande, Helvetica, sans-serif;*/
+       font-family: "Bitstream Vera","Vera","Trebuchet MS",Trebuchet,Tahoma,sans-serif
+}
+
+/* Prevent design overflowing the viewport in small resolutions */
+#container {
+       padding-right: 17px;
+       padding-left: 17px;
+       background-image: url(head_bg.png);
+       background-repeat: repeat-x;
+}
+
+/****************************/
+/* Top main menu            */
+/****************************/
+#header_logo {
+   background-image        : url(logo.png);
+   width                   : 61px;
+}
+
+#header_logo a {
+   position                : absolute;
+   border                  : 0px;
+   background-color        : transparent;
+   top                     : 0px;
+   width                   : 60px;
+   height                  : 60px;
+}
+
+#header_menu {
+   background-image        : url(header_menu_background.png);
+   font                    : normal 10pt verdana,'Bitstream Vera Sans',helvetica,arial,sans-serif;
+   text-align              : right;
+}
+
+#header_last {
+   background-image        : url(header_menu_background_last.png);
+   width                   : 15px;
+}
+
+td.nav_passive {
+   background              : url(header_menu_unselected_background.png) 0 0 no-repeat;
+   height                  : 63px;
+   font-family             : "Bitstream Vera","Vera","Trebuchet MS",Trebuchet,Tahoma,sans-serif;
+   font-size               : 11px;
+   padding                 : 20px 10px 20px 10px;
+   vertical-align          : middle;
+}
+
+td.nav_active {
+   background              : url(header_menu_current_background.png) 0 0 no-repeat;
+   height                  : 63px;
+   color                   : #646464;
+   font-family             : "Bitstream Vera","Vera","Trebuchet MS",Trebuchet,Tahoma,sans-serif;
+   font-size               : 11px;
+   font-weight             : bold;
+   padding                 : 20px 10px 20px 10px;
+   vertical-align          : middle;
+}
+
+#header_menu a {
+   display                 : block;
+   text-decoration         : none;
+   cursor                  : pointer;
+   color                   : #cdcdcd;
+}
+
+
+
+#header {
+       width: 100%;
+       height: 102px;
+}
+
+#header h1 {
+       width: 63px;
+       height: 63px;
+       position: absolute;
+       margin: 0px;
+}
+
+#header h1 span {
+       display: none;
+}
+
+#header h2 {
+       display: none;
+}
+
+/* .menu-container is used to set properties common to .menu and .submenu */
+#header .menu-container {
+}
+
+#header .menu-container ul {
+       list-style-type: none;
+       list-style-position: inside;
+       margin: 0;
+}
+
+#header .menu-container li {
+       display: block;
+       float: right;
+}
+
+#header .menu {
+       height: 63px;
+       display: block;
+       background-image: url(menu_bg.png);
+       background-repeat: repeat-x;
+}
+
+#header .menu ul {
+       height: 100%;
+       display: block;
+       background-image: url(menu_bg_last.png);
+       background-repeat: no-repeat;
+       background-position: top right;
+       padding-right: 17px;
+}
+
+#header .menu li {
+       height: 100%;
+       text-align: center;
+       background-image: url(menu_bg_unsel.png);
+       background-repeat: no-repeat;
+}
+
+#header .menu a {
+       height: 100%;
+       display: block;
+       color: #cdcdcd;
+       text-decoration: none;
+       font-size: 10pt;
+       line-height: 59px;
+       text-align: center;
+       padding: 0px 15px 0px 15px;
+}
+
+#header .menu li:hover {
+       background-image: url(menu_bg_hover.png);
+       background-repeat: no-repeat;
+}
+
+#header .menu li:hover a {
+       color: #FFFFFF;
+}
+
+#header .menu li.current {
+       background-image: url(menu_bg_current.png);
+       background-repeat: no-repeat;
+}
+
+#header .menu li.current a {
+       color: #646464;
+}
+
+
+/* Hide all the submenus but the current */
+#header .submenu ul {
+       display: none;
+}
+
+#header .submenu .current {
+       display: block;
+}
+
+#header .submenu {
+       font: bold 10px verdana,'Bitstream Vera Sans',helvetica,arial,sans-serif;
+       margin-top: 10px;
+}
+
+#header .submenu a {
+       color: #888888;
+       text-decoration: none;
+       font-size: 0.9em;
+       line-height: 15px;
+       padding:0px 5px 0px 5px;
+}
+
+#header .submenu a:hover {
+       color: #444444;
+}
+
+#header .submenu li {
+       border-left: 1px solid #DDDDDD;
+}
+
+#header .submenu li:last-child {
+       border-left: 0;
+}
+
+#header .doxytitle {
+       position: absolute;
+       font-size: 1.8em;
+       font-weight: bold;
+       color: #444444;
+       line-height: 35px;
+}
+
+#header small {
+       font-size: 0.4em;
+}
+
+#footer {
+       background-image: url(foot_bg.png);
+       width: 100%;
+}
+
+#footer table {
+       width: 100%;
+       text-align: center;
+       white-space: nowrap;
+       padding: 5px 30px 5px 30px;
+       font-size: 0.8em;
+       font-family: "Bitstream Vera","Vera","Trebuchet MS",Trebuchet,Tahoma,sans-serif;
+       color: #888888;
+}
+
+#footer td.copyright {
+       width: 100%;
+}
+
+table.edcref tr td.block {
+        vertical-align: top;
+        padding-top: 10px;
+}
+
+table.edcref tr.section td.section, div.luaclass {
+        color: #888;
+        font-size: 16pt;
+        padding: 15px;
+        border-top: 1px solid #ccc;
+        text-align: center;
+}
+
+table.edcref tr.section td.section a {
+        color: #888;
+        text-decoration: none;
+}
+
+div.luaattrib {
+        color: #888;
+        border: 1px solid #ccc;
+}
diff --git a/doc/edje.dox.in b/doc/edje.dox.in
new file mode 100644 (file)
index 0000000..8560104
--- /dev/null
@@ -0,0 +1,457 @@
+/** 
+@file edje.dox
+@brief Edje Graphical Design Library
+These routines are used for Edje.
+*/
+
+/**
+
+@mainpage Edje Library Documentation
+@image html  e.png
+@version @PACKAGE_VERSION@
+@author Carsten Haitzler <raster\@rasterman.com>
+@date 2003-2010
+
+
+
+
+
+
+
+
+
+
+@section intro What is Edje?
+
+Edje is a complex graphical design & layout library.
+
+It doesn't pretend to do containing and regular layout like a widget
+set, but it is the base for such components. Based on the requirements
+of Enlightenment 0.17, Edje should serve all the purposes of creating
+visual elements (borders of windows, buttons, scrollbars, etc.) and
+allow the designer the ability to animate, layout and control the look
+and feel of any program using Edje as its basic GUI constructor. This
+library allows for multiple collections of Layouts in one file,
+sharing the same image and font database and thus allowing a whole
+theme to be conveniently packaged into 1 file and shipped around.
+
+Edje separates the layout and behavior logic. Edje files ship with an
+image and font database, used by all the parts in all the collections
+to source graphical data. It has a directory of logical part names
+pointing to the part collection entry ID in the file (thus allowing
+for multiple logical names to point to the same part collection,
+allowing for the sharing of data between display elements). Each part
+collection consists of a list of visual parts, as well as a list of
+programs. A program is a conditionally run program that if a
+particular event occurs (a button is pressed, a mouse enters or leaves
+a part) will trigger an action that may affect other parts. In this
+way a part collection can be "programmed" via its file as to hilight
+buttons when the mouse passes over them or show hidden parts when a
+button is clicked somewhere etc. The actions performed in changing
+from one state to another are also allowed to transition over a period
+of time, allowing animation. Programs and animations can be run in
+"parallel".
+
+This separation and simplistic event driven style of programming can produce
+almost any look and feel one could want for basic visual elements. Anything
+more complex is likely the domain of an application or widget set that may
+use Edje as a convenient way of being able to configure parts of the display.
+
+For details of Edje's history, see the \ref history section.
+
+
+
+
+
+
+
+
+@section requirements What does Edje require?
+
+Edje requires fairly little on your system. to use the Edje runtime library
+you need:
+
+  - Evas (library)
+  - Ecore (library)
+  - Eet (library)
+  - Embryo (library)
+  - Eina (library)
+
+Evas needs to be build with the JPEG, PNG and EET image loaders enabled at a
+minimum. Edje uses X for the test program, so you will need the SOFTWARE_X11
+engine built into Evas as well. A suggested configure list is below in the
+"cheat sheet" for Evas.
+
+Ecore needs the ECORE, ECORE_EVAS and ECORE_X modules built at a minimum.
+It's suggested to build all the Ecore modules, but the ECORE_FB modules is
+definitely optional.
+
+Eina, Eet and Embryo have no interesting options so just build and
+install them.
+
+It is suggested right now that you get the latest SVN versions of the
+required libraries. You also need to build them in the right order and make
+sure the right options are enabled in the required libraries. Here is a
+quick "cheat sheet" on how to get started.
+
+@verbatim
+1. You need Eina from the trunk svn branch.
+
+  svn co http://svn.enlightenment.org/svn/e/trunk/eina/
+  cd eina
+  ./autogen.sh
+  ./configure
+  make
+  sudo make install
+  cd
+
+2. You need Eet from the trunk svn branch.
+
+  svn co http://svn.enlightenment.org/svn/e/trunk/eet/
+  cd eet
+  ./autogen.sh
+  ./configure
+  make
+  sudo make install
+  cd
+
+3. You need Evas from the trunk svn branch built with eet, png and jpeg loader support.
+
+  svn co http://svn.enlightenment.org/svn/e/trunk/evas/
+  cd evas
+  ./autogen.sh
+  ./configure --enable-image-loader-eet --enable-font-loader-eet --enable-image-loader-jpeg --enable-image-loader-png --enable-buffer
+  make
+  sudo make install
+  cd
+
+4. You need Ecore from the trunk svn branch built with ecore-x and ecore-evas.
+
+  svn co http://svn.enlightenment.org/svn/e/trunk/ecore/
+  cd ecore
+  ./autogen.sh
+  ./configure --enable-ecore-x --enable-ecore-evas --enable-ecore-evas-software-buffer --enable-ecore-evas-software-x11 --enable-ecore-evas-software-buffer
+  make
+  sudo make install
+  cd
+
+5. You need embryo from the trunk svn branch
+
+  svn co http://svn.enlightenment.org/svn/e/trunk/embryo/
+  cd embryo
+  ./autogen.sh
+  ./configure
+  make
+  sudo make install
+  cd
+
+@endverbatim
+
+
+
+
+
+
+
+
+
+@section compiling How to compile and test Edje
+
+Now you need to compile and install Edje.
+
+@verbatim
+  ./configure
+  make
+  sudo make install
+@endverbatim
+
+You now have it installed and ready to go, but you need input
+data. There are lots of examples in SVN, the best one is
+Enlightenment's own theme file.
+
+You may use different tools to edit and view the generated ".edj"
+files, for instance:
+
+  - editje (http://trac.enlightenment.org/e/wiki/Editje)
+  - edje_viewer (http://trac.enlightenment.org/e/wiki/Edje_Viewer)
+
+
+
+
+
+
+
+
+
+
+@section details So how does this all work?
+
+Edje internally holds a geometry state machine and state graph of what is
+visible, not, where, at what size, with what colors etc. This is described
+to Edje from an Edje .edj file containing this information. These files can
+be produced by using edje_cc to take a text file (a .edc file) and "compile"
+an output .edj file that contains this information, images and any other
+data needed.
+
+The application using Edje will then create an object in its Evas
+canvas and set the bundle file to use, specifying the @b group name to
+use. Edje will load such information and create all the required
+children objects with the specified properties as defined in each @b
+part of the given group. See the following annotated example:
+
+@code
+/*
+ * edje_example.c:
+ *
+ *    Creates a window using Ecore_Evas and inside it an object with
+ *    the edje group "my_group" from file "edje_example.edj".
+ *
+ *     Requires edje_example.edj in the current folder.
+ *
+ * Compile:
+ *    gcc -o edje_example edje_example.c `pkg-config --cflags --libs eina-0 evas ecore ecore-evas edje`
+ */
+
+#include <Eina.h>
+#include <Evas.h>
+#include <Ecore.h>
+#include <Ecore_Evas.h>
+#include <Edje.h>
+
+#define WIDTH 320
+#define HEIGHT 240
+
+static Evas_Object *create_my_group(Evas *canvas, const char *text)
+{
+   Evas_Object *edje;
+
+   /* create the edje object where we'll load our file */
+   edje = edje_object_add(canvas);
+   if (!edje)
+     {
+       EINA_LOG_CRIT("could not create edje object!");
+       return NULL;
+     }
+
+   /* load our desired file */
+   if (!edje_object_file_set(edje, "edje_example.edj", "my_group"))
+     {
+       int err = edje_object_load_error_get(edje);
+       const char *errmsg = edje_load_error_str(err);
+       EINA_LOG_ERR("could not load 'my_group' from edje_example.edj: %s",
+                    errmsg);
+
+       evas_object_del(edje);
+       return NULL;
+     }
+
+   if (text)
+     {
+       /* this is will replace the string used by "text" part in "my_group" */
+       if (!edje_object_part_text_set(edje, "text", text))
+         {
+            EINA_LOG_WARN("could not set the text. "
+                          "Maybe part 'text' does not exist?");
+         }
+     }
+
+   /* operate on edje as any other object */
+   evas_object_move(edje, 0, 0);
+   evas_object_resize(edje, WIDTH, HEIGHT);
+   evas_object_show(edje);
+   return edje;
+}
+
+int main(int argc, char *argv[])
+{
+   Ecore_Evas *window;
+   Evas *canvas;
+   Evas_Object *edje;
+   const char *text;
+
+   eina_init();
+   evas_init();
+   ecore_init();
+   ecore_evas_init();
+   edje_init();
+
+   window = ecore_evas_new(NULL, 0, 0, WIDTH, HEIGHT, NULL);
+   if (!window)
+     {
+       EINA_LOG_CRIT("could not create window.");
+       return -1;
+     }
+   canvas = ecore_evas_get(window);
+
+   text = (argc > 1) ? argv[1] : NULL;
+
+   edje = create_my_group(canvas, text);
+   if (!edje)
+     return -2;
+
+   ecore_evas_show(window);
+   ecore_main_loop_begin();
+
+   evas_object_del(edje);
+   ecore_evas_free(window);
+
+   return 0;
+}
+@endcode
+
+It requires the following source Edje file:
+@code
+// compile: edje_cc edje_example.edc
+collections {
+   group {
+      name: "my_group"; // must be the same as in edje_example.c
+
+      parts {
+         part {
+            name: "background";
+            type: RECT; // plain boring rectangle
+            mouse_events: 0; // we don't need any mouse event on the background
+
+            // just one state "default"
+            description {
+               state: "default" 0.0; // must always exist
+               color: 255 255 255 255; // white
+
+               // define part coordinates:
+
+               rel1 { // top-left point at (0, 0) [WIDTH * 0 + 0, HEIGHT * 0 + 0]
+                  relative: 0.0 0.0;
+                  offset: 0 0;
+               }
+               rel2 { // bottom-right point at (WIDTH * 1.0 - 1, HEIGHT * 1.0 - 1)
+                  relative: 1.0 1.0;
+                  offset: -1 -1;
+               }
+            }
+         }
+
+         part {
+            name: "text";
+            type: TEXT;
+            mouse_events: 1; // we want to change the color on mouse-over
+
+            // 2 states, one "default" and another "over" to be used
+            // on mouse over effect
+
+            description {
+               state: "default" 0.0;
+               color: 255 0 0 255; // red
+
+               // define part coordinates:
+
+               rel1 { // top-left at (WIDTH * 0.1 + 5, HEIGHT * 0.2 + 10)
+                  relative: 0.1 0.2;
+                  offset: 5 10;
+               }
+               rel2 { // bottom-right at (WIDTH * 0.9 - 6, HEIGHT * 0.8 - 11)
+                  relative: 0.9 0.8;
+                  offset: -6 -11;
+               }
+
+               // define text specific state details
+               text {
+                  font: "Sans"; /* using fontconfig name! */
+                  size: 10;
+                  text: "hello world";
+               }
+            }
+
+            description {
+               state: "over" 0.0;
+               inherit: "default" 0.0; // copy everything from "default" at this point
+
+               color: 0 255 0 255; // override color, now it is green
+            }
+         }
+
+         // do programs to change color on text mouse in/out (over)
+         programs {
+            program {
+               // what triggers this program:
+               signal: "mouse,in";
+               source: "text";
+
+               // what this program does:
+               action: STATE_SET "over" 0.0;
+               target: "text";
+
+               // do the state-set in a nice interpolation animation
+               // using linear time in 0.1 second
+               transition: LINEAR 0.1;
+            }
+
+            program {
+               // what triggers this program:
+               signal: "mouse,out";
+               source: "text";
+
+               // what this program does:
+               action: STATE_SET "default" 0.0;
+               target: "text";
+
+               // do the state-set in a nice interpolation animation
+               // using linear time in 0.1 second
+               transition: LINEAR 0.1;
+            }
+         }
+      }
+   }
+}
+@endcode
+
+
+One should save these files as edje_example.c and edje_example.edc then:
+@verbatim
+gcc -o edje_example edje_example.c `pkg-config --cflags --libs eina-0 evas ecore ecore-evas edje`
+edje_cc edje_example.edc
+
+./edje_example "some text"
+@endverbatim
+
+Although simple, this example illustrates that animations and state
+changes can be done from the Edje file itself without any requirement
+in the C application.
+
+Before digging into changing or creating your own Edje source (edc)
+files, read the \ref edcref.
+
+
+
+@section history Edje History
+
+It's a sequel to "Ebits" which has serviced the needs of Enlightenment
+development for early version 0.17. The original design parameters under
+which Ebits came about were a lot more restricted than the resulting
+use of them, thus Edje was born.
+
+Edje is a more complex layout engine compared to Ebits. It doesn't
+pretend to do containing and regular layout like a widget set. It
+still inherits the more simplistic layout ideas behind Ebits, but it
+now does them a lot more cleanly, allowing for easy expansion, and the
+ability to cover much more ground than Ebits ever could. For the
+purposes of Enlightenment 0.17, Edje was conceived to serve all the
+purposes of creating visual elements (borders of windows, buttons,
+scrollbars, etc.) and allow the designer the ability to animate,
+layout and control the look and feel of any program using Edje as its
+basic GUI constructor.
+
+Unlike Ebits, Edje separates the layout and behavior logic.
+
+
+
+
+
+
+
+
+
+@todo Complete documentation of API
+@todo Bytecode language for extending programs... but what/how?
+
+*/
diff --git a/doc/examples/lua_set_state.edc b/doc/examples/lua_set_state.edc
new file mode 100644 (file)
index 0000000..dc24ae9
--- /dev/null
@@ -0,0 +1,46 @@
+collections {
+   group { name: "main";
+      parts {
+         part { name: "bg";
+            type: RECT;
+            description { state: "default" 0.0;
+               color: 255 255 255 255;
+            }
+         }
+         part { name: "label";
+            type: TEXT;
+            description { state: "default" 0.0;
+               color: 0 0 0 255;
+               text {
+                  text: "Click me.";
+                  font: "Sans";
+                  size: 12;
+                  align: 0.0 0.7;
+               }
+            }
+         }
+         part { name: "red_rect";
+            type: RECT;
+            description { state: "default" 0.0;
+               color: 255 0 0 255;
+               max: 30 30;
+               align: 0.1 0.2;
+            }
+            description { state: "default" 1.0;
+               inherit: "default" 0.0;
+               color: 0 0 255 255;
+               align: 0.9 0.2;
+            }
+         }
+      }
+      programs {
+         program {
+            signal: "mouse,down,1";
+            source: "label";
+            lua_script {
+               ed.red_rect.state = { "default", 1.0}
+            }
+         }
+      }
+   }
+}
diff --git a/doc/examples/lua_set_text.edc b/doc/examples/lua_set_text.edc
new file mode 100644 (file)
index 0000000..2676104
--- /dev/null
@@ -0,0 +1,39 @@
+collections {
+   group { name: "main";
+      parts {
+         part { name: "bg";
+            type: RECT;
+            description { state: "default" 0.0;
+               color: 255 255 255 255;
+            }
+         }
+         part { name: "label";
+            type: TEXT;
+            description { state: "default" 0.0;
+               color: 0 0 0 255;
+               text {
+                  text: "Click me.";
+                  font: "Sans";
+                  size: 12;
+               }
+            }
+         }
+      }
+      programs {
+         program {
+            signal: "mouse,down,1";
+            source: "label";
+            lua_script {
+               ed.label.text = "Clicked!"
+            }
+         }
+         program {
+            signal: "mouse,up,1";
+            source: "label";
+            lua_script {
+               ed.label.text = "Click me."
+            }
+         }
+      }
+   }
+}
diff --git a/doc/examples/lua_timer.edc b/doc/examples/lua_timer.edc
new file mode 100644 (file)
index 0000000..492fb1a
--- /dev/null
@@ -0,0 +1,107 @@
+collections {
+   group { name: "main";
+      parts {
+         part { name: "bg";
+            type: RECT;
+            description { state: "default" 0.0;
+               color: 255 255 255 255;
+            }
+         }
+         part { name: "label1";
+            type: TEXT;
+            description { state: "default" 0.0;
+               color: 0 0 0 255;
+               text {
+                  text: "Timer delayed...";
+                  font: "Sans";
+                  size: 12;
+                  align: 0.0 0.7;
+               }
+            }
+         }
+         part { name: "label2";
+            type: TEXT;
+            description { state: "default" 0.0;
+               color: 0 0 0 255;
+               text {
+                  font: "Sans";
+                  size: 12;
+                  align: 0.0 0.8;
+               }
+            }
+         }
+         part { name: "label3";
+            type: TEXT;
+            description { state: "default" 0.0;
+               color: 0 0 0 255;
+               text {
+                  font: "Sans";
+                  size: 12;
+                  align: 0.0 0.9;
+               }
+            }
+         }
+         part { name: "red_rect";
+            type: RECT;
+            description { state: "default" 0.0;
+               color: 255 0 0 255;
+               max: 30 30;
+               align: 0.1 0.2;
+            }
+            description { state: "default" 1.0;
+               inherit: "default" 0.0;
+               color: 0 0 255 255;
+               align: 0.9 0.2;
+            }
+         }
+      }
+      programs {
+         /* Move the red rect back an forth in a loop */
+         program { name: "init";
+            signal: "load";
+            source: "";
+            action: STATE_SET "default" 1.0;
+            transition: SINUSOIDAL 1.0;
+            target: "red_rect";
+            after: "loop";
+         }
+         program { name: "loop";
+            action: STATE_SET "default" 0.0;
+            transition: SINUSOIDAL 1.0;
+            target: "red_rect";
+            after: "init";
+         }
+         program { name: "lua_init";
+            signal: "load";
+            source: "";
+            lua_script {
+               function timer_cb()
+                  /* Print Timer attributes */
+                  print("## timer_cb")
+                  print("   timer.pending:", timer.pending)
+                  print("   timer.precision:", timer.precision)
+                  print("   timer.interval:", timer.interval)
+
+                  /* Slow down the timer */
+                  timer.interval = timer.interval + 0.005
+
+                  /* Set labels with object info */
+                  ed.label1.text = "timer interval: " .. timer.interval
+                  ed.label2.text = "object x: " .. ed.red_rect.geometry[1]
+                  r, g, b, a = unpack(ed.red_rect.color)
+                  ed.label3.text = "object color: "..r.." "..g.." ".. b
+
+                  /* or return CALLBACK_CANCEL to stop the timer*/
+                  return CALLBACK_RENEW
+               end
+
+               /* Start a new timer that will call timer_cb every 0.01s */
+               timer = ed:timer(0.01, timer_cb)
+               
+               /* Delay the timer execution by 2s */
+               timer:delay(2)
+            }
+         }
+      }
+   }
+}
diff --git a/doc/foot.html b/doc/foot.html
new file mode 100644 (file)
index 0000000..d43cf8f
--- /dev/null
@@ -0,0 +1,18 @@
+ <div id="push"></div>
+ </div> <!-- #content -->
+  </div> <!-- .layout -->
+ </div> <!-- #container -->
+  <div id="footer">
+    <table><tr>
+      <td class="copyright">Copyright &copy;$year Enlightenment</td>
+      <td class="generated">Docs generated $datetime</td>
+    </tr></table>
+  </div>
+
+
+</body>
+</html>
diff --git a/doc/head.html b/doc/head.html
new file mode 100644 (file)
index 0000000..617c01b
--- /dev/null
@@ -0,0 +1,69 @@
+<html>
+<head>
+    <title>$title</title>
+    <meta http-equiv="content-type" content="text/html;charset=UTF-8">
+    <meta name="author" content="Andres Blanc" >
+    
+    <link rel="icon" href="img/favicon.png" type="image/x-icon">
+    <link rel="shortcut icon" href="img/favicon.png" type="image/x-icon">
+    <link rel="icon" href="img/favicon.png" type="image/ico">
+    <link rel="shortcut icon" href="img/favicon.png" type="image/ico">
+
+    <link rel="stylesheet" type="text/css" href="e.css">
+    <link rel="stylesheet" type="text/css" href="edoxy.css">
+</head>
+
+<body>
+
+<div id="container">
+
+<div id="header">
+<div class="layout">
+    
+    <h1><span>Enlightenment</span></h1>
+    <h2><span>Beauty at your fingertips</span></h2>
+
+    <table cellspacing="0" cellpadding="0" width="100%"><tr>
+      <td id="header_logo">
+        <a href="http://www.enlightenment.org"></a>
+      </td>
+      <td id="header_menu">
+        <table cellspacing="0" cellpadding="0" align="right"><tr>
+          <td class="nav_passive"><a class="nav_passive" href="http://www.enlightenment.org/p.php?p=home">Home</a></td> 
+          <td class="nav_passive"><a class="nav_passive" href="http://www.enlightenment.org/p.php?p=news">News</a></td> 
+          <td class="nav_passive"><a class="nav_passive" href="http://www.enlightenment.org/p.php?p=about">About</a></td> 
+          <td class="nav_passive"><a class="nav_passive" href="http://www.enlightenment.org/p.php?p=download">Download</a></td> 
+          <td class="nav_passive"><a class="nav_passive" href="http://www.enlightenment.org/p.php?p=support">Support</a></td> 
+          <td class="nav_passive"><a class="nav_passive" href="http://www.enlightenment.org/p.php?p=contribute">Contribute</a></td> 
+          <td class="nav_passive"><a class="nav_passive" href="http://www.enlightenment.org/p.php?p=contact">Contact</a></td> 
+          <td class="nav_passive"><a class="nav_passive" href="http://trac.enlightenment.org/e">Tracker</a></td>
+          <td class="nav_passive"><a class="nav_passive" href="http://www.enlightenment.org/p.php?p=docs">Docs</a></td> 
+        </tr></table>          
+      </td>
+      <td id="header_last"></td>
+    </tr></table>
+
+    <div class="doxytitle">
+        $projectname Documentation <small>at $date</small>
+    </div>
+
+    <div class="menu-container">
+        <div class="submenu">
+            <ul class="current">
+                <li><a href="files.html">Files</a></li>
+                <li><a href="Edje__Edit_8h.html">Edje Edit API</a></li>
+                <li><a href="luaref.html">LUA scripting</a></li>
+                <li><a href="Edje_8h.html">Edje API</a></li>
+                <li><a href="edcref.html">EDC Reference</a></li>
+               <li class="current"><a  href="index.html">Main Page</a></li>
+            </ul>
+        </div>
+    </div>
+
+
+    <div class="clear"></div>
+</div>
+</div>
+
+<div id="content">
+<div class="layout">
diff --git a/doc/img/e.png b/doc/img/e.png
new file mode 100644 (file)
index 0000000..d42aeb4
Binary files /dev/null and b/doc/img/e.png differ
diff --git a/doc/img/edoxy.css b/doc/img/edoxy.css
new file mode 100644 (file)
index 0000000..311ca23
--- /dev/null
@@ -0,0 +1,486 @@
+/*
+ * This file contain a custom doxygen style to match e.org graphics
+ */
+
+
+
+/* BODY,H1,H2,H3,H4,H5,H6,P,CENTER,TD,TH,UL,DL,DIV {
+       font-family: Geneva, Arial, Helvetica, sans-serif;
+}*/ 
+BODY, TD {
+       font-size: 12px;
+}
+H1 {
+       text-align: center;
+       font-size: 160%;
+}
+H2 {
+       font-size: 120%;
+}
+H3 {
+       font-size: 100%;
+}
+CAPTION { 
+       font-weight: bold 
+}
+DIV.qindex {
+       width: 100%;
+       background-color: #e8eef2;
+       border: 1px solid #84b0c7;
+       text-align: center;
+       margin: 2px;
+       padding: 2px;
+       line-height: 140%;
+}
+DIV.navpath {
+       width: 100%;
+       background-color: #e8eef2;
+       border: 1px solid #84b0c7;
+       text-align: center;
+       margin: 2px;
+       padding: 2px;
+       line-height: 140%;
+}
+DIV.navtab {
+       background-color: #e8eef2;
+       border: 1px solid #84b0c7;
+       text-align: center;
+       margin: 2px;
+       margin-right: 15px;
+       padding: 2px;
+}
+TD.navtab {
+       font-size: 70%;
+}
+A.qindex {
+       text-decoration: none;
+       font-weight: bold;
+       color: #1A419D;
+}
+A.qindex:visited {
+       text-decoration: none;
+       font-weight: bold;
+       color: #1A419D
+}
+A.qindex:hover {
+       text-decoration: none;
+       background-color: #ddddff;
+}
+A.qindexHL {
+       text-decoration: none;
+       font-weight: bold;
+       background-color: #6666cc;
+       color: #ffffff;
+       border: 1px double #9295C2;
+}
+A.qindexHL:hover {
+       text-decoration: none;
+       background-color: #6666cc;
+       color: #ffffff;
+}
+A.qindexHL:visited { 
+       text-decoration: none; 
+       background-color: #6666cc; 
+       color: #ffffff 
+}
+A.el { 
+       text-decoration: none; 
+       font-weight: bold 
+}
+A.elRef { 
+       font-weight: bold 
+}
+A.code:link { 
+       text-decoration: none; 
+       font-weight: normal; 
+       color: #0000FF
+}
+A.code:visited { 
+       text-decoration: none; 
+       font-weight: normal; 
+       color: #0000FF
+}
+A.codeRef:link { 
+       font-weight: normal; 
+       color: #0000FF
+}
+A.codeRef:visited { 
+       font-weight: normal; 
+       color: #0000FF
+}
+A:hover, A:visited:hover { 
+       text-decoration: none;  
+       /* background-color: #f2f2ff; */
+       color: #000055;
+}
+A.anchor {
+       color: #000;
+}
+DL.el { 
+       margin-left: -1cm 
+}
+.fragment {
+       font-family: monospace, fixed;
+       font-size: 95%;
+}
+PRE.fragment {
+       border: 1px solid #CCCCCC;
+       background-color: #f5f5f5;
+       margin-top: 4px;
+       margin-bottom: 4px;
+       margin-left: 2px;
+       margin-right: 8px;
+       padding-left: 6px;
+       padding-right: 6px;
+       padding-top: 4px;
+       padding-bottom: 4px;
+}
+DIV.ah { 
+       background-color: black; 
+       font-weight: bold; 
+       color: #ffffff; 
+       margin-bottom: 3px; 
+       margin-top: 3px 
+}
+
+DIV.groupHeader {
+       margin-left: 16px;
+       margin-top: 12px;
+       margin-bottom: 6px;
+       font-weight: bold;
+}
+DIV.groupText { 
+       margin-left: 16px; 
+       font-style: italic; 
+       font-size: 90% 
+}
+/*BODY {
+       background: white;
+       color: black;
+       margin-right: 20px;
+       margin-left: 20px;
+}*/
+TD.indexkey {
+       background-color: #e8eef2;
+       font-weight: bold;
+       padding-right  : 10px;
+       padding-top    : 2px;
+       padding-left   : 10px;
+       padding-bottom : 2px;
+       margin-left    : 0px;
+       margin-right   : 0px;
+       margin-top     : 2px;
+       margin-bottom  : 2px;
+       border: 1px solid #CCCCCC;
+}
+TD.indexvalue {
+       background-color: #e8eef2;
+       font-style: italic;
+       padding-right  : 10px;
+       padding-top    : 2px;
+       padding-left   : 10px;
+       padding-bottom : 2px;
+       margin-left    : 0px;
+       margin-right   : 0px;
+       margin-top     : 2px;
+       margin-bottom  : 2px;
+       border: 1px solid #CCCCCC;
+}
+TR.memlist {
+       background-color: #f0f0f0; 
+}
+P.formulaDsp { 
+       text-align: center; 
+}
+IMG.formulaDsp {
+}
+IMG.formulaInl { 
+       vertical-align: middle; 
+}
+SPAN.keyword       { color: #008000 }
+SPAN.keywordtype   { color: #604020 }
+SPAN.keywordflow   { color: #e08000 }
+SPAN.comment       { color: #800000 }
+SPAN.preprocessor  { color: #806020 }
+SPAN.stringliteral { color: #002080 }
+SPAN.charliteral   { color: #008080 }
+SPAN.vhdldigit     { color: #ff00ff }
+SPAN.vhdlchar      { color: #000000 }
+SPAN.vhdlkeyword   { color: #700070 }
+SPAN.vhdllogic     { color: #ff0000 }
+
+.mdescLeft {
+       padding: 0px 8px 4px 8px;
+       font-size: 80%;
+       font-style: italic;
+       background-color: #FAFAFA;
+       border-top: 1px none #E0E0E0;
+       border-right: 1px none #E0E0E0;
+       border-bottom: 1px none #E0E0E0;
+       border-left: 1px none #E0E0E0;
+       margin: 0px;
+}
+.mdescRight {
+        padding: 0px 8px 4px 8px;
+       font-size: 80%;
+       font-style: italic;
+       background-color: #FAFAFA;
+       border-top: 1px none #E0E0E0;
+       border-right: 1px none #E0E0E0;
+       border-bottom: 1px none #E0E0E0;
+       border-left: 1px none #E0E0E0;
+       margin: 0px;
+}
+.memItemLeft {
+       padding: 1px 0px 0px 8px;
+       margin: 4px;
+       border-top-width: 1px;
+       border-right-width: 1px;
+       border-bottom-width: 1px;
+       border-left-width: 1px;
+       border-top-color: #E0E0E0;
+       border-right-color: #E0E0E0;
+       border-bottom-color: #E0E0E0;
+       border-left-color: #E0E0E0;
+       border-top-style: solid;
+       border-right-style: none;
+       border-bottom-style: none;
+       border-left-style: none;
+       background-color: #FAFAFA;
+       font-size: 80%;
+}
+.memItemRight {
+       padding: 1px 8px 0px 8px;
+       margin: 4px;
+       border-top-width: 1px;
+       border-right-width: 1px;
+       border-bottom-width: 1px;
+       border-left-width: 1px;
+       border-top-color: #E0E0E0;
+       border-right-color: #E0E0E0;
+       border-bottom-color: #E0E0E0;
+       border-left-color: #E0E0E0;
+       border-top-style: solid;
+       border-right-style: none;
+       border-bottom-style: none;
+       border-left-style: none;
+       background-color: #FAFAFA;
+       font-size: 80%;
+}
+.memTemplItemLeft {
+       padding: 1px 0px 0px 8px;
+       margin: 4px;
+       border-top-width: 1px;
+       border-right-width: 1px;
+       border-bottom-width: 1px;
+       border-left-width: 1px;
+       border-top-color: #E0E0E0;
+       border-right-color: #E0E0E0;
+       border-bottom-color: #E0E0E0;
+       border-left-color: #E0E0E0;
+       border-top-style: none;
+       border-right-style: none;
+       border-bottom-style: none;
+       border-left-style: none;
+       background-color: #FAFAFA;
+       font-size: 80%;
+}
+.memTemplItemRight {
+       padding: 1px 8px 0px 8px;
+       margin: 4px;
+       border-top-width: 1px;
+       border-right-width: 1px;
+       border-bottom-width: 1px;
+       border-left-width: 1px;
+       border-top-color: #E0E0E0;
+       border-right-color: #E0E0E0;
+       border-bottom-color: #E0E0E0;
+       border-left-color: #E0E0E0;
+       border-top-style: none;
+       border-right-style: none;
+       border-bottom-style: none;
+       border-left-style: none;
+       background-color: #FAFAFA;
+       font-size: 80%;
+}
+.memTemplParams {
+       padding: 1px 0px 0px 8px;
+       margin: 4px;
+       border-top-width: 1px;
+       border-right-width: 1px;
+       border-bottom-width: 1px;
+       border-left-width: 1px;
+       border-top-color: #E0E0E0;
+       border-right-color: #E0E0E0;
+       border-bottom-color: #E0E0E0;
+       border-left-color: #E0E0E0;
+       border-top-style: solid;
+       border-right-style: none;
+       border-bottom-style: none;
+       border-left-style: none;
+       color: #606060;
+       background-color: #FAFAFA;
+       font-size: 80%;
+}
+.search { 
+       color: #003399;
+       font-weight: bold;
+}
+FORM.search {
+       margin-bottom: 0px;
+       margin-top: 0px;
+}
+INPUT.search { 
+       font-size: 75%;
+       color: #000080;
+       font-weight: normal;
+       background-color: #e8eef2;
+}
+TD.tiny { 
+       font-size: 75%;
+}
+a {
+       color: #1A41A8;
+}
+a:visited {
+       color: #2A3798;
+}
+.dirtab { 
+       padding: 4px;
+       border-collapse: collapse;
+       border: 1px solid #84b0c7;
+}
+TH.dirtab { 
+       background: #e8eef2;
+       font-weight: bold;
+}
+HR { 
+       height: 1px;
+       border: none;
+       border-top: 1px solid black;
+}
+
+/* Style for detailed member documentation */
+.memtemplate {
+       font-size: 80%;
+       color: #606060;
+       font-weight: normal;
+       margin-left: 3px;
+} 
+.memnav { 
+       background-color: #eeeeee;
+       border: 1px solid #dddddd;
+       text-align: center;
+       margin: 2px;
+       margin-right: 15px;
+       padding: 2px;
+}
+.memitem {
+       padding: 4px;
+       background-color: #eeeeee;
+       border-width: 1px;
+       border-style: solid;
+       border-color: #dddddd;
+       -moz-border-radius: 4px 4px 4px 4px;
+}
+.memname {
+       white-space: nowrap;
+       font-weight: bold;
+        color: #ffffff;
+}
+.memdoc{
+       padding-left: 10px;
+}
+.memproto {
+       background-color: #111111;
+       width: 100%;
+       border-width: 1px;
+       border-style: solid;
+       border-color: #000000;
+       font-weight: bold;
+       -moz-border-radius: 4px 4px 4px 4px;
+}
+.paramkey {
+       text-align: right;
+       color: #ffffff;
+}
+.paramtype {
+       white-space: nowrap;
+       color: #aaaaaa;
+}
+.paramname {
+       color: #ff0000;
+       font-style: italic;
+       white-space: nowrap;
+}
+/* End Styling for detailed member documentation */
+
+/* for the tree view */
+.ftvtree {
+       font-family: sans-serif;
+       margin:0.5em;
+}
+/* these are for tree view when used as main index */
+.directory { 
+       font-size: 9pt; 
+       font-weight: bold; 
+}
+.directory h3 { 
+       margin: 0px; 
+       margin-top: 1em; 
+       font-size: 11pt; 
+}
+
+/* The following two styles can be used to replace the root node title */
+/* with an image of your choice.  Simply uncomment the next two styles, */
+/* specify the name of your image and be sure to set 'height' to the */
+/* proper pixel height of your image. */
+
+/* .directory h3.swap { */
+/*     height: 61px; */
+/*     background-repeat: no-repeat; */
+/*     background-image: url("yourimage.gif"); */
+/* } */
+/* .directory h3.swap span { */
+/*     display: none; */
+/* } */
+
+.directory > h3 { 
+       margin-top: 0; 
+}
+.directory p { 
+       margin: 0px; 
+       white-space: nowrap; 
+}
+.directory div { 
+       display: none; 
+       margin: 0px; 
+}
+.directory img { 
+       vertical-align: -30%; 
+}
+/* these are for tree view when not used as main index */
+.directory-alt { 
+       font-size: 100%; 
+       font-weight: bold; 
+}
+.directory-alt h3 { 
+       margin: 0px; 
+       margin-top: 1em; 
+       font-size: 11pt; 
+}
+.directory-alt > h3 { 
+       margin-top: 0; 
+}
+.directory-alt p { 
+       margin: 0px; 
+       white-space: nowrap; 
+}
+.directory-alt div { 
+       display: none; 
+       margin: 0px; 
+}
+.directory-alt img { 
+       vertical-align: -30%; 
+}
+
diff --git a/doc/img/elementary.png b/doc/img/elementary.png
new file mode 100644 (file)
index 0000000..7975489
Binary files /dev/null and b/doc/img/elementary.png differ
diff --git a/doc/img/foot_bg.png b/doc/img/foot_bg.png
new file mode 100644 (file)
index 0000000..b24f3a4
Binary files /dev/null and b/doc/img/foot_bg.png differ
diff --git a/doc/img/head_bg.png b/doc/img/head_bg.png
new file mode 100644 (file)
index 0000000..081dc13
Binary files /dev/null and b/doc/img/head_bg.png differ
diff --git a/doc/img/header_menu_background.png b/doc/img/header_menu_background.png
new file mode 100644 (file)
index 0000000..e978743
Binary files /dev/null and b/doc/img/header_menu_background.png differ
diff --git a/doc/img/header_menu_background_last.png b/doc/img/header_menu_background_last.png
new file mode 100644 (file)
index 0000000..88c116c
Binary files /dev/null and b/doc/img/header_menu_background_last.png differ
diff --git a/doc/img/header_menu_current_background.png b/doc/img/header_menu_current_background.png
new file mode 100644 (file)
index 0000000..de97c92
Binary files /dev/null and b/doc/img/header_menu_current_background.png differ
diff --git a/doc/img/header_menu_unselected_background.png b/doc/img/header_menu_unselected_background.png
new file mode 100644 (file)
index 0000000..50e5fd8
Binary files /dev/null and b/doc/img/header_menu_unselected_background.png differ
diff --git a/doc/img/logo.png b/doc/img/logo.png
new file mode 100644 (file)
index 0000000..b3884a5
Binary files /dev/null and b/doc/img/logo.png differ
diff --git a/edje.pc.in b/edje.pc.in
new file mode 100644 (file)
index 0000000..48412ff
--- /dev/null
@@ -0,0 +1,14 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+datarootdir=@datarootdir@
+datadir=@datadir@/edje
+
+Name: edje
+Description: Enlightened graphical design and layout engine.
+@pkgconfig_requires_private@: @requirement_edje@
+Version: @VERSION@
+Libs: -L${libdir} -ledje
+Libs.private:
+Cflags: -I${includedir}
diff --git a/edje.spec.in b/edje.spec.in
new file mode 100644 (file)
index 0000000..c28ac02
--- /dev/null
@@ -0,0 +1,101 @@
+%define _missing_doc_files_terminate_build 0
+
+%{!?_rel:%{expand:%%global _rel 0.r%(svnversion | sed 's/[^0-9].*$//' || echo 0000)}}
+
+Summary: Complex Graphical Design/Layout Engine
+Name: @PACKAGE@
+Version: @VERSION@
+Release: %{_rel}
+License: BSD
+Group: System Environment/Libraries
+URL: http://www.enlightenment.org/
+Source: ftp://ftp.enlightenment.org/pub/evoak/%{name}-%{version}.tar.gz
+Packager: %{?_packager:%{_packager}}%{!?_packager:Michael Jennings <mej@eterm.org>}
+Vendor: %{?_vendorinfo:%{_vendorinfo}}%{!?_vendorinfo:The Enlightenment Project (http://www.enlightenment.org/)}
+Distribution: %{?_distribution:%{_distribution}}%{!?_distribution:%{_vendor}}
+#BuildSuggests: xorg-x11-devel, vim-enhanced
+BuildRequires: eet-devel, embryo-devel, evas-devel, ecore-devel
+Requires:  evas-module_loader_eet
+BuildRoot: %{_tmppath}/%{name}-%{version}-root
+
+%description
+Edje is a complex graphical design and layout engine. It provides a
+mechanism for allowing configuration data to define visual elements in
+terms of layout, behavior, and appearance.  Edje allows for multiple
+collections of layouts in one file, allowing a complete set of images,
+animations, and controls to exist as a unified whole.
+
+Edje separates the arrangement, appearance, and behavior logic into
+distinct independent entities.  This allows visual objects to share
+image data and configuration information without requiring them to do
+so.  This separation and simplistic event driven style of programming
+can produce almost any look and feel one could want for basic visual
+elements. Anything more complex is likely the domain of an application
+or widget set that may use Edje as a conveneient way of being able to
+configure parts of the display.
+
+%package devel
+Summary: Edje headers, static libraries, documentation and test programs
+Group: System Environment/Libraries
+Requires: %{name} = %{version}, %{name}-bin = %{version}
+Requires: eet-devel embryo-devel evas-devel ecore-devel
+
+%description devel
+Headers, static libraries, test programs and documentation for Edje
+
+%package bin
+Summary: Edje file compiler/decompiler suite
+Group: System Environment/Libraries
+Requires: %{name} = %{version}
+Requires: embryo-bin
+Requires: evas-module_saver_eet, evas-module_loader_png, evas-module_saver_png
+Requires: evas-module_loader_jpeg, evas-module_saver_jpeg, evas-module_engine_buffer
+
+%description bin
+Edje file compiler/decompiler suite
+
+%prep
+%setup -q
+
+%build
+%{configure} --prefix=%{_prefix}
+%{__make} %{?_smp_mflags} %{?mflags}
+
+%install
+%{__make} %{?mflags_install} DESTDIR=$RPM_BUILD_ROOT install
+test -x `which doxygen` && sh gendoc || :
+
+%post
+/sbin/ldconfig || :
+
+%postun
+/sbin/ldconfig || :
+
+%clean
+test "x$RPM_BUILD_ROOT" != "x/" && rm -rf $RPM_BUILD_ROOT
+
+%files
+%defattr(-, root, root)
+%doc AUTHORS COPYING README
+%{_libdir}/libedje*.so.*
+
+%files devel
+%defattr(-, root, root)
+%doc doc/html
+%{_libdir}/*.so
+%{_libdir}/*.la
+%{_libdir}/*.a
+%{_libdir}/pkgconfig/*
+%{_includedir}/*.h
+
+%files bin
+%defattr(-, root, root)
+%{_bindir}/edje_cc
+%{_bindir}/edje_decc
+%{_bindir}/edje_recc
+%{_bindir}/edje_player
+%{_bindir}/inkscape2edc
+%{_datadir}/edje/include/edje.inc
+%{_datadir}/mime/packages/edje.xml
+
+%changelog
diff --git a/edje.supp b/edje.supp
new file mode 100644 (file)
index 0000000..9e7a647
--- /dev/null
+++ b/edje.supp
@@ -0,0 +1,8 @@
+# $Id: edje.supp 8548 2004-01-17 23:53:57Z tsauerbeck $
+# valgrind suppression file for Edje.
+#
+{
+   BogusWarning
+   Memcheck:Cond
+   fun:_edje_part_recalc
+}
diff --git a/m4/ac_attribute.m4 b/m4/ac_attribute.m4
new file mode 100644 (file)
index 0000000..23479a9
--- /dev/null
@@ -0,0 +1,47 @@
+dnl Copyright (C) 2004-2008 Kim Woelders
+dnl Copyright (C) 2008 Vincent Torri <vtorri at univ-evry dot fr>
+dnl That code is public domain and can be freely used or copied.
+dnl Originally snatched from somewhere...
+
+dnl Macro for checking if the compiler supports __attribute__
+
+dnl Usage: AC_C___ATTRIBUTE__
+dnl call AC_DEFINE for HAVE___ATTRIBUTE__ and __UNUSED__
+dnl if the compiler supports __attribute__, HAVE___ATTRIBUTE__ is
+dnl defined to 1 and __UNUSED__ is defined to __attribute__((unused))
+dnl otherwise, HAVE___ATTRIBUTE__ is not defined and __UNUSED__ is
+dnl defined to nothing.
+
+AC_DEFUN([AC_C___ATTRIBUTE__],
+[
+
+AC_MSG_CHECKING([for __attribute__])
+
+AC_CACHE_VAL([ac_cv___attribute__],
+   [AC_TRY_COMPILE(
+       [
+#include <stdlib.h>
+
+int func(int x);
+int foo(int x __attribute__ ((unused)))
+{
+   exit(1);
+}
+       ],
+       [],
+       [ac_cv___attribute__="yes"],
+       [ac_cv___attribute__="no"]
+    )])
+
+AC_MSG_RESULT($ac_cv___attribute__)
+
+if test "x${ac_cv___attribute__}" = "xyes" ; then
+   AC_DEFINE([HAVE___ATTRIBUTE__], [1], [Define to 1 if your compiler has __attribute__])
+   AC_DEFINE([__UNUSED__], [__attribute__((unused))], [Macro declaring a function argument to be unused])
+  else
+    AC_DEFINE([__UNUSED__], [], [Macro declaring a function argument to be unused])
+fi
+
+])
+
+dnl End of ac_attribute.m4
diff --git a/m4/efl_binary.m4 b/m4/efl_binary.m4
new file mode 100644 (file)
index 0000000..0fe85ab
--- /dev/null
@@ -0,0 +1,44 @@
+dnl Copyright (C) 2010 Vincent Torri <vtorri at univ-evry dot fr>
+dnl That code is public domain and can be freely used or copied.
+
+dnl Macro that check if a binary is built or not
+
+dnl Usage: EFL_ENABLE_BIN(binary)
+dnl Call AC_SUBST(BINARY_PRG) (BINARY is the uppercase of binary, - being tranformed into _)
+dnl Define have_binary (- is tranformed into _)
+dnl Define conditional BUILD_BINARY (BINARY is the uppercase of binary, - being tranformed into _)
+
+AC_DEFUN([EFL_ENABLE_BIN],
+[
+
+m4_pushdef([UP], m4_translit([[$1]], [-a-z], [_A-Z]))dnl
+m4_pushdef([DOWN], m4_translit([[$1]], [-A-Z], [_a-z]))dnl
+
+have_[]m4_defn([DOWN])="yes"
+
+dnl configure option
+
+AC_ARG_ENABLE([$1],
+   [AC_HELP_STRING([--disable-$1], [disable building of ]DOWN)],
+   [
+    if test "x${enableval}" = "xyes" ; then
+       have_[]m4_defn([DOWN])="yes"
+    else
+       have_[]m4_defn([DOWN])="no"
+    fi
+   ])
+
+AC_MSG_CHECKING([whether to build ]DOWN[ binary])
+AC_MSG_RESULT([$have_[]m4_defn([DOWN])])
+
+if test "x$have_[]m4_defn([DOWN])" = "xyes"; then
+   UP[]_PRG=DOWN[${EXEEXT}]
+fi
+
+AC_SUBST(UP[]_PRG)
+
+AM_CONDITIONAL(BUILD_[]UP, test "x$have_[]m4_defn([DOWN])" = "xyes")
+
+AS_IF([test "x$have_[]m4_defn([DOWN])" = "xyes"], [$2], [$3])
+
+])
diff --git a/m4/efl_doxygen.m4 b/m4/efl_doxygen.m4
new file mode 100644 (file)
index 0000000..d83ed68
--- /dev/null
@@ -0,0 +1,97 @@
+dnl Copyright (C) 2008 Vincent Torri <vtorri at univ-evry dot fr>
+dnl That code is public domain and can be freely used or copied.
+
+dnl Macro that check if doxygen is available or not.
+
+dnl EFL_CHECK_DOXYGEN([ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]])
+dnl Test for the doxygen program
+dnl Defines efl_doxygen
+dnl Defines the automake conditionnal EFL_BUILD_DOC
+dnl
+AC_DEFUN([EFL_CHECK_DOXYGEN],
+[
+
+dnl
+dnl Disable the build of the documentation
+dnl
+AC_ARG_ENABLE([doc],
+   [AC_HELP_STRING(
+       [--disable-doc],
+       [Disable documentation build @<:@default=enabled@:>@])],
+   [
+    if test "x${enableval}" = "xyes" ; then
+       efl_enable_doc="yes"
+    else
+       efl_enable_doc="no"
+    fi
+   ],
+   [efl_enable_doc="yes"])
+
+AC_MSG_CHECKING([whether to build documentation])
+AC_MSG_RESULT([${efl_enable_doc}])
+
+if test "x${efl_enable_doc}" = "xyes" ; then
+
+dnl Specify the file name, without path
+
+   efl_doxygen="doxygen"
+
+   AC_ARG_WITH([doxygen],
+      [AC_HELP_STRING(
+          [--with-doxygen=FILE],
+          [doxygen program to use @<:@default=doxygen@:>@])],
+
+dnl Check the given doxygen program.
+
+      [efl_doxygen=${withval}
+       AC_CHECK_PROG([efl_have_doxygen],
+          [${efl_doxygen}],
+          [yes],
+          [no])
+       if test "x${efl_have_doxygen}" = "xno" ; then
+          echo "WARNING:"
+          echo "The doxygen program you specified:"
+          echo "${efl_doxygen}"
+          echo "was not found.  Please check the path and make sure "
+          echo "the program exists and is executable."
+          AC_MSG_WARN([no doxygen detected. Documentation will not be built])
+       fi
+      ],
+      [AC_CHECK_PROG([efl_have_doxygen],
+          [${efl_doxygen}],
+          [yes],
+          [no])
+       if test "x${efl_have_doxygen}" = "xno" ; then
+          echo "WARNING:"
+          echo "The doxygen program was not found in your execute path."
+          echo "You may have doxygen installed somewhere not covered by your path."
+          echo ""
+          echo "If this is the case make sure you have the packages installed, AND"
+          echo "that the doxygen program is in your execute path (see your"
+          echo "shell manual page on setting the \$PATH environment variable), OR"
+          echo "alternatively, specify the program to use with --with-doxygen."
+          AC_MSG_WARN([no doxygen detected. Documentation will not be built])
+       fi
+      ])
+fi
+
+dnl
+dnl Substitution
+dnl
+AC_SUBST([efl_doxygen])
+
+if ! test "x${efl_have_doxygen}" = "xyes" ; then
+   efl_enable_doc="no"
+fi
+
+AM_CONDITIONAL(EFL_BUILD_DOC, test "x${efl_enable_doc}" = "xyes")
+
+if test "x${efl_enable_doc}" = "xyes" ; then
+  m4_default([$1], [:])
+else
+  m4_default([$2], [:])
+fi
+
+])
+
+dnl End of efl_doxygen.m4
diff --git a/m4/efl_path_max.m4 b/m4/efl_path_max.m4
new file mode 100644 (file)
index 0000000..f57bfd2
--- /dev/null
@@ -0,0 +1,36 @@
+dnl Check for PATH_MAX in limits.h, and define a default value if not found
+dnl This is a workaround for systems not providing PATH_MAX, like GNU/Hurd
+
+dnl EFL_CHECK_PATH_MAX([DEFAULT_VALUE_IF_NOT_FOUND])
+dnl
+dnl If PATH_MAX is not defined in <limits.h>, defines it
+dnl to DEFAULT_VALUE_IF_NOT_FOUND if it exists, or fallback
+dnl to using 4096
+
+AC_DEFUN([EFL_CHECK_PATH_MAX],
+[
+
+default_max=m4_default([$1], "4096")
+AC_LANG_PUSH([C])
+
+AC_MSG_CHECKING([for PATH_MAX in limits.h])
+AC_COMPILE_IFELSE(
+   [AC_LANG_PROGRAM(
+       [[
+#include <limits.h>
+       ]],
+       [[
+int i = PATH_MAX;
+       ]])],
+   [AC_MSG_RESULT([yes])],
+   [
+    AC_DEFINE_UNQUOTED([PATH_MAX],
+       [${default_max}],
+       [default value since PATH_MAX is not defined])
+    AC_MSG_RESULT([no: using ${default_max}])
+   ])
+
+AC_LANG_POP([C])
+
+])
+dnl end of efl_path_max.m4
diff --git a/src/.cvsignore b/src/.cvsignore
new file mode 100644 (file)
index 0000000..282522d
--- /dev/null
@@ -0,0 +1,2 @@
+Makefile
+Makefile.in
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644 (file)
index 0000000..7b45af6
--- /dev/null
@@ -0,0 +1,3 @@
+## Process this file with automake to produce Makefile.in
+
+SUBDIRS = lib bin
diff --git a/src/bin/.cvsignore b/src/bin/.cvsignore
new file mode 100644 (file)
index 0000000..93f5fa1
--- /dev/null
@@ -0,0 +1,10 @@
+.deps
+.libs
+Makefile
+Makefile.in
+edje
+edje_ls
+edje_cc
+edje_decc
+edje_test
+edje_thumb
diff --git a/src/bin/Makefile.am b/src/bin/Makefile.am
new file mode 100644 (file)
index 0000000..4a9d6b5
--- /dev/null
@@ -0,0 +1,49 @@
+
+MAINTAINERCLEANFILES = Makefile.in
+
+AM_CPPFLAGS = \
+-I$(top_srcdir) \
+-I$(top_srcdir)/src/bin \
+-I$(top_srcdir)/src/lib \
+-DPACKAGE_BIN_DIR=\"$(bindir)\" \
+-DPACKAGE_LIB_DIR=\"$(libdir)\" \
+-DPACKAGE_DATA_DIR=\"$(datadir)/$(PACKAGE)\" \
+@EDJE_CFLAGS@ \
+@ECORE_EVAS_CFLAGS@ \
+@ECORE_FILE_CFLAGS@ \
+@EVIL_CFLAGS@
+
+bin_SCRIPTS = @EDJE_RECC_PRG@
+
+bin_PROGRAMS = @EDJE_CC_PRG@ @EDJE_DECC_PRG@ @EDJE_PLAYER_PRG@
+
+EXTRA_PROGRAMS = edje_cc edje_decc edje_player
+
+edje_cc_SOURCES = \
+edje_cc.c \
+edje_cc_out.c \
+edje_cc_parse.c \
+edje_cc_mem.c \
+edje_cc_handlers.c \
+edje_cc_sources.c \
+edje_prefix.c
+
+edje_cc_LDADD = $(top_builddir)/src/lib/libedje.la $(ECORE_EVAS_LIBS) $(EVIL_LIBS)
+edje_cc_LDFLAGS = @lt_enable_auto_import@
+
+
+edje_decc_SOURCES = \
+edje_decc.c \
+edje_decc.h \
+edje_cc_mem.c \
+edje_cc_sources.c
+
+edje_decc_LDADD = $(top_builddir)/src/lib/libedje.la $(ECORE_EVAS_LIBS) $(ECORE_FILE_LIBS)
+edje_decc_LDFLAGS = @lt_enable_auto_import@
+
+edje_player_SOURCES = edje_player.c
+edje_player_LDADD = $(top_builddir)/src/lib/libedje.la $(ECORE_EVAS_LIBS) $(EVIL_LIBS)
+edje_player_LDFLAGS = @lt_enable_auto_import@
+
+EXTRA_DIST = @EDJE_RECC_PRG@ edje_prefix.h edje_cc.h
+EXTRA_SCRIPTS = edje_recc
diff --git a/src/bin/edje_cc.c b/src/bin/edje_cc.c
new file mode 100644 (file)
index 0000000..b86ea8a
--- /dev/null
@@ -0,0 +1,226 @@
+/*
+ * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <string.h>
+#include <locale.h>
+#include <limits.h>
+#include <sys/stat.h>
+
+#include "edje_cc.h"
+#include "edje_prefix.h"
+int _edje_cc_log_dom = -1;
+static void main_help(void);
+
+Eina_List *img_dirs = NULL;
+Eina_List *fnt_dirs = NULL;
+Eina_List *defines = NULL;
+char      *file_in = NULL;
+char      *tmp_dir = NULL;
+char      *file_out = NULL;
+char      *progname = NULL;
+int        verbose = 0;
+
+int        no_lossy = 0;
+int        no_comp = 0;
+int        no_raw = 0;
+int        min_quality = 0;
+int        max_quality = 100;
+
+static void
+main_help(void)
+{
+   printf
+     ("Usage:\n"
+      "\t%s [OPTIONS] input_file.edc [output_file.edj]\n"
+      "\n"
+      "Where OPTIONS is one or more of:\n"
+      "\n"
+      "-id image/directory      Add a directory to look in for relative path images\n"
+      "-fd font/directory       Add a directory to look in for relative path fonts\n"
+      "-td temp/directory       Directory to store temporary files\n"
+      "-v                       Verbose output\n"
+      "-no-lossy                Do NOT allow images to be lossy\n"
+      "-no-comp                 Do NOT allow images to be stored with lossless compression\n"
+      "-no-raw                  Do NOT allow images to be stored with zero compression (raw)\n"
+      "-min-quality VAL         Do NOT allow lossy images with quality < VAL (0-100)\n"
+      "-max-quality VAL         Do NOT allow lossy images with quality > VAL (0-100)\n"
+      "-Ddefine_val=to          CPP style define to define input macro definitions to the .edc source\n"
+      ,progname);
+}
+
+int
+main(int argc, char **argv)
+{
+   int i;
+   struct stat st;
+   char rpath[PATH_MAX], rpath2[PATH_MAX];
+
+   setlocale(LC_NUMERIC, "C");
+
+   if (!eina_init())
+     return -1;
+
+   _edje_cc_log_dom = eina_log_domain_register("EDJE_CC", EDJE_DEFAULT_LOG_COLOR);
+   if(_edje_cc_log_dom<0)
+     {
+       EINA_LOG_ERR("Enable to create a log domain.");
+       exit(-1);
+     }
+   tmp_dir = getenv("TMPDIR");
+
+   img_dirs = eina_list_append(img_dirs, ".");
+
+   progname = argv[0];
+   for (i = 1; i < argc; i++)
+     {
+       if (!strcmp(argv[i], "-h"))
+         {
+            main_help();
+            exit(0);
+         }
+       else if (!strcmp(argv[i], "-v"))
+         {
+            verbose = 1;
+         }
+       else if (!strcmp(argv[i], "-no-lossy"))
+         {
+            no_lossy = 1;
+         }
+       else if (!strcmp(argv[i], "-no-comp"))
+         {
+            no_comp = 1;
+         }
+       else if (!strcmp(argv[i], "-no-raw"))
+         {
+            no_raw = 1;
+         }
+       else if ((!strcmp(argv[i], "-id") || !strcmp(argv[i], "--image_dir")) && (i < (argc - 1)))
+         {
+            i++;
+            img_dirs = eina_list_append(img_dirs, argv[i]);
+         }
+       else if ((!strcmp(argv[i], "-fd") || !strcmp(argv[i], "--font_dir")) && (i < (argc - 1)))
+         {
+            i++;
+            fnt_dirs = eina_list_append(fnt_dirs, argv[i]);
+         }
+       else if ((!strcmp(argv[i], "-td") || !strcmp(argv[i], "--tmp_dir")) && (i < (argc - 1)))
+         {
+            i++;
+             if (!tmp_dir)
+               tmp_dir = argv[i];
+         }
+       else if ((!strcmp(argv[i], "-min-quality")) && (i < (argc - 1)))
+         {
+            i++;
+            min_quality = atoi(argv[i]);
+            if (min_quality < 0) min_quality = 0;
+            if (min_quality > 100) min_quality = 100;
+         }
+       else if ((!strcmp(argv[i], "-max-quality")) && (i < (argc - 1)))
+         {
+            i++;
+            max_quality = atoi(argv[i]);
+            if (max_quality < 0) max_quality = 0;
+            if (max_quality > 100) max_quality = 100;
+         }
+       else if (!strncmp(argv[i], "-D", 2))
+         {
+            defines = eina_list_append(defines, mem_strdup(argv[i]));
+         }
+       else if ((!strcmp(argv[i], "-o")) && (i < (argc - 1)))
+         {
+            i++;
+            file_out = argv[i];
+         }
+       else if (!file_in)
+         file_in = argv[i];
+       else if (!file_out)
+         file_out = argv[i];
+     }
+   if (!file_in)
+     {
+       fprintf(stderr, "%s: Error: no input file specified.\n", progname);
+       main_help();
+       exit(-1);
+     }
+
+   e_prefix_determine(argv[0]);
+
+   /* check whether file_in exists */
+#ifdef HAVE_REALPATH
+   if (!realpath(file_in, rpath) || stat(rpath, &st) || !S_ISREG(st.st_mode))
+#else
+   if (stat(file_in, &st) || !S_ISREG(st.st_mode))
+#endif
+     {
+       fprintf(stderr, "%s: Error: file not found: %s.\n", progname, file_in);
+       main_help();
+       exit(-1);
+     }
+
+   if (!file_out)
+      {
+         char *suffix;
+
+         if ((suffix = strstr(file_in,".edc")) && (suffix[4] == 0))
+            {
+               file_out = strdup(file_in);
+               if (file_out)
+                  {
+                     suffix = strstr(file_out,".edc");
+                     strcpy(suffix,".edj");
+                  }
+            }
+      }
+   if (!file_out)
+     {
+       fprintf(stderr, "%s: Error: no output file specified.\n", progname);
+       main_help();
+       exit(-1);
+     }
+
+#ifdef HAVE_REALPATH
+   if (realpath(file_out, rpath2) && !strcmp (rpath, rpath2))
+#else
+   if (!strcmp (file_in, file_out))
+#endif
+     {
+       fprintf(stderr, "%s: Error: input file equals output file.\n", progname);
+       main_help();
+       exit(-1);
+     }
+
+   if (!edje_init())
+     exit(-1);
+
+   edje_file = mem_alloc(SZ(Edje_File));
+   edje_file->compiler = strdup("edje_cc");
+   edje_file->version = EDJE_FILE_VERSION;
+   edje_file->feature_ver = 1; /* increment this every time we add a field
+                               * or feature to the edje file format that
+                               * does not load nicely as a NULL or 0 value
+                               * and needs a special fallback initialization
+                               */
+
+   source_edd();
+   source_fetch();
+
+   data_setup();
+   compile();
+   data_process_scripts();
+   data_process_lookups();
+   data_process_script_lookups();
+   data_write();
+
+   edje_shutdown();
+   eina_log_domain_unregister(_edje_cc_log_dom);
+   eina_shutdown();
+
+   return 0;
+}
diff --git a/src/bin/edje_cc.h b/src/bin/edje_cc.h
new file mode 100644 (file)
index 0000000..828c6cd
--- /dev/null
@@ -0,0 +1,180 @@
+#ifndef EDJE_CC_H
+#define EDJE_CC_H
+
+#include <edje_private.h>
+
+/*
+ * On Windows, if the file is not opened in binary mode,
+ * read does not return the correct size, because of
+ * CR / LF translation.
+ */
+#ifndef O_BINARY
+# define O_BINARY 0
+#endif
+
+/* logging variables */
+extern int _edje_cc_log_dom ;
+#define EDJE_CC_DEFAULT_LOG_COLOR EINA_COLOR_CYAN
+#ifdef ERR
+# undef ERR
+#endif
+#define ERR(...) EINA_LOG_DOM_ERR(_edje_cc_log_dom, __VA_ARGS__)
+#ifdef INF
+# undef INF
+#endif
+#define INF(...) EINA_LOG_DOM_INFO(_edje_cc_log_dom, __VA_ARGS__)
+#ifdef WRN
+# undef WRN
+#endif
+#define WRN(...) EINA_LOG_DOM_WARN(_edje_cc_log_dom, __VA_ARGS__)
+
+
+/* types */
+typedef struct _New_Object_Handler    New_Object_Handler;
+typedef struct _New_Statement_Handler New_Statement_Handler;
+typedef struct _External_List         External_List;
+typedef struct _External              External;
+typedef struct _Font_List             Font_List;
+typedef struct _Font                  Font;
+typedef struct _Code                  Code;
+typedef struct _Code_Program          Code_Program;
+typedef struct _SrcFile               SrcFile;
+typedef struct _SrcFile_List          SrcFile_List;
+
+struct _New_Object_Handler
+{
+   const char *type;
+   void (*func)(void);
+};
+
+struct _New_Statement_Handler
+{
+   const char *type;
+   void (*func)(void);
+};
+
+struct _External_List
+{
+   Eina_List *list;
+};
+
+struct _External
+{
+    char *name;
+};
+
+struct _Font_List
+{
+   Eina_List *list;
+};
+
+struct _Font
+{
+   char *file;
+   char *name;
+};
+
+struct _Code
+{
+   int       l1, l2;
+   char      *shared;
+   Eina_List *programs;
+   int         is_lua;
+};
+
+struct _Code_Program
+{
+   int        l1, l2;
+   int        id;
+   char      *script;
+};
+
+struct _SrcFile
+{
+   char *name;
+   char *file;
+};
+
+struct _SrcFile_List
+{
+   Eina_List *list;
+};
+
+/* global fn calls */
+void    data_setup(void);
+void    data_write(void);
+void    data_queue_part_lookup(Edje_Part_Collection *pc, char *name, int *dest);
+void    data_queue_program_lookup(Edje_Part_Collection *pc, char *name, int *dest);
+void    data_queue_image_lookup(char *name, int *dest);
+void    data_queue_part_slave_lookup(int *master, int *slave);
+void    data_queue_image_slave_lookup(int *master, int *slave);
+void    data_queue_spectrum_lookup(char *name, int *dest);
+void    data_queue_spectrum_slave_lookup(int *master, int *slave);
+void    data_process_lookups(void);
+void    data_process_scripts(void);
+void    data_process_script_lookups(void);
+
+
+int     is_verbatim(void);
+void    track_verbatim(int on);
+void    set_verbatim(char *s, int l1, int l2);
+char   *get_verbatim(void);
+int     get_verbatim_line1(void);
+int     get_verbatim_line2(void);
+void    compile(void);
+int     is_param(int n);
+int     is_num(int n);
+char   *parse_str(int n);
+int     parse_enum(int n, ...);
+int     parse_flags(int n, ...);
+int     parse_int(int n);
+int     parse_int_range(int n, int f, int t);
+int     parse_bool(int n);
+double  parse_float(int n);
+double  parse_float_range(int n, double f, double t);
+void    check_arg_count(int n);
+void    check_min_arg_count(int n);
+
+int     object_handler_num(void);
+int     statement_handler_num(void);
+
+void    source_edd(void);
+void    source_fetch(void);
+int     source_append(Eet_File *ef);
+SrcFile_List *source_load(Eet_File *ef);
+int     source_fontmap_save(Eet_File *ef, Eina_List *fonts);
+Font_List *source_fontmap_load(Eet_File *ef);
+
+void   *mem_alloc(size_t size);
+char   *mem_strdup(const char *s);
+#define SZ sizeof
+
+/* global vars */
+extern Eina_List             *ext_dirs;
+extern Eina_List             *img_dirs;
+extern Eina_List             *fnt_dirs;
+extern char                  *file_in;
+extern char                  *tmp_dir;
+extern char                  *file_out;
+extern char                  *progname;
+extern int                    verbose;
+extern int                    no_lossy;
+extern int                    no_comp;
+extern int                    no_raw;
+extern int                    min_quality;
+extern int                    max_quality;
+extern int                    line;
+extern Eina_List             *stack;
+extern Eina_List             *params;
+extern Edje_File             *edje_file;
+extern Eina_List             *edje_collections;
+extern Eina_List             *externals;
+extern Eina_List             *fonts;
+extern Eina_List             *codes;
+extern Eina_List             *defines;
+extern Eina_List             *aliases;
+extern New_Object_Handler     object_handlers[];
+extern New_Statement_Handler  statement_handlers[];
+
+
+#endif
diff --git a/src/bin/edje_cc_handlers.c b/src/bin/edje_cc_handlers.c
new file mode 100644 (file)
index 0000000..c10d89e
--- /dev/null
@@ -0,0 +1,6949 @@
+/*
+ * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
+ */
+
+/*
+    Concerning the EDC reference:
+
+    The formatting for blocks and properties has been implemented as a table
+    which is filled using ALIASES.
+    For maximum flexibility I implemented them in the \@code/\@encode style,
+    this means that missing one or changing the order most certainly cause
+    formatting errors.
+
+    \@block
+        block name
+    \@context
+        code sample of the block
+    \@description
+        the block's description
+    \@endblock
+
+    \@property
+        property name
+    \@parameters
+        property's parameter list
+    \@effect
+        the property description (lol)
+    \@endproperty
+*/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <string.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <unistd.h>
+
+#include "edje_cc.h"
+
+/**
+ * @page edcref Edje Data Collection reference
+ * An Edje Data Collection, it's a plain text file (normally identified with the
+ * .edc extension),consisting of instructions for the Edje Compiler.
+ *
+ * The syntax for the edje data collection files follows a simple structure of
+ * "blocks { .. }" that can contain "properties: ..", more blocks, or both.
+ *
+ * @anchor sec_quickaccess Quick access to block descriptions:
+ * <ul>
+ *    <li>@ref sec_toplevel "Top-Level"</li>
+ *    <li>@ref sec_group "Group"</li>
+ *    <li>@ref sec_description "State description"</li>
+ *    <ul>
+ *      <li>@ref sec_description_image "Image"</li>
+ *      <li>@ref sec_description_text "Text"</li>
+ *      <li>@ref sec_description_gradient "Gradient"</li>
+ *      <li>@ref sec_description_box "Box"</li>
+ *      <li>@ref sec_description_table "Table"</li>
+ *      <li>@ref sec_description_map "Map (3d/transformations)"</li>
+ *    </ul>
+ *    <li>@ref sec_program "Program block"</li>
+ * </ul>
+ *
+ * @author Andres Blanc (dresb) andresblanc@gmail.com
+ *
+ * <table class="edcref" border="0">
+ */
+
+static void st_externals_external(void);
+
+static void st_images_image(void);
+
+static void st_fonts_font(void);
+
+static void st_data_item(void);
+static void st_data_file(void);
+
+static void ob_styles_style(void);
+static void st_styles_style_name(void);
+static void st_styles_style_base(void);
+static void st_styles_style_tag(void);
+
+static void ob_color_class(void);
+static void st_color_class_name(void);
+static void st_color_class_color(void);
+static void st_color_class_color2(void);
+static void st_color_class_color3(void);
+
+static void ob_spectrum(void);
+/*static void st_spectrum(void);*/
+static void st_spectrum_name(void);
+static void st_spectrum_color(void);
+
+static void ob_collections(void);
+
+static void ob_collections_group(void);
+static void st_collections_group_name(void);
+static void st_collections_group_script_only(void);
+static void st_collections_group_lua_script_only(void);
+static void st_collections_group_alias(void);
+static void st_collections_group_min(void);
+static void st_collections_group_max(void);
+static void st_collections_group_data_item(void);
+
+static void ob_collections_group_script(void);
+static void ob_collections_group_lua_script(void);
+
+static void ob_collections_group_parts_part(void);
+static void st_collections_group_parts_part_name(void);
+static void st_collections_group_parts_part_type(void);
+static void st_collections_group_parts_part_effect(void);
+static void st_collections_group_parts_part_mouse_events(void);
+static void st_collections_group_parts_part_repeat_events(void);
+static void st_collections_group_parts_part_ignore_flags(void);
+static void st_collections_group_parts_part_scale(void);
+static void st_collections_group_parts_part_pointer_mode(void);
+static void st_collections_group_parts_part_precise_is_inside(void);
+static void st_collections_group_parts_part_use_alternate_font_metrics(void);
+static void st_collections_group_parts_part_clip_to_id(void);
+static void st_collections_group_parts_part_source(void);
+static void st_collections_group_parts_part_source2(void);
+static void st_collections_group_parts_part_source3(void);
+static void st_collections_group_parts_part_source4(void);
+static void st_collections_group_parts_part_source5(void);
+static void st_collections_group_parts_part_source6(void);
+static void st_collections_group_parts_part_entry_mode(void);
+static void st_collections_group_parts_part_select_mode(void);
+static void st_collections_group_parts_part_multiline(void);
+static void st_collections_group_parts_part_dragable_x(void);
+static void st_collections_group_parts_part_dragable_y(void);
+static void st_collections_group_parts_part_dragable_confine(void);
+static void st_collections_group_parts_part_dragable_events(void);
+
+/* box and table items share these */
+static void ob_collections_group_parts_part_box_items_item(void);
+static void st_collections_group_parts_part_box_items_item_type(void);
+static void st_collections_group_parts_part_box_items_item_name(void);
+static void st_collections_group_parts_part_box_items_item_source(void);
+static void st_collections_group_parts_part_box_items_item_min(void);
+static void st_collections_group_parts_part_box_items_item_prefer(void);
+static void st_collections_group_parts_part_box_items_item_max(void);
+static void st_collections_group_parts_part_box_items_item_padding(void);
+static void st_collections_group_parts_part_box_items_item_align(void);
+static void st_collections_group_parts_part_box_items_item_weight(void);
+static void st_collections_group_parts_part_box_items_item_aspect(void);
+static void st_collections_group_parts_part_box_items_item_aspect_mode(void);
+static void st_collections_group_parts_part_box_items_item_options(void);
+/* but these are only for table */
+static void st_collections_group_parts_part_table_items_item_position(void);
+static void st_collections_group_parts_part_table_items_item_span(void);
+
+static void ob_collections_group_parts_part_description(void);
+static void st_collections_group_parts_part_description_inherit(void);
+static void st_collections_group_parts_part_description_state(void);
+static void st_collections_group_parts_part_description_visible(void);
+static void st_collections_group_parts_part_description_align(void);
+static void st_collections_group_parts_part_description_fixed(void);
+static void st_collections_group_parts_part_description_min(void);
+static void st_collections_group_parts_part_description_max(void);
+static void st_collections_group_parts_part_description_step(void);
+static void st_collections_group_parts_part_description_aspect(void);
+static void st_collections_group_parts_part_description_aspect_preference(void);
+static void st_collections_group_parts_part_description_rel1_relative(void);
+static void st_collections_group_parts_part_description_rel1_offset(void);
+static void st_collections_group_parts_part_description_rel1_to(void);
+static void st_collections_group_parts_part_description_rel1_to_x(void);
+static void st_collections_group_parts_part_description_rel1_to_y(void);
+static void st_collections_group_parts_part_description_rel2_relative(void);
+static void st_collections_group_parts_part_description_rel2_offset(void);
+static void st_collections_group_parts_part_description_rel2_to(void);
+static void st_collections_group_parts_part_description_rel2_to_x(void);
+static void st_collections_group_parts_part_description_rel2_to_y(void);
+static void st_collections_group_parts_part_description_image_normal(void);
+static void st_collections_group_parts_part_description_image_tween(void);
+static void st_collections_group_parts_part_description_image_border(void);
+static void st_collections_group_parts_part_description_image_middle(void);
+static void st_collections_group_parts_part_description_image_border_scale(void);
+static void st_collections_group_parts_part_description_image_scale_hint(void);
+static void st_collections_group_parts_part_description_fill_smooth(void);
+static void st_collections_group_parts_part_description_fill_origin_relative(void);
+static void st_collections_group_parts_part_description_fill_origin_offset(void);
+static void st_collections_group_parts_part_description_fill_size_relative(void);
+static void st_collections_group_parts_part_description_fill_size_offset(void);
+static void st_collections_group_parts_part_description_fill_angle(void);
+static void st_collections_group_parts_part_description_fill_spread(void);
+static void st_collections_group_parts_part_description_fill_type(void);
+static void st_collections_group_parts_part_description_color_class(void);
+static void st_collections_group_parts_part_description_color(void);
+static void st_collections_group_parts_part_description_color2(void);
+static void st_collections_group_parts_part_description_color3(void);
+static void st_collections_group_parts_part_description_text_text(void);
+static void st_collections_group_parts_part_description_text_text_class(void);
+static void st_collections_group_parts_part_description_text_font(void);
+static void st_collections_group_parts_part_description_text_style(void);
+static void st_collections_group_parts_part_description_text_repch(void);
+static void st_collections_group_parts_part_description_text_size(void);
+static void st_collections_group_parts_part_description_text_fit(void);
+static void st_collections_group_parts_part_description_text_min(void);
+static void st_collections_group_parts_part_description_text_max(void);
+static void st_collections_group_parts_part_description_text_align(void);
+static void st_collections_group_parts_part_description_text_source(void);
+static void st_collections_group_parts_part_description_text_text_source(void);
+static void st_collections_group_parts_part_description_text_elipsis(void);
+static void st_collections_group_parts_part_description_gradient_type(void);
+static void st_collections_group_parts_part_description_gradient_spectrum(void);
+static void st_collections_group_parts_part_description_gradient_rel1_relative(void);
+static void st_collections_group_parts_part_description_gradient_rel1_offset(void);
+static void st_collections_group_parts_part_description_gradient_rel2_relative(void);
+static void st_collections_group_parts_part_description_gradient_rel2_offset(void);
+static void st_collections_group_parts_part_description_box_layout(void);
+static void st_collections_group_parts_part_description_box_align(void);
+static void st_collections_group_parts_part_description_box_padding(void);
+static void st_collections_group_parts_part_description_box_min(void);
+static void st_collections_group_parts_part_description_table_homogeneous(void);
+static void st_collections_group_parts_part_description_table_align(void);
+static void st_collections_group_parts_part_description_table_padding(void);
+static void st_collections_group_parts_part_description_map_perspective(void);
+static void st_collections_group_parts_part_description_map_light(void);
+static void st_collections_group_parts_part_description_map_rotation_center(void);
+static void st_collections_group_parts_part_description_map_rotation_x(void);
+static void st_collections_group_parts_part_description_map_rotation_y(void);
+static void st_collections_group_parts_part_description_map_rotation_z(void);
+static void st_collections_group_parts_part_description_map_on(void);
+static void st_collections_group_parts_part_description_map_smooth(void);
+static void st_collections_group_parts_part_description_map_alpha(void);
+static void st_collections_group_parts_part_description_map_backface_cull(void);
+static void st_collections_group_parts_part_description_map_perspective_on(void);
+static void st_collections_group_parts_part_description_perspective_zplane(void);
+static void st_collections_group_parts_part_description_perspective_focal(void);
+static void st_collections_group_parts_part_api(void);
+
+/* external part parameters */
+static void st_collections_group_parts_part_description_params_int(void);
+static void ob_collections_group_programs_program(void);
+static void st_collections_group_parts_part_description_params_double(void);
+
+static void st_collections_group_programs_program_name(void);
+static void st_collections_group_parts_part_description_params_string(void);
+static void st_collections_group_parts_part_description_params_bool(void);
+static void st_collections_group_parts_part_description_params_choice(void);
+static void st_collections_group_programs_program_signal(void);
+static void st_collections_group_programs_program_source(void);
+static void st_collections_group_programs_program_filter(void);
+static void st_collections_group_programs_program_in(void);
+static void st_collections_group_programs_program_action(void);
+static void st_collections_group_programs_program_transition(void);
+static void st_collections_group_programs_program_target(void);
+static void st_collections_group_programs_program_after(void);
+static void st_collections_group_programs_program_api(void);
+
+static void ob_collections_group_programs_program_script(void);
+static void ob_collections_group_programs_program_lua_script(void);
+
+/*****/
+
+New_Statement_Handler statement_handlers[] =
+{
+     {"externals.external", st_externals_external},
+     {"images.image", st_images_image},
+     {"fonts.font", st_fonts_font},
+     {"data.item", st_data_item},
+     {"data.file", st_data_file},
+     {"styles.style.name", st_styles_style_name},
+     {"styles.style.base", st_styles_style_base},
+     {"styles.style.tag", st_styles_style_tag},
+     {"color_classes.color_class.name", st_color_class_name},
+     {"color_classes.color_class.color", st_color_class_color},
+     {"color_classes.color_class.color2", st_color_class_color2},
+     {"color_classes.color_class.color3", st_color_class_color3},
+     /*{"spectra.spectrum", st_spectrum},*/
+     {"spectra.spectrum.name", st_spectrum_name},
+     {"spectra.spectrum.color", st_spectrum_color},
+     {"collections.externals.external", st_externals_external}, /* dup */
+     {"collections.image", st_images_image}, /* dup */
+     {"collections.images.image", st_images_image}, /* dup */
+     {"collections.font", st_fonts_font}, /* dup */
+     {"collections.fonts.font", st_fonts_font}, /* dup */
+     {"collections.styles.style.name", st_styles_style_name}, /* dup */
+     {"collections.styles.style.base", st_styles_style_base}, /* dup */
+     {"collections.styles.style.tag", st_styles_style_tag}, /* dup */
+     {"collections.color_classes.color_class.name", st_color_class_name}, /* dup */
+     {"collections.color_classes.color_class.color", st_color_class_color}, /* dup */
+     {"collections.color_classes.color_class.color2", st_color_class_color2}, /* dup */
+     {"collections.color_classes.color_class.color3", st_color_class_color3}, /* dup */
+     {"collections.group.name", st_collections_group_name},
+     {"collections.group.script_only", st_collections_group_script_only},
+     {"collections.group.lua_script_only", st_collections_group_lua_script_only},
+     {"collections.group.alias", st_collections_group_alias},
+     {"collections.group.min", st_collections_group_min},
+     {"collections.group.max", st_collections_group_max},
+     {"collections.group.data.item", st_collections_group_data_item},
+     {"collections.group.externals.external", st_externals_external}, /* dup */
+     {"collections.group.image", st_images_image}, /* dup */
+     {"collections.group.images.image", st_images_image}, /* dup */
+     {"collections.group.font", st_fonts_font}, /* dup */
+     {"collections.group.fonts.font", st_fonts_font}, /* dup */
+     {"collections.group.styles.style.name", st_styles_style_name}, /* dup */
+     {"collections.group.styles.style.base", st_styles_style_base}, /* dup */
+     {"collections.group.styles.style.tag", st_styles_style_tag}, /* dup */
+     {"collections.group.color_classes.color_class.name", st_color_class_name}, /* dup */
+     {"collections.group.color_classes.color_class.color", st_color_class_color}, /* dup */
+     {"collections.group.color_classes.color_class.color2", st_color_class_color2}, /* dup */
+     {"collections.group.color_classes.color_class.color3", st_color_class_color3}, /* dup */
+     {"collections.group.parts.image", st_images_image}, /* dup */
+     {"collections.group.parts.images.image", st_images_image}, /* dup */
+     {"collections.group.parts.font", st_fonts_font}, /* dup */
+     {"collections.group.parts.fonts.font", st_fonts_font}, /* dup */
+     {"collections.group.parts.styles.style.name", st_styles_style_name}, /* dup */
+     {"collections.group.parts.styles.style.base", st_styles_style_base}, /* dup */
+     {"collections.group.parts.styles.style.tag", st_styles_style_tag}, /* dup */
+     {"collections.group.parts.color_classes.color_class.name", st_color_class_name}, /* dup */
+     {"collections.group.parts.color_classes.color_class.color", st_color_class_color}, /* dup */
+     {"collections.group.parts.color_classes.color_class.color2", st_color_class_color2}, /* dup */
+     {"collections.group.parts.color_classes.color_class.color3", st_color_class_color3}, /* dup */
+     {"collections.group.parts.part.name", st_collections_group_parts_part_name},
+     {"collections.group.parts.part.api", st_collections_group_parts_part_api},
+     {"collections.group.parts.part.type", st_collections_group_parts_part_type},
+     {"collections.group.parts.part.effect", st_collections_group_parts_part_effect},
+     {"collections.group.parts.part.mouse_events", st_collections_group_parts_part_mouse_events},
+     {"collections.group.parts.part.repeat_events", st_collections_group_parts_part_repeat_events},
+     {"collections.group.parts.part.ignore_flags", st_collections_group_parts_part_ignore_flags},
+     {"collections.group.parts.part.scale", st_collections_group_parts_part_scale},
+     {"collections.group.parts.part.pointer_mode", st_collections_group_parts_part_pointer_mode},
+     {"collections.group.parts.part.precise_is_inside", st_collections_group_parts_part_precise_is_inside},
+     {"collections.group.parts.part.use_alternate_font_metrics", st_collections_group_parts_part_use_alternate_font_metrics},
+     {"collections.group.parts.part.clip_to", st_collections_group_parts_part_clip_to_id},
+     {"collections.group.parts.part.source", st_collections_group_parts_part_source},
+     {"collections.group.parts.part.source2", st_collections_group_parts_part_source2},
+     {"collections.group.parts.part.source3", st_collections_group_parts_part_source3},
+     {"collections.group.parts.part.source4", st_collections_group_parts_part_source4},
+     {"collections.group.parts.part.source5", st_collections_group_parts_part_source5},
+     {"collections.group.parts.part.source6", st_collections_group_parts_part_source6},
+     {"collections.group.parts.part.dragable.x", st_collections_group_parts_part_dragable_x},
+     {"collections.group.parts.part.dragable.y", st_collections_group_parts_part_dragable_y},
+     {"collections.group.parts.part.dragable.confine", st_collections_group_parts_part_dragable_confine},
+     {"collections.group.parts.part.dragable.events", st_collections_group_parts_part_dragable_events},
+     {"collections.group.parts.part.entry_mode", st_collections_group_parts_part_entry_mode},
+     {"collections.group.parts.part.select_mode", st_collections_group_parts_part_select_mode},
+     {"collections.group.parts.part.multiline", st_collections_group_parts_part_multiline},
+     {"collections.group.parts.part.image", st_images_image}, /* dup */
+     {"collections.group.parts.part.images.image", st_images_image}, /* dup */
+     {"collections.group.parts.part.font", st_fonts_font}, /* dup */
+     {"collections.group.parts.part.fonts.font", st_fonts_font}, /* dup */
+     {"collections.group.parts.part.styles.style.name", st_styles_style_name}, /* dup */
+     {"collections.group.parts.part.styles.style.base", st_styles_style_base}, /* dup */
+     {"collections.group.parts.part.styles.style.tag", st_styles_style_tag}, /* dup */
+     {"collections.group.parts.part.color_classes.color_class.name", st_color_class_name}, /* dup */
+     {"collections.group.parts.part.color_classes.color_class.color", st_color_class_color}, /* dup */
+     {"collections.group.parts.part.color_classes.color_class.color2", st_color_class_color2}, /* dup */
+     {"collections.group.parts.part.color_classes.color_class.color3", st_color_class_color3}, /* dup */
+     {"collections.group.parts.part.box.items.item.type", st_collections_group_parts_part_box_items_item_type},
+     {"collections.group.parts.part.box.items.item.name", st_collections_group_parts_part_box_items_item_name},
+     {"collections.group.parts.part.box.items.item.source", st_collections_group_parts_part_box_items_item_source},
+     {"collections.group.parts.part.box.items.item.min", st_collections_group_parts_part_box_items_item_min},
+     {"collections.group.parts.part.box.items.item.prefer", st_collections_group_parts_part_box_items_item_prefer},
+     {"collections.group.parts.part.box.items.item.max", st_collections_group_parts_part_box_items_item_max},
+     {"collections.group.parts.part.box.items.item.padding", st_collections_group_parts_part_box_items_item_padding},
+     {"collections.group.parts.part.box.items.item.align", st_collections_group_parts_part_box_items_item_align},
+     {"collections.group.parts.part.box.items.item.weight", st_collections_group_parts_part_box_items_item_weight},
+     {"collections.group.parts.part.box.items.item.aspect", st_collections_group_parts_part_box_items_item_aspect},
+     {"collections.group.parts.part.box.items.item.aspect_mode", st_collections_group_parts_part_box_items_item_aspect_mode},
+     {"collections.group.parts.part.box.items.item.options", st_collections_group_parts_part_box_items_item_options},
+     {"collections.group.parts.part.table.items.item.type", st_collections_group_parts_part_box_items_item_type}, /* dup */
+     {"collections.group.parts.part.table.items.item.name", st_collections_group_parts_part_box_items_item_name}, /* dup */
+     {"collections.group.parts.part.table.items.item.source", st_collections_group_parts_part_box_items_item_source}, /* dup */
+     {"collections.group.parts.part.table.items.item.min", st_collections_group_parts_part_box_items_item_min}, /* dup */
+     {"collections.group.parts.part.table.items.item.prefer", st_collections_group_parts_part_box_items_item_prefer}, /* dup */
+     {"collections.group.parts.part.table.items.item.max", st_collections_group_parts_part_box_items_item_max}, /* dup */
+     {"collections.group.parts.part.table.items.item.padding", st_collections_group_parts_part_box_items_item_padding}, /* dup */
+     {"collections.group.parts.part.table.items.item.align", st_collections_group_parts_part_box_items_item_align}, /* dup */
+     {"collections.group.parts.part.table.items.item.weight", st_collections_group_parts_part_box_items_item_weight}, /* dup */
+     {"collections.group.parts.part.table.items.item.aspect", st_collections_group_parts_part_box_items_item_aspect}, /* dup */
+     {"collections.group.parts.part.table.items.item.aspect_mode", st_collections_group_parts_part_box_items_item_aspect_mode}, /* dup */
+     {"collections.group.parts.part.table.items.item.options", st_collections_group_parts_part_box_items_item_options}, /* dup */
+     {"collections.group.parts.part.table.items.item.position", st_collections_group_parts_part_table_items_item_position},
+     {"collections.group.parts.part.table.items.item.span", st_collections_group_parts_part_table_items_item_span},
+     {"collections.group.parts.part.description.inherit", st_collections_group_parts_part_description_inherit},
+     {"collections.group.parts.part.description.state", st_collections_group_parts_part_description_state},
+     {"collections.group.parts.part.description.visible", st_collections_group_parts_part_description_visible},
+     {"collections.group.parts.part.description.align", st_collections_group_parts_part_description_align},
+     {"collections.group.parts.part.description.fixed", st_collections_group_parts_part_description_fixed},
+     {"collections.group.parts.part.description.min", st_collections_group_parts_part_description_min},
+     {"collections.group.parts.part.description.max", st_collections_group_parts_part_description_max},
+     {"collections.group.parts.part.description.step", st_collections_group_parts_part_description_step},
+     {"collections.group.parts.part.description.aspect", st_collections_group_parts_part_description_aspect},
+     {"collections.group.parts.part.description.aspect_preference", st_collections_group_parts_part_description_aspect_preference},
+     {"collections.group.parts.part.description.rel1.relative", st_collections_group_parts_part_description_rel1_relative},
+     {"collections.group.parts.part.description.rel1.offset", st_collections_group_parts_part_description_rel1_offset},
+     {"collections.group.parts.part.description.rel1.to", st_collections_group_parts_part_description_rel1_to},
+     {"collections.group.parts.part.description.rel1.to_x", st_collections_group_parts_part_description_rel1_to_x},
+     {"collections.group.parts.part.description.rel1.to_y", st_collections_group_parts_part_description_rel1_to_y},
+     {"collections.group.parts.part.description.rel2.relative", st_collections_group_parts_part_description_rel2_relative},
+     {"collections.group.parts.part.description.rel2.offset", st_collections_group_parts_part_description_rel2_offset},
+     {"collections.group.parts.part.description.rel2.to", st_collections_group_parts_part_description_rel2_to},
+     {"collections.group.parts.part.description.rel2.to_x", st_collections_group_parts_part_description_rel2_to_x},
+     {"collections.group.parts.part.description.rel2.to_y", st_collections_group_parts_part_description_rel2_to_y},
+     {"collections.group.parts.part.description.image.normal", st_collections_group_parts_part_description_image_normal},
+     {"collections.group.parts.part.description.image.tween", st_collections_group_parts_part_description_image_tween},
+     {"collections.group.parts.part.description.image.image", st_images_image}, /* dup */
+     {"collections.group.parts.part.description.image.images.image", st_images_image}, /* dup */
+     {"collections.group.parts.part.description.image.border", st_collections_group_parts_part_description_image_border},
+     {"collections.group.parts.part.description.image.middle", st_collections_group_parts_part_description_image_middle},
+     {"collections.group.parts.part.description.image.border_scale", st_collections_group_parts_part_description_image_border_scale},
+     {"collections.group.parts.part.description.image.scale_hint", st_collections_group_parts_part_description_image_scale_hint},
+     {"collections.group.parts.part.description.fill.smooth", st_collections_group_parts_part_description_fill_smooth},
+     {"collections.group.parts.part.description.fill.origin.relative", st_collections_group_parts_part_description_fill_origin_relative},
+     {"collections.group.parts.part.description.fill.origin.offset", st_collections_group_parts_part_description_fill_origin_offset},
+     {"collections.group.parts.part.description.fill.size.relative", st_collections_group_parts_part_description_fill_size_relative},
+     {"collections.group.parts.part.description.fill.size.offset", st_collections_group_parts_part_description_fill_size_offset},
+     {"collections.group.parts.part.description.fill.angle", st_collections_group_parts_part_description_fill_angle},
+     {"collections.group.parts.part.description.fill.spread", st_collections_group_parts_part_description_fill_spread},
+     {"collections.group.parts.part.description.fill.type", st_collections_group_parts_part_description_fill_type},
+     {"collections.group.parts.part.description.color_class", st_collections_group_parts_part_description_color_class},
+     {"collections.group.parts.part.description.color", st_collections_group_parts_part_description_color},
+     {"collections.group.parts.part.description.color2", st_collections_group_parts_part_description_color2},
+     {"collections.group.parts.part.description.color3", st_collections_group_parts_part_description_color3},
+     {"collections.group.parts.part.description.text.text", st_collections_group_parts_part_description_text_text},
+     {"collections.group.parts.part.description.text.text_class", st_collections_group_parts_part_description_text_text_class},
+     {"collections.group.parts.part.description.text.font", st_collections_group_parts_part_description_text_font},
+     {"collections.group.parts.part.description.text.style", st_collections_group_parts_part_description_text_style},
+     {"collections.group.parts.part.description.text.repch", st_collections_group_parts_part_description_text_repch},
+     {"collections.group.parts.part.description.text.size", st_collections_group_parts_part_description_text_size},
+     {"collections.group.parts.part.description.text.fit", st_collections_group_parts_part_description_text_fit},
+     {"collections.group.parts.part.description.text.min", st_collections_group_parts_part_description_text_min},
+     {"collections.group.parts.part.description.text.max", st_collections_group_parts_part_description_text_max},
+     {"collections.group.parts.part.description.text.align", st_collections_group_parts_part_description_text_align},
+     {"collections.group.parts.part.description.text.source", st_collections_group_parts_part_description_text_source},
+     {"collections.group.parts.part.description.text.text_source", st_collections_group_parts_part_description_text_text_source},
+     {"collections.group.parts.part.description.text.font", st_fonts_font}, /* dup */
+     {"collections.group.parts.part.description.text.fonts.font", st_fonts_font}, /* dup */
+     {"collections.group.parts.part.description.text.elipsis", st_collections_group_parts_part_description_text_elipsis},
+     {"collections.group.parts.part.description.gradient.type", st_collections_group_parts_part_description_gradient_type},
+     {"collections.group.parts.part.description.gradient.rel1.relative", st_collections_group_parts_part_description_gradient_rel1_relative},
+     {"collections.group.parts.part.description.gradient.rel1.offset", st_collections_group_parts_part_description_gradient_rel1_offset},
+     {"collections.group.parts.part.description.gradient.rel2.relative", st_collections_group_parts_part_description_gradient_rel2_relative},
+     {"collections.group.parts.part.description.gradient.rel2.offset", st_collections_group_parts_part_description_gradient_rel2_offset},
+     {"collections.group.parts.part.description.gradient.spectrum", st_collections_group_parts_part_description_gradient_spectrum},
+     {"collections.group.parts.part.description.box.layout", st_collections_group_parts_part_description_box_layout},
+     {"collections.group.parts.part.description.box.align", st_collections_group_parts_part_description_box_align},
+     {"collections.group.parts.part.description.box.padding", st_collections_group_parts_part_description_box_padding},
+     {"collections.group.parts.part.description.box.min", st_collections_group_parts_part_description_box_min},
+     {"collections.group.parts.part.description.table.homogeneous", st_collections_group_parts_part_description_table_homogeneous},
+     {"collections.group.parts.part.description.table.align", st_collections_group_parts_part_description_table_align},
+     {"collections.group.parts.part.description.table.padding", st_collections_group_parts_part_description_table_padding},
+     {"collections.group.parts.part.description.map.perspective", st_collections_group_parts_part_description_map_perspective},
+     {"collections.group.parts.part.description.map.light", st_collections_group_parts_part_description_map_light},
+     {"collections.group.parts.part.description.map.rotation.center", st_collections_group_parts_part_description_map_rotation_center},
+     {"collections.group.parts.part.description.map.rotation.x", st_collections_group_parts_part_description_map_rotation_x},
+     {"collections.group.parts.part.description.map.rotation.y", st_collections_group_parts_part_description_map_rotation_y},
+     {"collections.group.parts.part.description.map.rotation.z", st_collections_group_parts_part_description_map_rotation_z},
+     {"collections.group.parts.part.description.map.on", st_collections_group_parts_part_description_map_on},
+     {"collections.group.parts.part.description.map.smooth", st_collections_group_parts_part_description_map_smooth},
+     {"collections.group.parts.part.description.map.alpha", st_collections_group_parts_part_description_map_alpha},
+     {"collections.group.parts.part.description.map.backface_cull", st_collections_group_parts_part_description_map_backface_cull},
+     {"collections.group.parts.part.description.map.perspective_on", st_collections_group_parts_part_description_map_perspective_on},
+     {"collections.group.parts.part.description.perspective.zplane", st_collections_group_parts_part_description_perspective_zplane},
+     {"collections.group.parts.part.description.perspective.focal", st_collections_group_parts_part_description_perspective_focal},
+     {"collections.group.parts.part.description.params.int", st_collections_group_parts_part_description_params_int},
+     {"collections.group.parts.part.description.params.double", st_collections_group_parts_part_description_params_double},
+     {"collections.group.parts.part.description.params.string", st_collections_group_parts_part_description_params_string},
+     {"collections.group.parts.part.description.params.bool", st_collections_group_parts_part_description_params_bool},
+     {"collections.group.parts.part.description.params.choice", st_collections_group_parts_part_description_params_choice},
+     {"collections.group.parts.part.description.images.image", st_images_image}, /* dup */
+     {"collections.group.parts.part.description.font", st_fonts_font}, /* dup */
+     {"collections.group.parts.part.description.fonts.font", st_fonts_font}, /* dup */
+     {"collections.group.parts.part.description.styles.style.name", st_styles_style_name}, /* dup */
+     {"collections.group.parts.part.description.styles.style.base", st_styles_style_base}, /* dup */
+     {"collections.group.parts.part.description.styles.style.tag", st_styles_style_tag}, /* dup */
+     {"collections.group.parts.part.description.color_classes.color_class.name", st_color_class_name}, /* dup */
+     {"collections.group.parts.part.description.color_classes.color_class.color", st_color_class_color}, /* dup */
+     {"collections.group.parts.part.description.color_classes.color_class.color2", st_color_class_color2}, /* dup */
+     {"collections.group.parts.part.description.color_classes.color_class.color3", st_color_class_color3}, /* dup */
+     {"collections.group.parts.part.description.programs.image", st_images_image}, /* dup */
+     {"collections.group.parts.part.description.programs.images.image", st_images_image}, /* dup */
+     {"collections.group.parts.part.description.programs.font", st_fonts_font}, /* dup */
+     {"collections.group.parts.part.description.programs.fonts.font", st_fonts_font}, /* dup */
+     {"collections.group.parts.part.description.programs.program.name", st_collections_group_programs_program_name}, /* dup */
+     {"collections.group.parts.part.description.programs.program.signal", st_collections_group_programs_program_signal}, /* dup */
+     {"collections.group.parts.part.description.programs.program.source", st_collections_group_programs_program_source}, /* dup */
+     {"collections.group.parts.part.description.programs.program.in", st_collections_group_programs_program_in}, /* dup */
+     {"collections.group.parts.part.description.programs.program.action", st_collections_group_programs_program_action}, /* dup */
+     {"collections.group.parts.part.description.programs.program.transition", st_collections_group_programs_program_transition}, /* dup */
+     {"collections.group.parts.part.description.programs.program.target", st_collections_group_programs_program_target}, /* dup */
+     {"collections.group.parts.part.description.programs.program.after", st_collections_group_programs_program_after}, /* dup */
+     {"collections.group.parts.part.description.programs.program.api", st_collections_group_programs_program_api}, /* dup */
+     {"collections.group.parts.part.description.program.name", st_collections_group_programs_program_name}, /* dup */
+     {"collections.group.parts.part.description.program.signal", st_collections_group_programs_program_signal}, /* dup */
+     {"collections.group.parts.part.description.program.source", st_collections_group_programs_program_source}, /* dup */
+     {"collections.group.parts.part.description.program.in", st_collections_group_programs_program_in}, /* dup */
+     {"collections.group.parts.part.description.program.action", st_collections_group_programs_program_action}, /* dup */
+     {"collections.group.parts.part.description.program.transition", st_collections_group_programs_program_transition}, /* dup */
+     {"collections.group.parts.part.description.program.target", st_collections_group_programs_program_target}, /* dup */
+     {"collections.group.parts.part.description.program.after", st_collections_group_programs_program_after}, /* dup */
+     {"collections.group.parts.part.description.program.api", st_collections_group_programs_program_api}, /* dup */
+     {"collections.group.parts.part.programs.image", st_images_image}, /* dup */
+     {"collections.group.parts.part.programs.images.image", st_images_image}, /* dup */
+     {"collections.group.parts.part.programs.font", st_fonts_font}, /* dup */
+     {"collections.group.parts.part.programs.fonts.font", st_fonts_font}, /* dup */
+     {"collections.group.parts.part.programs.program.name", st_collections_group_programs_program_name}, /* dup */
+     {"collections.group.parts.part.programs.program.signal", st_collections_group_programs_program_signal}, /* dup */
+     {"collections.group.parts.part.programs.program.source", st_collections_group_programs_program_source}, /* dup */
+     {"collections.group.parts.part.programs.program.in", st_collections_group_programs_program_in}, /* dup */
+     {"collections.group.parts.part.programs.program.action", st_collections_group_programs_program_action}, /* dup */
+     {"collections.group.parts.part.programs.program.transition", st_collections_group_programs_program_transition}, /* dup */
+     {"collections.group.parts.part.programs.program.target", st_collections_group_programs_program_target}, /* dup */
+     {"collections.group.parts.part.programs.program.after", st_collections_group_programs_program_after}, /* dup */
+     {"collections.group.parts.part.programs.program.api", st_collections_group_programs_program_api}, /* dup */
+     {"collections.group.parts.part.program.name", st_collections_group_programs_program_name}, /* dup */
+     {"collections.group.parts.part.program.signal", st_collections_group_programs_program_signal}, /* dup */
+     {"collections.group.parts.part.program.source", st_collections_group_programs_program_source}, /* dup */
+     {"collections.group.parts.part.program.in", st_collections_group_programs_program_in}, /* dup */
+     {"collections.group.parts.part.program.action", st_collections_group_programs_program_action}, /* dup */
+     {"collections.group.parts.part.program.transition", st_collections_group_programs_program_transition}, /* dup */
+     {"collections.group.parts.part.program.target", st_collections_group_programs_program_target}, /* dup */
+     {"collections.group.parts.part.program.after", st_collections_group_programs_program_after}, /* dup */
+     {"collections.group.parts.part.program.api", st_collections_group_programs_program_api}, /* dup */
+     {"collections.group.parts.programs.image", st_images_image}, /* dup */
+     {"collections.group.parts.programs.images.image", st_images_image}, /* dup */
+     {"collections.group.parts.programs.font", st_fonts_font}, /* dup */
+     {"collections.group.parts.programs.fonts.font", st_fonts_font}, /* dup */
+     {"collections.group.parts.programs.program.name", st_collections_group_programs_program_name}, /* dup */
+     {"collections.group.parts.programs.program.signal", st_collections_group_programs_program_signal}, /* dup */
+     {"collections.group.parts.programs.program.source", st_collections_group_programs_program_source}, /* dup */
+     {"collections.group.parts.programs.program.in", st_collections_group_programs_program_in}, /* dup */
+     {"collections.group.parts.programs.program.action", st_collections_group_programs_program_action}, /* dup */
+     {"collections.group.parts.programs.program.transition", st_collections_group_programs_program_transition}, /* dup */
+     {"collections.group.parts.programs.program.target", st_collections_group_programs_program_target}, /* dup */
+     {"collections.group.parts.programs.program.after", st_collections_group_programs_program_after},
+     {"collections.group.parts.programs.program.api", st_collections_group_programs_program_api},
+     {"collections.group.parts.program.name", st_collections_group_programs_program_name}, /* dup */
+     {"collections.group.parts.program.signal", st_collections_group_programs_program_signal}, /* dup */
+     {"collections.group.parts.program.source", st_collections_group_programs_program_source}, /* dup */
+     {"collections.group.parts.program.filter", st_collections_group_programs_program_filter}, /* dup */
+     {"collections.group.parts.program.in", st_collections_group_programs_program_in}, /* dup */
+     {"collections.group.parts.program.action", st_collections_group_programs_program_action}, /* dup */
+     {"collections.group.parts.program.transition", st_collections_group_programs_program_transition}, /* dup */
+     {"collections.group.parts.program.target", st_collections_group_programs_program_target}, /* dup */
+     {"collections.group.parts.program.after", st_collections_group_programs_program_after}, /* dup */
+     {"collections.group.parts.program.api", st_collections_group_programs_program_api}, /* dup */
+     {"collections.group.program.name", st_collections_group_programs_program_name}, /* dup */
+     {"collections.group.program.signal", st_collections_group_programs_program_signal}, /* dup */
+     {"collections.group.program.source", st_collections_group_programs_program_source}, /* dup */
+     {"collections.group.program.filter", st_collections_group_programs_program_filter}, /* dup */
+     {"collections.group.program.in", st_collections_group_programs_program_in}, /* dup */
+     {"collections.group.program.action", st_collections_group_programs_program_action}, /* dup */
+     {"collections.group.program.transition", st_collections_group_programs_program_transition}, /* dup */
+     {"collections.group.program.target", st_collections_group_programs_program_target}, /* dup */
+     {"collections.group.program.after", st_collections_group_programs_program_after}, /* dup */
+     {"collections.group.program.api", st_collections_group_programs_program_api}, /* dup */
+     {"collections.group.programs.program.name", st_collections_group_programs_program_name},
+     {"collections.group.programs.program.signal", st_collections_group_programs_program_signal},
+     {"collections.group.programs.program.source", st_collections_group_programs_program_source},
+     {"collections.group.programs.program.filter", st_collections_group_programs_program_filter}, /* dup */
+     {"collections.group.programs.program.in", st_collections_group_programs_program_in},
+     {"collections.group.programs.program.action", st_collections_group_programs_program_action},
+     {"collections.group.programs.program.transition", st_collections_group_programs_program_transition},
+     {"collections.group.programs.program.target", st_collections_group_programs_program_target},
+     {"collections.group.programs.program.after", st_collections_group_programs_program_after},
+     {"collections.group.programs.program.api", st_collections_group_programs_program_api},
+     {"collections.group.programs.image", st_images_image}, /* dup */
+     {"collections.group.programs.images.image", st_images_image}, /* dup */
+     {"collections.group.programs.font", st_fonts_font}, /* dup */
+     {"collections.group.programs.fonts.font", st_fonts_font} /* dup */
+};
+
+New_Object_Handler object_handlers[] =
+{
+     {"externals", NULL},
+     {"images", NULL},
+     {"fonts", NULL},
+     {"data", NULL},
+     {"styles", NULL},
+     {"styles.style", ob_styles_style},
+     {"color_classes", NULL},
+     {"color_classes.color_class", ob_color_class},
+     {"spectra", NULL},
+     {"spectra.spectrum", ob_spectrum},
+     {"collections", ob_collections},
+     {"collections.externals", NULL}, /* dup */
+     {"collections.images", NULL}, /* dup */
+     {"collections.fonts", NULL}, /* dup */
+     {"collections.styles", NULL}, /* dup */
+     {"collections.styles.style", ob_styles_style}, /* dup */
+     {"collections.color_classes", NULL}, /* dup */
+     {"collections.color_classes.color_class", ob_color_class}, /* dup */
+     {"collections.group", ob_collections_group},
+     {"collections.group.data", NULL},
+     {"collections.group.script", ob_collections_group_script},
+     {"collections.group.lua_script", ob_collections_group_lua_script},
+     {"collections.group.externals", NULL}, /* dup */
+     {"collections.group.images", NULL}, /* dup */
+     {"collections.group.fonts", NULL}, /* dup */
+     {"collections.group.styles", NULL}, /* dup */
+     {"collections.group.styles.style", ob_styles_style}, /* dup */
+     {"collections.group.color_classes", NULL}, /* dup */
+     {"collections.group.color_classes.color_class", ob_color_class}, /* dup */
+     {"collections.group.parts", NULL},
+     {"collections.group.parts.images", NULL}, /* dup */
+     {"collections.group.parts.fonts", NULL}, /* dup */
+     {"collections.group.parts.styles", NULL}, /* dup */
+     {"collections.group.parts.styles.style", ob_styles_style}, /* dup */
+     {"collections.group.parts.color_classes", NULL}, /* dup */
+     {"collections.group.parts.color_classes.color_class", ob_color_class}, /* dup */
+     {"collections.group.parts.part", ob_collections_group_parts_part},
+     {"collections.group.parts.part.dragable", NULL},
+     {"collections.group.parts.part.images", NULL}, /* dup */
+     {"collections.group.parts.part.fonts", NULL}, /* dup */
+     {"collections.group.parts.part.styles", NULL}, /* dup */
+     {"collections.group.parts.part.styles.style", ob_styles_style}, /* dup */
+     {"collections.group.parts.part.color_classes", NULL}, /* dup */
+     {"collections.group.parts.part.color_classes.color_class", ob_color_class}, /* dup */
+     {"collections.group.parts.part.box", NULL},
+     {"collections.group.parts.part.box.items", NULL},
+     {"collections.group.parts.part.box.items.item", ob_collections_group_parts_part_box_items_item},
+     {"collections.group.parts.part.table", NULL},
+     {"collections.group.parts.part.table.items", NULL},
+     {"collections.group.parts.part.table.items.item", ob_collections_group_parts_part_box_items_item}, /* dup */
+     {"collections.group.parts.part.description", ob_collections_group_parts_part_description},
+     {"collections.group.parts.part.description.rel1", NULL},
+     {"collections.group.parts.part.description.rel2", NULL},
+     {"collections.group.parts.part.description.image", NULL}, /* dup */
+     {"collections.group.parts.part.description.image.images", NULL}, /* dup */
+     {"collections.group.parts.part.description.fill", NULL},
+     {"collections.group.parts.part.description.fill.origin", NULL},
+     {"collections.group.parts.part.description.fill.size", NULL},
+     {"collections.group.parts.part.description.text", NULL},
+     {"collections.group.parts.part.description.text.fonts", NULL}, /* dup */
+     {"collections.group.parts.part.description.images", NULL}, /* dup */
+     {"collections.group.parts.part.description.fonts", NULL}, /* dup */
+     {"collections.group.parts.part.description.styles", NULL}, /* dup */
+     {"collections.group.parts.part.description.styles.style", ob_styles_style}, /* dup */
+     {"collections.group.parts.part.description.gradient", NULL},
+     {"collections.group.parts.part.description.gradient.rel1", NULL},
+     {"collections.group.parts.part.description.gradient.rel2", NULL},
+     {"collections.group.parts.part.description.box", NULL},
+     {"collections.group.parts.part.description.table", NULL},
+     {"collections.group.parts.part.description.map", NULL},
+     {"collections.group.parts.part.description.map.rotation", NULL},
+     {"collections.group.parts.part.description.perspective", NULL},
+     {"collections.group.parts.part.description.params", NULL},
+     {"collections.group.parts.part.description.color_classes", NULL}, /* dup */
+     {"collections.group.parts.part.description.color_classes.color_class", ob_color_class}, /* dup */
+     {"collections.group.parts.part.description.program", ob_collections_group_programs_program}, /* dup */
+     {"collections.group.parts.part.description.program.script", ob_collections_group_programs_program_script}, /* dup */
+     {"collections.group.parts.part.description.program.lua_script", ob_collections_group_programs_program_lua_script}, /* dup */
+     {"collections.group.parts.part.description.programs", NULL}, /* dup */
+     {"collections.group.parts.part.description.programs.images", NULL}, /* dup */
+     {"collections.group.parts.part.description.programs.fonts", NULL}, /* dup */
+     {"collections.group.parts.part.description.programs.program", ob_collections_group_programs_program}, /* dup */
+     {"collections.group.parts.part.description.programs.program.script", ob_collections_group_programs_program_script}, /* dup */
+     {"collections.group.parts.part.description.programs.program.lua_script", ob_collections_group_programs_program_lua_script}, /* dup */
+     {"collections.group.parts.part.description.script", ob_collections_group_script}, /* dup */
+     {"collections.group.parts.part.description.lua_script", ob_collections_group_lua_script}, /* dup */
+     {"collections.group.parts.part.program", ob_collections_group_programs_program}, /* dup */
+     {"collections.group.parts.part.program.script", ob_collections_group_programs_program_script}, /* dup */
+     {"collections.group.parts.part.program.lua_script", ob_collections_group_programs_program_lua_script}, /* dup */
+     {"collections.group.parts.part.programs", NULL}, /* dup */
+     {"collections.group.parts.part.programs.images", NULL}, /* dup */
+     {"collections.group.parts.part.programs.fonts", NULL}, /* dup */
+     {"collections.group.parts.part.programs.program", ob_collections_group_programs_program}, /* dup */
+     {"collections.group.parts.part.programs.program.script", ob_collections_group_programs_program_script}, /* dup */
+     {"collections.group.parts.part.programs.program.lua_script", ob_collections_group_programs_program_lua_script}, /* dup */
+     {"collections.group.parts.part.script", ob_collections_group_script}, /* dup */
+     {"collections.group.parts.part.lua_script", ob_collections_group_lua_script}, /* dup */
+     {"collections.group.parts.program", ob_collections_group_programs_program}, /* dup */
+     {"collections.group.parts.program.script", ob_collections_group_programs_program_script}, /* dup */
+     {"collections.group.parts.program.lua_script", ob_collections_group_programs_program_lua_script}, /* dup */
+     {"collections.group.parts.programs", NULL}, /* dup */
+     {"collections.group.parts.programs.images", NULL}, /* dup */
+     {"collections.group.parts.programs.fonts", NULL}, /* dup */
+     {"collections.group.parts.programs.program", ob_collections_group_programs_program}, /* dup */
+     {"collections.group.parts.programs.program.script", ob_collections_group_programs_program_script}, /* dup */
+     {"collections.group.parts.programs.program.lua_script", ob_collections_group_programs_program_lua_script}, /* dup */
+     {"collections.group.parts.script", ob_collections_group_script}, /* dup */
+     {"collections.group.parts.lua_script", ob_collections_group_lua_script}, /* dup */
+     {"collections.group.program", ob_collections_group_programs_program}, /* dup */
+     {"collections.group.program.script", ob_collections_group_programs_program_script}, /* dup */
+     {"collections.group.program.lua_script", ob_collections_group_programs_program_lua_script}, /* dup */
+     {"collections.group.programs", NULL},
+     {"collections.group.programs.images", NULL}, /* dup */
+     {"collections.group.programs.fonts", NULL}, /* dup */
+     {"collections.group.programs.program", ob_collections_group_programs_program},
+     {"collections.group.programs.program.script", ob_collections_group_programs_program_script},
+     {"collections.group.programs.program.lua_script", ob_collections_group_programs_program_lua_script},
+     {"collections.group.programs.script", ob_collections_group_script}, /* dup */
+     {"collections.group.programs.lua_script", ob_collections_group_lua_script} /* dup */
+};
+
+/*****/
+
+int
+object_handler_num(void)
+{
+   return sizeof(object_handlers) / sizeof (New_Object_Handler);
+}
+
+int
+statement_handler_num(void)
+{
+   return sizeof(statement_handlers) / sizeof (New_Object_Handler);
+}
+
+/*****/
+
+/**
+   @edcsection{toplevel,Top-Level blocks}
+ */
+
+/**
+    @page edcref
+
+    @block
+        externals
+    @context
+        externals {
+           external: "name";
+        }
+    @description
+        The "externals" block is used to list each external module file that will be used in others
+       programs.
+    @endblock
+
+    @property
+        external
+    @parameters
+        [external filename]
+    @effect
+        Used to add a file to the externals list.
+    @endproperty
+ */
+static void
+st_externals_external(void)
+{
+   External *ex;
+   Edje_External_Directory_Entry *ext;
+
+   check_arg_count(1);
+
+   if (!edje_file->external_dir)
+     edje_file->external_dir = mem_alloc(SZ(Edje_External_Directory));
+
+   ex = mem_alloc(SZ(External));
+   ex->name = parse_str(0);
+     {
+       Eina_List *l;
+       External *lex;
+
+       EINA_LIST_FOREACH(externals, l, lex)
+         {
+            if (!strcmp(lex->name, ex->name))
+              {
+                 free(ex->name);
+                 free(ex);
+                 return;
+              }
+         }
+     }
+   externals = eina_list_append(externals, ex);
+
+   if (edje_file->external_dir)
+     {
+       ext = mem_alloc(SZ(Edje_External_Directory_Entry));
+       ext->entry = mem_strdup(ex->name);
+       edje_file->external_dir->entries = eina_list_append(edje_file->external_dir->entries, ext);
+     }
+}
+
+/**
+    @page edcref
+
+    @block
+        images
+    @context
+        images {
+            image: "filename1.ext" COMP;
+            image: "filename2.ext" LOSSY 99;
+            ..
+        }
+    @description
+        The "images" block is used to list each image file that will be used in
+        the theme along with its compression method (if any).
+        Besides the domcument's root, additional "images" blocks can be
+        included inside other blocks, normally "collections", "group" and
+        "part", easing mantienance of the file list when the theme is split
+        among multiple files.
+    @endblock
+
+    @property
+        image
+    @parameters
+        [image file] [compression method] (compression level)
+    @effect
+        Used to include each image file. The full path to the directory holding
+        the images can be defined later with edje_cc's "-id" option.
+        Compression methods:
+        @li RAW: Uncompressed.
+        @li COMP: Lossless compression.
+        @li LOSSY [0-100]: Lossy comression with quality from 0 to 100.
+        @li USER: Do not embed the file, refer to the external file instead.
+    @endproperty
+ */
+static void
+st_images_image(void)
+{
+   Edje_Image_Directory_Entry *img;
+   int v;
+
+   if (!edje_file->image_dir)
+     edje_file->image_dir = mem_alloc(SZ(Edje_Image_Directory));
+   img = mem_alloc(SZ(Edje_Image_Directory_Entry));
+   img->entry = parse_str(0);
+     {
+       Eina_List *l;
+       Edje_Image_Directory_Entry *limg;
+
+       EINA_LIST_FOREACH(edje_file->image_dir->entries, l, limg)
+         {
+            if (!strcmp(limg->entry, img->entry))
+              {
+                 free(img->entry);
+                 free(img);
+                 return;
+              }
+         }
+     }
+   edje_file->image_dir->entries = eina_list_append(edje_file->image_dir->entries, img);
+   img->id = eina_list_count(edje_file->image_dir->entries) - 1;
+   v = parse_enum(1,
+                 "RAW", 0,
+                 "COMP", 1,
+                 "LOSSY", 2,
+                 "USER", 3,
+                 NULL);
+   if (v == 0)
+     {
+       img->source_type = EDJE_IMAGE_SOURCE_TYPE_INLINE_PERFECT;
+       img->source_param = 0;
+     }
+   else if (v == 1)
+     {
+       img->source_type = EDJE_IMAGE_SOURCE_TYPE_INLINE_PERFECT;
+       img->source_param = 1;
+     }
+   else if (v == 2)
+     {
+       img->source_type = EDJE_IMAGE_SOURCE_TYPE_INLINE_LOSSY;
+       img->source_param = 0;
+     }
+   else if (v == 3)
+     {
+       img->source_type = EDJE_IMAGE_SOURCE_TYPE_EXTERNAL;
+       img->source_param = 0;
+     }
+   if (img->source_type != EDJE_IMAGE_SOURCE_TYPE_INLINE_LOSSY)
+       check_arg_count(2);
+   else
+     {
+       img->source_param = parse_int_range(2, 0, 100);
+       check_arg_count(3);
+     }
+}
+
+/**
+    @page edcref
+
+    @block
+        fonts
+    @context
+        fonts {
+            font: "filename1.ext" "fontname";
+            font: "filename2.ext" "otherfontname";
+            ..
+        }
+    @description
+        The "fonts" block is used to list each font file with an alias used later
+        in the theme. As with the "images" block, additional "fonts" blocks can
+        be included inside other blocks.
+    @endblock
+
+    @property
+        font
+    @parameters
+        [font filename] [font alias]
+    @effect
+        Defines each font "file" and "alias", the full path to the directory
+        holding the font files can be defined with edje_cc's "-fd" option.
+    @endproperty
+ */
+static void
+st_fonts_font(void)
+{
+   Font *fn;
+   Edje_Font_Directory_Entry *fnt;
+
+   check_arg_count(2);
+
+   if (!edje_file->font_dir)
+     edje_file->font_dir = mem_alloc(SZ(Edje_Font_Directory));
+
+   fn = mem_alloc(SZ(Font));
+   fn->file = parse_str(0);
+   fn->name = parse_str(1);
+     {
+       Eina_List *l;
+       Font *lfn;
+
+       EINA_LIST_FOREACH(fonts, l, lfn)
+         {
+            if (!strcmp(lfn->name, fn->name))
+              {
+                 free(fn->file);
+                 free(fn->name);
+                 free(fn);
+                 return;
+              }
+         }
+     }
+   fonts = eina_list_append(fonts, fn);
+
+   if (edje_file->font_dir)
+     {
+       fnt = mem_alloc(SZ(Edje_Font_Directory_Entry));
+       fnt->entry = mem_strdup(fn->name);
+       fnt->file = mem_strdup(fn->file);
+       edje_file->font_dir->entries = eina_list_append(edje_file->font_dir->entries, fnt);
+     }
+}
+
+/**
+    @page edcref
+    @block
+        data
+    @context
+        data {
+            item: "key" "value";
+            file: "otherkey" "filename.ext";
+            ..
+        }
+    @description
+        The "data" block is used to pass arbitrary parameters from the theme to
+        the application. Unlike the "images" and "fonts" blocks, additional
+        "data" blocks can only be included inside the "group" block.
+    @endblock
+
+    @property
+        item
+    @parameters
+        [parameter name] [parameter value]
+    @effect
+        Defines a new parameter, the value will be the string specified next to
+        it.
+    @endproperty
+ */
+static void
+st_data_item(void)
+{
+   Edje_Data *di;
+
+   check_arg_count(2);
+
+   di = mem_alloc(SZ(Edje_Data));
+   di->key = parse_str(0);
+   di->value = parse_str(1);
+   edje_file->data = eina_list_append(edje_file->data, di);
+}
+
+/**
+    @page edcref
+    @property
+        file
+    @parameters
+        [parameter name] [parameter filename]
+    @effect
+        Defines a new parameter , the value will be the contents of the
+        specified file formated as a single string of text. This property only
+        works with plain text files.
+    @endproperty
+ */
+static void
+st_data_file(void)
+{
+   const char *data;
+   const char *over;
+   Edje_Data *di;
+   char *filename;
+   char *value;
+   int fd;
+   int i;
+   struct stat buf;
+
+   check_arg_count(2);
+
+   di = mem_alloc(SZ(Edje_Data));
+   di->key = parse_str(0);
+   filename = parse_str(1);
+
+   fd = open(filename, O_RDONLY | O_BINARY, S_IRUSR | S_IWUSR);
+   if (fd < 0)
+     {
+        ERR("%s: Error. %s:%i when opening file \"%s\": \"%s\"",
+           progname, file_in, line, filename, strerror(errno));
+        exit(-1);
+     }
+
+   if (fstat(fd, &buf))
+     {
+        ERR("%s: Error. %s:%i when stating file \"%s\": \"%s\"",
+           progname, file_in, line, filename, strerror(errno));
+        exit(-1);
+     }
+
+   data = mmap(NULL, buf.st_size, PROT_READ, MAP_SHARED, fd, 0);
+   if (data == MAP_FAILED)
+     {
+        ERR("%s: Error. %s:%i when mapping file \"%s\": \"%s\"",
+           progname, file_in, line, filename, strerror(errno));
+        exit(-1);
+     }
+
+   over = data;
+   for (i = 0; i < buf.st_size; ++i, ++over)
+     if (*over == '\0')
+       {
+          ERR("%s: Error. %s:%i file \"%s\" is a binary file.",
+                  progname, file_in, line, filename);
+          exit(-1);
+       }
+
+   value = malloc(sizeof (char) * buf.st_size + 1);
+   snprintf(value, buf.st_size + 1, "%s", data);
+
+   munmap((void*)data, buf.st_size);
+   close(fd);
+
+   di->value = value;
+   edje_file->data = eina_list_append(edje_file->data, di);
+
+   free(filename);
+}
+
+/**
+    @page edcref
+    @block
+        color_classes
+    @context
+        color_classes {
+            color_class {
+                name:  "colorclassname";
+                color:  [0-255] [0-255] [0-255] [0-255];
+                color2: [0-255] [0-255] [0-255] [0-255];
+                color3: [0-255] [0-255] [0-255] [0-255]
+            }
+            ..
+        }
+    @description
+        The "color_classes" block contains a list of one or more "color_class"
+        blocks. Each "color_class" allows the designer to name an arbitrary
+        group of colors to be used in the theme, the application can use that
+        name to alter the color values at runtime.
+    @endblock
+*/
+static void
+ob_color_class(void)
+{
+   Edje_Color_Class *cc;
+
+   cc = mem_alloc(SZ(Edje_Color_Class));
+   edje_file->color_classes = eina_list_append(edje_file->color_classes, cc);
+
+   cc->r = 0;
+   cc->g = 0;
+   cc->b = 0;
+   cc->a = 0;
+   cc->r2 = 0;
+   cc->g2 = 0;
+   cc->b2 = 0;
+   cc->a2 = 0;
+   cc->r3 = 0;
+   cc->g3 = 0;
+   cc->b3 = 0;
+   cc->a3 = 0;
+}
+
+/**
+    @page edcref
+
+    @property
+        name
+    @parameters
+        [color class name]
+    @effect
+        Sets the name for the color class, used as reference by both the theme
+        and the application.
+    @endproperty
+*/
+static void
+st_color_class_name(void)
+{
+   Edje_Color_Class *cc, *tcc;
+   Eina_List *l;
+
+   cc = eina_list_data_get(eina_list_last(edje_file->color_classes));
+   cc->name = parse_str(0);
+   EINA_LIST_FOREACH(edje_file->color_classes, l, tcc)
+     {
+       if ((cc != tcc) && (!strcmp(cc->name, tcc->name)))
+         {
+            fprintf(stderr, "%s: Error. parse error %s:%i. There is already a color class named \"%s\"\n",
+                    progname, file_in, line - 1, cc->name);
+            exit(-1);
+         }
+     }
+}
+
+/**
+    @page edcref
+    @property
+        color
+    @parameters
+        [red] [green] [blue] [alpha]
+    @effect
+        The main color.
+    @endproperty
+*/
+static void
+st_color_class_color(void)
+{
+   Edje_Color_Class *cc;
+
+   check_arg_count(4);
+
+   cc = eina_list_data_get(eina_list_last(edje_file->color_classes));
+   cc->r = parse_int_range(0, 0, 255);
+   cc->g = parse_int_range(1, 0, 255);
+   cc->b = parse_int_range(2, 0, 255);
+   cc->a = parse_int_range(3, 0, 255);
+}
+
+/**
+    @page edcref
+    @property
+        color2
+    @parameters
+        [red] [green] [blue] [alpha]
+    @effect
+        Used as shadow in text and textblock parts.
+    @endproperty
+*/
+static void
+st_color_class_color2(void)
+{
+   Edje_Color_Class *cc;
+
+   check_arg_count(4);
+
+   cc = eina_list_data_get(eina_list_last(edje_file->color_classes));
+   cc->r2 = parse_int_range(0, 0, 255);
+   cc->g2 = parse_int_range(1, 0, 255);
+   cc->b2 = parse_int_range(2, 0, 255);
+   cc->a2 = parse_int_range(3, 0, 255);
+}
+
+/**
+    @page edcref
+    @property
+        color3
+    @parameters
+        [red] [green] [blue] [alpha]
+    @effect
+        Used as outline in text and textblock parts.
+    @endproperty
+*/
+static void
+st_color_class_color3(void)
+{
+   Edje_Color_Class *cc;
+
+   check_arg_count(4);
+
+   cc = eina_list_data_get(eina_list_last(edje_file->color_classes));
+   cc->r3 = parse_int_range(0, 0, 255);
+   cc->g3 = parse_int_range(1, 0, 255);
+   cc->b3 = parse_int_range(2, 0, 255);
+   cc->a3 = parse_int_range(3, 0, 255);
+}
+
+/**
+    @page edcref
+    @block
+        spectra
+    @context
+        spectra {
+            spectrum {
+                name: "colorspectrumname";
+                color: [0-255] [0-255] [0-255] [0-255] [0-?]
+                color: [0-255] [0-255] [0-255] [0-255] [0-?]
+                ..
+            }
+            ..
+        }
+    @description
+        The "spectra" block contains a list of one or more "spectrum" blocks.
+        Each "spectrum" block defines a color range used to fill GRADIENT
+        parts. The colors are defined with the red, green, blue, alpha, delta
+        format.
+    @endblock
+*/
+static void
+ob_spectrum(void)
+{
+   Edje_Spectrum_Directory_Entry *se;
+
+   if (!edje_file->spectrum_dir)
+     edje_file->spectrum_dir = mem_alloc(SZ(Edje_Spectrum_Directory));
+   se = mem_alloc(SZ(Edje_Spectrum_Directory_Entry));
+   edje_file->spectrum_dir->entries = eina_list_append(edje_file->spectrum_dir->entries, se);
+   se->id = eina_list_count(edje_file->spectrum_dir->entries) - 1;
+   se->entry = NULL;
+   se->filename = NULL;
+   se->color_list = NULL;
+}
+
+/**
+    @page edcref
+    @property
+        name
+    @parameters
+        [spectrum name]
+    @effect
+        The name of the spectrum used as reference later in the theme.
+    @endproperty
+*/
+static void
+st_spectrum_name(void)
+{
+   Edje_Spectrum_Directory_Entry *se;
+
+   se = eina_list_data_get(eina_list_last(edje_file->spectrum_dir->entries));
+   se->entry = parse_str(0);
+}
+
+/**
+    @page edcref
+    @property
+        color
+    @parameters
+        [red] [green] [blue] [alpha] [delta]
+    @effect
+        Each color declaration represents a stop point in the color range. The
+        last parameter (delta) is used to set the proportion of a given stop
+        point higher or lower in contrast with the other color's delta value.
+    @endproperty
+*/
+static void
+st_spectrum_color(void)
+{
+   Edje_Spectrum_Directory_Entry *se;
+   Edje_Spectrum_Color *sc;
+
+   se = eina_list_data_get(eina_list_last(edje_file->spectrum_dir->entries));
+
+   sc = mem_alloc(SZ(Edje_Spectrum_Color));
+   se->color_list = eina_list_append(se->color_list, sc);
+   sc->r = parse_int_range(0, 0, 255);
+   sc->g = parse_int_range(1, 0, 255);
+   sc->b = parse_int_range(2, 0, 255);
+   sc->a = parse_int_range(3, 0, 255);
+   sc->d = parse_int(4);
+}
+
+/**
+    @page edcref
+    @block
+        styles
+    @context
+        styles {
+            style {
+                name: "stylename";
+                base: "..default style properties..";
+
+                tag:  "tagname" "..style properties..";
+                ..
+            }
+            ..
+        }
+    @description
+        The "styles" block contains a list of one or more "style" blocks. A
+        "style" block is used to create style \<tags\> for advanced TEXTBLOCK
+        formatting.
+    @endblock
+*/
+static void
+ob_styles_style(void)
+{
+   Edje_Style *stl;
+
+   stl = mem_alloc(SZ(Edje_Style));
+   edje_file->styles = eina_list_append(edje_file->styles, stl);
+}
+
+/**
+    @page edcref
+    @property
+        name
+    @parameters
+        [style name]
+    @effect
+        The name of  the style to be used as reference later in the theme.
+    @endproperty
+*/
+static void
+st_styles_style_name(void)
+{
+   Edje_Style *stl, *tstl;
+   Eina_List *l;
+
+   stl = eina_list_data_get(eina_list_last(edje_file->styles));
+   stl->name = parse_str(0);
+   EINA_LIST_FOREACH(edje_file->styles, l, tstl)
+     {
+       if ((stl != tstl) && (!strcmp(stl->name, tstl->name)))
+         {
+            ERR("%s: Error. parse error %s:%i. There is already a style named \"%s\"",
+                progname, file_in, line - 1, stl->name);
+            exit(-1);
+         }
+     }
+}
+
+/**
+    @page edcref
+    @property
+        base
+    @parameters
+        [style properties string]
+    @effect
+        The default style properties that will be applied to the complete
+        text.
+    @endproperty
+*/
+static void
+st_styles_style_base(void)
+{
+   Edje_Style *stl;
+   Edje_Style_Tag *tag;
+
+   stl = eina_list_data_get(eina_list_last(edje_file->styles));
+   if (stl->tags)
+     {
+       ERR("%s: Error. parse error %s:%i. There is already a basic format for the style",
+           progname, file_in, line - 1);
+       exit(-1);
+     }
+   tag = mem_alloc(SZ(Edje_Style_Tag));
+   tag->key = mem_strdup("DEFAULT");
+   tag->value = parse_str(0);
+   stl->tags = eina_list_append(stl->tags, tag);
+}
+
+/**
+    @page edcref
+    @property
+        tag
+    @parameters
+        [tag name] [style properties string]
+    @effect
+        Style to be applied only to text between style \<tags\>..\</tags\>.
+    @endproperty
+*/
+static void
+st_styles_style_tag(void)
+{
+   Edje_Style *stl;
+   Edje_Style_Tag *tag;
+
+   stl = eina_list_data_get(eina_list_last(edje_file->styles));
+   tag = mem_alloc(SZ(Edje_Style_Tag));
+   tag->key = parse_str(0);
+   tag->value = parse_str(1);
+   stl->tags = eina_list_append(stl->tags, tag);
+}
+
+/**
+    @page edcref
+    @block
+        collections
+    @context
+        collections {
+            ..
+            group { }
+            group { }
+            ..
+        }
+    @description
+        The "collections" block is used to list the groups that compose the
+        theme. Additional "collections" blocks do not prevent overriding group
+        names.
+    @endblock
+*/
+static void
+ob_collections(void)
+{
+   if (!edje_file->collection_dir)
+     edje_file->collection_dir = mem_alloc(SZ(Edje_Part_Collection_Directory));
+}
+
+/**
+   @edcsection{group,Group sub blocks}
+ */
+
+/**
+    @page edcref
+    @block
+        group
+    @context
+        collections {
+            ..
+            group {
+                name: "nameusedbytheapplication";
+                alias: "anothername";
+                min: width height;
+                max: width height;
+
+                data { }
+                script { }
+                parts { }
+                programs { }
+            }
+            ..
+        }
+    @description
+        A "group" block contains the list of parts and programs that compose a
+        given Edje Object.
+    @endblock
+*/
+static void
+ob_collections_group(void)
+{
+   Edje_Part_Collection_Directory_Entry *de;
+   Edje_Part_Collection *pc;
+   Code *cd;
+   
+   de = mem_alloc(SZ(Edje_Part_Collection_Directory_Entry));
+   edje_file->collection_dir->entries = eina_list_append(edje_file->collection_dir->entries, de);
+   de->id = eina_list_count(edje_file->collection_dir->entries) - 1;
+
+   pc = mem_alloc(SZ(Edje_Part_Collection));
+   edje_collections = eina_list_append(edje_collections, pc);
+   pc->id = eina_list_count(edje_collections) - 1;
+
+   cd = mem_alloc(SZ(Code));
+   codes = eina_list_append(codes, cd);
+}
+
+/**
+    @page edcref
+    @property
+        name
+    @parameters
+        [group name]
+    @effect
+        The name that will be used by the application to load the resulting
+        Edje object and to identify the group to swallow in a GROUP part. If a
+        group with the same name exists already it will be completely overriden
+        by the new group.
+    @endproperty
+*/
+static void
+st_collections_group_name(void)
+{
+   Edje_Part_Collection_Directory_Entry *de, *de_other, *alias;
+   Eina_List *l, *l2;
+
+   check_arg_count(1);
+
+   de = eina_list_data_get(eina_list_last(edje_file->collection_dir->entries));
+   de->entry = parse_str(0);
+   EINA_LIST_FOREACH(edje_file->collection_dir->entries, l, de_other)
+     {
+       if ((de_other != de) && (de_other->entry) && 
+           (!strcmp(de->entry, de_other->entry)))
+         {
+            Edje_Part_Collection *pc;
+            Code *cd;
+            int i;
+            
+            pc = eina_list_nth(edje_collections, de_other->id);
+            cd = eina_list_nth(codes, de_other->id);
+            
+            edje_file->collection_dir->entries = 
+              eina_list_remove(edje_file->collection_dir->entries, de_other);
+            edje_collections = 
+              eina_list_remove(edje_collections, pc);
+            codes =
+              eina_list_remove(codes, cd);
+
+            for (i = 0, l = edje_file->collection_dir->entries; l; l = eina_list_next(l), i++)
+              {
+                 de_other = eina_list_data_get(l);
+                  for (l2 = aliases; l2; l2 = l2->next)
+                    {
+                       alias = l2->data;
+                       if (alias->id == de_other->id)
+                         alias->id = i;
+                    }
+                 de_other->id = i;
+              }
+            for (i = 0, l = edje_collections; l; l = eina_list_next(l), i++)
+              {
+                 pc = eina_list_data_get(l);
+                 pc->id = i;
+              }
+            break;
+         }
+     }
+}
+
+/**
+    @page edcref
+    @property
+        script_only
+    @parameters
+        [on/off]
+    @effect
+        The flag (on/off) as to if this group is defined ONLY by script
+        callbacks such as init(), resize() and shutdown()
+    @endproperty
+*/
+static void
+st_collections_group_script_only(void)
+{
+   Edje_Part_Collection *pc;
+
+   check_arg_count(1);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   pc->script_only = parse_bool(0);
+}
+
+static void
+st_collections_group_lua_script_only(void)
+{
+   Edje_Part_Collection *pc;
+
+   check_arg_count(1);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   pc->lua_script_only = parse_bool(0);
+}
+
+/**
+    @page edcref
+    @property
+        alias
+    @parameters
+        [aditional group name]
+    @effect
+        Additional name to serve as identifier. Defining multiple aliases is
+        supported.
+    @endproperty
+*/
+static void
+st_collections_group_alias(void)
+{
+   Edje_Part_Collection_Directory_Entry *de, *alias;
+
+   check_arg_count(1);
+   de = eina_list_data_get(eina_list_last(edje_file->collection_dir->entries));
+
+   alias = mem_alloc(SZ(Edje_Part_Collection_Directory_Entry));
+   alias->id = de->id;
+   alias->entry = parse_str(0);
+
+   aliases = eina_list_append(aliases, alias);
+}
+
+/**
+    @page edcref
+    @property
+        min
+    @parameters
+        [width] [height]
+    @effect
+        The minimum size for the container defined by the composition of the
+        parts.
+    @endproperty
+*/
+static void
+st_collections_group_min(void)
+{
+   Edje_Part_Collection *pc;
+
+   check_arg_count(2);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   pc->prop.min.w = parse_int_range(0, 0, 0x7fffffff);
+   pc->prop.min.h = parse_int_range(1, 0, 0x7fffffff);
+}
+
+/**
+    @page edcref
+    @property
+        max
+    @parameters
+        [width] [height]
+    @effect
+        The maximum size for the container defined by the totality of the
+        parts.
+    @endproperty
+*/
+static void
+st_collections_group_max(void)
+{
+   Edje_Part_Collection *pc;
+
+   check_arg_count(2);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   pc->prop.max.w = parse_int_range(0, 0, 0x7fffffff);
+   pc->prop.max.h = parse_int_range(1, 0, 0x7fffffff);
+}
+
+/**
+    @page edcref
+    @block
+        script
+    @context
+        ..
+        group {
+            script {
+                //embryo script
+            }
+            ..
+            program {
+                script {
+                    //embryo script
+                }
+            }
+            ..
+        }
+        ..
+    @description
+        This block is used to "inject" embryo scripts to a given Edje theme and
+        it functions in two modalities. When it's included inside a "program"
+        block, the script will be executed every time the program is run, on
+        the other hand, when included directly into a "group", "part" or
+        "description" block, it will be executed once at load time, in the
+        load order.
+    @endblock
+*/
+static void
+ob_collections_group_script(void)
+{
+   Code *cd;
+
+   cd = eina_list_data_get(eina_list_last(codes));
+
+   if (!is_verbatim()) track_verbatim(1);
+   else
+     {
+       char *s;
+
+       s = get_verbatim();
+       if (s)
+         {
+            cd->l1 = get_verbatim_line1();
+            cd->l2 = get_verbatim_line2();
+            if (cd->shared)
+              {
+                 ERR("%s: Error. parse error %s:%i. There is already an existing script section for the group",
+                     progname, file_in, line - 1);
+                 exit(-1);
+              }
+            cd->shared = s;
+            cd->is_lua = 0;
+            set_verbatim(NULL, 0, 0);
+         }
+     }
+}
+
+static void
+ob_collections_group_lua_script(void)
+{
+   Code *cd;
+
+   cd = eina_list_data_get(eina_list_last(codes));
+
+   if (!is_verbatim()) track_verbatim(1);
+   else
+     {
+       char *s;
+
+       s = get_verbatim();
+       if (s)
+         {
+            cd->l1 = get_verbatim_line1();
+            cd->l2 = get_verbatim_line2();
+            if (cd->shared)
+              {
+                 ERR("%s: Error. parse error %s:%i. There is already an existing script section for the group",
+                     progname, file_in, line - 1);
+                 exit(-1);
+              }
+            cd->shared = s;
+            cd->is_lua = 1;
+            set_verbatim(NULL, 0, 0);
+         }
+     }
+}
+
+static void
+st_collections_group_data_item(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Data *di;
+
+   check_arg_count(2);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   di = mem_alloc(SZ(Edje_Data));
+   di->key = parse_str(0);
+   di->value = parse_str(1);
+   pc->data = eina_list_append(pc->data, di);
+}
+
+/**
+    @page edcref
+    @block
+        part
+    @context
+        group {
+            parts {
+                ..
+                part {
+                    name: "partname";
+                    type: IMAGE;
+                    mouse_events:  1;
+                    repeat_events: 0;
+                    ignore_flags: NONE;
+                    clip_to: "anotherpart";
+                    source:  "groupname";
+                    pointer_mode: AUTOGRAB;
+                    use_alternate_font_metrics: 0;
+
+                    description { }
+                    dragable { }
+                    items { }
+                }
+                ..
+            }
+        }
+    @description
+        Parts are used to represent the most basic design elements of the
+        theme, for example, a part can represent a line in a border or a label
+        on a button.
+    @endblock
+*/
+static void
+ob_collections_group_parts_part(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+
+   ep = mem_alloc(SZ(Edje_Part));
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   pc->parts = eina_list_append(pc->parts, ep);
+   ep->id = eina_list_count(pc->parts) - 1;
+   ep->type = EDJE_PART_TYPE_IMAGE;
+   ep->mouse_events = 1;
+   ep->repeat_events = 0;
+   ep->ignore_flags = EVAS_EVENT_FLAG_NONE;
+   ep->scale = 0;
+   ep->pointer_mode = EVAS_OBJECT_POINTER_MODE_AUTOGRAB;
+   ep->precise_is_inside = 0;
+   ep->use_alternate_font_metrics = 0;
+   ep->clip_to_id = -1;
+   ep->dragable.confine_id = -1;
+   ep->dragable.events_id = -1;
+   ep->items = NULL;
+}
+
+/**
+    @page edcref
+    @property
+        name
+    @parameters
+        [part name]
+    @effect
+        The part's name will be used as reference in the theme's relative
+        positioning system, by programs and in some cases by the application.
+        It must be unique within the group.
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_name(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+
+   check_arg_count(1);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+   ep->name = parse_str(0);
+
+   {
+       Eina_List *l;
+       Edje_Part *lep;
+
+       EINA_LIST_FOREACH(pc->parts, l, lep)
+         {
+            if ((lep != ep) && (lep->name) && (!strcmp(lep->name, ep->name)))
+              {
+                 ERR("%s: Error. parse error %s:%i. There is already a part of the name %s",
+                     progname, file_in, line - 1, ep->name);
+                 exit(-1);
+              }
+         }
+   }
+}
+
+/**
+    @page edcref
+    @property
+        type
+    @parameters
+        [TYPE]
+    @effect
+        Set the type (all caps) from among the available types, it's set to
+        IMAGE by default. Valid types:
+            @li RECT
+            @li TEXT
+            @li IMAGE
+            @li SWALLOW
+            @li TEXTBLOCK
+            @li GRADIENT
+            @li GROUP
+            @li BOX
+            @li TABLE
+            @li EXTERNAL
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_type(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+
+   check_arg_count(1);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+   ep->type = parse_enum(0,
+                        "NONE", EDJE_PART_TYPE_NONE,
+                        "RECT", EDJE_PART_TYPE_RECTANGLE,
+                        "TEXT", EDJE_PART_TYPE_TEXT,
+                        "IMAGE", EDJE_PART_TYPE_IMAGE,
+                        "SWALLOW", EDJE_PART_TYPE_SWALLOW,
+                        "TEXTBLOCK", EDJE_PART_TYPE_TEXTBLOCK,
+                        "GRADIENT", EDJE_PART_TYPE_GRADIENT,
+                        "GROUP", EDJE_PART_TYPE_GROUP,
+                        "BOX", EDJE_PART_TYPE_BOX,
+                        "TABLE", EDJE_PART_TYPE_TABLE,
+                        "EXTERNAL", EDJE_PART_TYPE_EXTERNAL,
+                        NULL);
+}
+
+/**
+    @page edcref
+    @property
+        mouse_events
+    @parameters
+        [1 or 0]
+    @effect
+        Specifies whether the part will emit signals, altought is named
+        "mouse_events", disabling it (0) will prevent the part from emitting
+        any type of signal at all. Its set to 1 by default.
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_mouse_events(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+
+   check_arg_count(1);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+   ep->mouse_events = parse_bool(0);
+}
+
+/**
+    @page edcref
+    @property
+        repeat_events
+    @parameters
+        [1 or 0]
+    @effect
+        Specifies whether a part echoes a mouse event to other parts below the
+        pointer (1), or not (0). Its set to 0 by default.
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_repeat_events(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+
+   check_arg_count(1);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+   ep->repeat_events = parse_bool(0);
+}
+
+/**
+    @page edcref
+    @property
+        ignore_flags
+    @parameters
+        [FLAG] ...
+    @effect
+        Specifies whether events with the given flags should be ignored,
+       i.e., will not have the signals emitted to the parts. Multiple flags
+       must be separated by spaces, the effect will be ignoring all events
+       with one of the flags specified. Possible flags:
+            @li NONE (default value, no event will be ignored)
+            @li ON_HOLD
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_ignore_flags(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+
+   check_min_arg_count(1);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+   ep->ignore_flags = parse_flags(0,
+                                 "NONE", EVAS_EVENT_FLAG_NONE,
+                                 "ON_HOLD", EVAS_EVENT_FLAG_ON_HOLD,
+                                 NULL);
+}
+
+/**
+    @page edcref
+    @property
+        scale
+    @parameters
+        [1 or 0]
+    @effect
+        Specifies whether the part will scale its size with an edje scaling
+        factor. By default scale is off (0) and the default scale factor is
+        1.0 - that means no scaling. This would be used to scale properties
+        such as font size, min/max size of the part, and possibly can be used
+        to scale based on DPI of the target device. The reason to be selective
+        is that some things work well being scaled, others do not, so the
+        designer gets to choose what works best.
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_scale(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+
+   check_arg_count(1);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+   ep->scale = parse_bool(0);
+}
+
+/**
+    @page edcref
+    @property
+        pointer_mode
+    @parameters
+        [MODE]
+    @effect
+        Sets the mouse pointer behavior for a given part. The default value is
+        AUTOGRAB. Aviable modes:
+            @li AUTOGRAB, when the part is clicked and the button remains
+                pressed, the part will be the source of all future mouse
+                signals emitted, even outside the object, until the button is
+                released.
+            @li NOGRAB, the effect will be limited to the part's container.
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_pointer_mode(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+
+   check_arg_count(1);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+   ep->pointer_mode = parse_enum(0,
+                                "AUTOGRAB", EVAS_OBJECT_POINTER_MODE_AUTOGRAB,
+                                "NOGRAB", EVAS_OBJECT_POINTER_MODE_NOGRAB,
+                                NULL);
+}
+
+/**
+    @page edcref
+    @property
+        precise_is_inside
+    @parameters
+        [1 or 0]
+    @effect
+        Enables precise point collision detection for the part, which is more
+        resource intensive. Disabled by default.
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_precise_is_inside(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+
+   check_arg_count(1);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+   ep->precise_is_inside = parse_bool(0);
+}
+
+/**
+    @page edcref
+    @property
+        use_alternate_font_metrics
+    @parameters
+        [1 or 0]
+    @effect
+        Only affects text and textblock parts, when enabled Edje will use
+        different size measurement functions. Disabled by default. (note from
+        the author: I don't know what this is exactlu useful for?)
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_use_alternate_font_metrics(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+
+   check_arg_count(1);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+   ep->use_alternate_font_metrics = parse_bool(0);
+}
+
+/**
+    @page edcref
+    @property
+        clip_to
+    @parameters
+        [another part's name]
+    @effect
+        Only renders the area of part that coincides with another part's
+        container. Overflowing content will not be displayed.
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_clip_to_id(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+
+   check_arg_count(1);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+     {
+       char *name;
+
+       name = parse_str(0);
+       data_queue_part_lookup(pc, name, &(ep->clip_to_id));
+       free(name);
+     }
+}
+
+/**
+    @page edcref
+    @property
+        source
+    @parameters
+        [another group's name]
+    @effect
+        Only available to GROUP or TEXTBLOCK parts. Swallows the specified 
+        group into the part's container if a GROUP. If TEXTBLOCK it is used
+        for the group to be loaded and used for selection display UNDER the
+        selected text. source2 is used for on top of the selected text, if
+        source2 is specified.
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_source(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+
+   check_arg_count(1);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+
+   //FIXME: validate this somehow (need to decide on the format also)
+   ep->source = parse_str(0);
+}
+
+/**
+    @page edcref
+    @property
+        source2
+    @parameters
+        [another group's name]
+    @effect
+        Only available to TEXTBLOCK parts. It is used for the group to be 
+        loaded and used for selection display OVER the selected text. source
+        is used for under of the selected text, if source is specified.
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_source2(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+
+   check_arg_count(1);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+
+   //FIXME: validate this somehow (need to decide on the format also)
+   ep->source2 = parse_str(0);
+}
+
+/**
+    @page edcref
+    @property
+        source3
+    @parameters
+        [another group's name]
+    @effect
+        Only available to TEXTBLOCK parts. It is used for the group to be 
+        loaded and used for cursor display UNDER the cursor position. source4
+        is used for over the cursor text, if source4 is specified.
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_source3(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+
+   check_arg_count(1);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+
+   //FIXME: validate this somehow (need to decide on the format also)
+   ep->source3 = parse_str(0);
+}
+
+/**
+    @page edcref
+    @property
+        source4
+    @parameters
+        [another group's name]
+    @effect
+        Only available to TEXTBLOCK parts. It is used for the group to be 
+        loaded and used for cursor display OVER the cursor position. source3
+        is used for under the cursor text, if source4 is specified.
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_source4(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+
+   check_arg_count(1);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+
+   //FIXME: validate this somehow (need to decide on the format also)
+   ep->source4 = parse_str(0);
+}
+
+/**
+    @page edcref
+    @property
+        source5
+    @parameters
+        [another group's name]
+    @effect
+        Only available to TEXTBLOCK parts. It is used for the group to be 
+        loaded and used for anchors display UNDER the anchor position. source6
+        is used for over the anchors text, if source6 is specified.
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_source5(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+
+   check_arg_count(1);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+
+   //FIXME: validate this somehow (need to decide on the format also)
+   ep->source5 = parse_str(0);
+}
+
+/**
+    @page edcref
+    @property
+        source6
+    @parameters
+        [another group's name]
+    @effect
+        Only available to TEXTBLOCK parts. It is used for the group to be 
+        loaded and used for anchor display OVER the anchor position. source5
+        is used for under the anchor text, if source6 is specified.
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_source6(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+
+   check_arg_count(1);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+
+   //FIXME: validate this somehow (need to decide on the format also)
+   ep->source6 = parse_str(0);
+}
+
+/**
+    @page edcref
+
+    @property
+        effect
+    @parameters
+        [EFFECT]
+    @effect
+        Causes Edje to draw the selected effect among:
+        @li PLAIN
+        @li OUTLINE
+        @li SOFT_OUTLINE
+        @li SHADOW
+        @li SOFT_SHADOW
+        @li OUTLINE_SHADOW
+        @li OUTLINE_SOFT_SHADOW
+        @li FAR_SHADOW
+        @li FAR_SOFT_SHADOW
+        @li GLOW
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_effect(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+
+   check_arg_count(1);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+   ep->effect = parse_enum(0,
+               "NONE", EDJE_TEXT_EFFECT_NONE,
+               "PLAIN", EDJE_TEXT_EFFECT_PLAIN,
+               "OUTLINE", EDJE_TEXT_EFFECT_OUTLINE,
+               "SOFT_OUTLINE", EDJE_TEXT_EFFECT_SOFT_OUTLINE,
+               "SHADOW", EDJE_TEXT_EFFECT_SHADOW,
+               "SOFT_SHADOW", EDJE_TEXT_EFFECT_SOFT_SHADOW,
+               "OUTLINE_SHADOW", EDJE_TEXT_EFFECT_OUTLINE_SHADOW,
+               "OUTLINE_SOFT_SHADOW", EDJE_TEXT_EFFECT_OUTLINE_SOFT_SHADOW,
+               "FAR_SHADOW", EDJE_TEXT_EFFECT_FAR_SHADOW,
+               "FAR_SOFT_SHADOW", EDJE_TEXT_EFFECT_FAR_SOFT_SHADOW,
+               "GLOW", EDJE_TEXT_EFFECT_GLOW,
+               NULL);
+}
+
+/**
+    @page edcref
+    @property
+        entry_mode
+    @parameters
+        [MODE]
+    @effect
+        Sets the edit mode for a textblock part to one of:
+        @li NONE
+        @li PLAIN
+        @li EDITABLE
+        @li PASSWORD
+        It causes the part be editable if the edje object has the keyboard
+        focus AND the part has the edje focus (or selectable always
+        regardless of focus) and in the event of password mode, not
+        selectable and all text chars replaced with *'s but editable and
+        pastable.
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_entry_mode(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+
+   check_arg_count(1);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+   ep->entry_mode = parse_enum(0,
+                              "NONE", EDJE_ENTRY_EDIT_MODE_NONE,
+                              "PLAIN", EDJE_ENTRY_EDIT_MODE_SELECTABLE,
+                              "EDITABLE", EDJE_ENTRY_EDIT_MODE_EDITABLE,
+                              "PASSWORD", EDJE_ENTRY_EDIT_MODE_PASSWORD,
+                              NULL);
+}
+
+/**
+    @page edcref
+    @property
+        select_mode
+    @parameters
+        [MODE]
+    @effect
+        Sets the selection mode for a textblock part to one of:
+        @li DEFAULT
+        @li EXPLICIT
+        DEFAULT selection mode is what you would expect on any desktop. Press
+        mouse, drag and release to end. EXPLICIT mode requires the application
+        controlling the edje object has to explicitly begin and end selection
+        modes, and the selection itself is dragable at both ends.
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_select_mode(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+
+   check_arg_count(1);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+   ep->select_mode = parse_enum(0,
+                                "DEFAULT", EDJE_ENTRY_SELECTION_MODE_DEFAULT,
+                                "EXPLICIT", EDJE_ENTRY_SELECTION_MODE_EXPLICIT,
+                                NULL);
+}
+
+/**
+    @page edcref
+    @property
+        multiline
+    @parameters
+        [1 or 0]
+    @effect
+        It causes a textblock that is editable to allow multiple lines for
+        editing.
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_multiline(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+
+   check_arg_count(1);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+   ep->multiline = parse_bool(0);
+}
+
+/**
+    @page edcref
+    @block
+        dragable
+    @context
+        part {
+            ..
+            dragable {
+                confine: "another part";
+                events:  "another dragable part";
+                x: 0 0 0;
+                y: 0 0 0;
+            }
+            ..
+        }
+    @description
+        When this block is used the resulting part can be dragged around the
+        interface, do not confuse with external drag & drop. By default Edje
+        (and most applications) will attempt to use the minimal size possible
+        for a dragable part. If the min property is not set in the description
+        the part will be (most likely) set to 0px width and 0px height, thus
+        invisible.
+    @endblock
+
+    @property
+        x
+    @parameters
+        [enable/disable] [step] [count]
+    @effect
+        Used to setup dragging events for the X axis. The first parameter is
+        used to enable (1 or -1) and disable (0) dragging along the axis. When
+        enabled, 1 will set the starting point at 0.0 and -1 at 1.0. The second
+        parameter takes any integer and will limit movement to values
+        divisible by it, causing the part to jump from position to position.
+        The third parameter, (question from the author: What is count for?).
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_dragable_x(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+
+   check_arg_count(3);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+   ep->dragable.x = parse_int_range(0, -1, 1);
+   ep->dragable.step_x = parse_int_range(1, 0, 0x7fffffff);
+   ep->dragable.count_x = parse_int_range(2, 0, 0x7fffffff);
+}
+
+/**
+    @page edcref
+    @property
+        y
+    @parameters
+        [enable/disable] [step] [count]
+    @effect
+        Used to setup dragging events for the Y axis. The first parameter is
+        used to enable (1 or -1) and disable (0) dragging along the axis. When
+        enabled, 1 will set the starting point at 0.0 and -1 at 1.0. The second
+        parameter takes any integer and will limit movement to values
+        divisibles by it, causing the part to jump from position to position.
+        The third parameter, (question from the author: What is count for?).
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_dragable_y(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+
+   check_arg_count(3);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+   ep->dragable.y = parse_int_range(0, -1, 1);
+   ep->dragable.step_y = parse_int_range(1, 0, 0x7fffffff);
+   ep->dragable.count_y = parse_int_range(2, 0, 0x7fffffff);
+}
+
+/**
+    @page edcref
+    @property
+        confine
+    @parameters
+        [another part's name]
+    @effect
+        When set, limits the movement of the dragged part to another part's
+        container. When you use confine don't forget to set a min size for the
+        part, or the draggie will not show up.
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_dragable_confine(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+
+   check_arg_count(1);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+     {
+       char *name;
+
+       name = parse_str(0);
+       data_queue_part_lookup(pc, name, &(ep->dragable.confine_id));
+       free(name);
+     }
+}
+
+/**
+    @page edcref
+    @property
+        events
+    @parameters
+        [another dragable part's name]
+    @effect
+        It causes the part to forward the drag events to another part, thus
+        ignoring them for itself.
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_dragable_events(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+
+   check_arg_count(1);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+     {
+       char *name;
+
+       name = parse_str(0);
+       data_queue_part_lookup(pc, name, &(ep->dragable.events_id));
+       free(name);
+     }
+}
+
+/**
+    @page edcref
+    @block
+        items
+    @context
+        part {
+            ..
+           box {
+                items {
+                    item {
+                        type: TYPE;
+                        source: "some source";
+                        min: 1 1;
+                        max: 100 100;
+                        padding: 1 1 2 2;
+                    }
+                    item {
+                        type: TYPE;
+                        source: "some other source";
+                        name: "some name";
+                        align: 1.0 0.5;
+                    }
+                    ..
+                }
+           }
+            ..
+        }
+    @description
+        On a part of type BOX, this block can be used to set other groups
+       as elements of the box. These can be mixed with external objects set
+       by the application through the edje_object_part_box_* API.
+    @endblock
+*/
+static void ob_collections_group_parts_part_box_items_item(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Pack_Element *item;
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+
+   if ((ep->type != EDJE_PART_TYPE_BOX) && (ep->type != EDJE_PART_TYPE_TABLE))
+     {
+       ERR("%s: Error. parse error %s:%i. "
+           "box attributes in non-BOX or TABLE part.",
+           progname, file_in, line - 1);
+       exit(-1);
+     }
+
+   item = mem_alloc(SZ(Edje_Pack_Element));
+   ep->items = eina_list_append(ep->items, item);
+   item->type = EDJE_PART_TYPE_GROUP;
+   item->name = NULL;
+   item->source = NULL;
+   item->min.w = 0;
+   item->min.h = 0;
+   item->prefer.w = 0;
+   item->prefer.h = 0;
+   item->max.w = -1;
+   item->max.h = -1;
+   item->padding.l = 0;
+   item->padding.r = 0;
+   item->padding.t = 0;
+   item->padding.b = 0;
+   item->align.x = FROM_DOUBLE(0.5);
+   item->align.y = FROM_DOUBLE(0.5);
+   item->weight.x = FROM_DOUBLE(0.0);
+   item->weight.y = FROM_DOUBLE(0.0);
+   item->aspect.w = 0;
+   item->aspect.h = 0;
+   item->aspect.mode = EDJE_ASPECT_PREFER_NONE;
+   item->options = NULL;
+   item->col = -1;
+   item->row = -1;
+   item->colspan = 1;
+   item->rowspan = 1;
+}
+
+/**
+    @page edcref
+    @property
+        type
+    @parameters
+        Only GROUP for now (defaults to it)
+    @effect
+        Sets the type of the object this item will hold.
+    @endproperty
+*/
+static void st_collections_group_parts_part_box_items_item_type(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Pack_Element *item;
+
+   check_arg_count(1);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+
+   item = eina_list_data_get(eina_list_last(ep->items));
+
+     {
+       char *s;
+
+       s = parse_str(0);
+       if (strcmp(s, "GROUP"))
+         {
+            ERR("%s: Error. parse error %s:%i. "
+                "token %s not one of: GROUP.",
+                progname, file_in, line - 1, s);
+            exit(-1);
+         }
+       /* FIXME: handle the enum, once everything else is supported */
+       item->type = EDJE_PART_TYPE_GROUP;
+     }
+}
+
+/**
+    @page edcref
+    @property
+        name
+    @parameters
+        [name for the object]
+    @effect
+        Sets the name of the object via evas_object_name_set().
+    @endproperty
+*/
+static void st_collections_group_parts_part_box_items_item_name(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Pack_Element *item;
+
+   check_arg_count(1);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+
+   item = eina_list_data_get(eina_list_last(ep->items));
+   item->name = parse_str(0);
+}
+
+/**
+    @page edcref
+    @property
+        source
+    @parameters
+        [another group's name]
+    @effect
+        Sets the group this object will be made from.
+    @endproperty
+*/
+static void st_collections_group_parts_part_box_items_item_source(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Pack_Element *item;
+
+   check_arg_count(1);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+
+   item = eina_list_data_get(eina_list_last(ep->items));
+   item->source = parse_str(0);
+}
+
+/**
+    @page edcref
+    @property
+        min
+    @parameters
+        [width] [height]
+    @effect
+        Sets the minimum size hints for this object.
+    @endproperty
+*/
+static void st_collections_group_parts_part_box_items_item_min(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Pack_Element *item;
+
+   check_arg_count(2);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+
+   item = eina_list_data_get(eina_list_last(ep->items));
+   item->min.w = parse_int_range(0, 0, 0x7ffffff);
+   item->min.h = parse_int_range(1, 0, 0x7ffffff);
+}
+
+/**
+    @page edcref
+    @property
+        prefer
+    @parameters
+        [width] [height]
+    @effect
+        Sets the preferred size hints for this object.
+    @endproperty
+*/
+static void st_collections_group_parts_part_box_items_item_prefer(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Pack_Element *item;
+
+   check_arg_count(2);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+
+   item = eina_list_data_get(eina_list_last(ep->items));
+   item->prefer.w = parse_int_range(0, 0, 0x7ffffff);
+   item->prefer.h = parse_int_range(1, 0, 0x7ffffff);
+}
+/**
+    @page edcref
+    @property
+        max
+    @parameters
+        [width] [height]
+    @effect
+        Sets the maximum size hints for this object.
+    @endproperty
+*/
+static void st_collections_group_parts_part_box_items_item_max(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Pack_Element *item;
+
+   check_arg_count(2);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+
+   item = eina_list_data_get(eina_list_last(ep->items));
+   item->max.w = parse_int_range(0, 0, 0x7ffffff);
+   item->max.h = parse_int_range(1, 0, 0x7ffffff);
+}
+
+/**
+    @page edcref
+    @property
+        padding
+    @parameters
+        [left] [right] [top] [bottom]
+    @effect
+        Sets the padding hints for this object.
+    @endproperty
+*/
+static void st_collections_group_parts_part_box_items_item_padding(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Pack_Element *item;
+
+   check_arg_count(4);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+
+   item = eina_list_data_get(eina_list_last(ep->items));
+   item->padding.l = parse_int_range(0, 0, 0x7ffffff);
+   item->padding.r = parse_int_range(1, 0, 0x7ffffff);
+   item->padding.t = parse_int_range(2, 0, 0x7ffffff);
+   item->padding.b = parse_int_range(3, 0, 0x7ffffff);
+}
+
+/**
+    @page edcref
+    @property
+        align
+    @parameters
+        [x] [y]
+    @effect
+        Sets the alignment hints for this object.
+    @endproperty
+*/
+static void st_collections_group_parts_part_box_items_item_align(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Pack_Element *item;
+
+   check_arg_count(2);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+
+   item = eina_list_data_get(eina_list_last(ep->items));
+   item->align.x = FROM_DOUBLE(parse_float_range(0, -1.0, 1.0));
+   item->align.y = FROM_DOUBLE(parse_float_range(1, -1.0, 1.0));
+}
+
+/**
+    @page edcref
+    @property
+        weight
+    @parameters
+        [x] [y]
+    @effect
+        Sets the weight hints for this object.
+    @endproperty
+*/
+static void st_collections_group_parts_part_box_items_item_weight(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Pack_Element *item;
+
+   check_arg_count(2);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+
+   item = eina_list_data_get(eina_list_last(ep->items));
+   item->weight.x = FROM_DOUBLE(parse_float_range(0, 0.0, 99999.99));
+   item->weight.y = FROM_DOUBLE(parse_float_range(1, 0.0, 99999.99));
+}
+
+/**
+    @page edcref
+    @property
+        aspect
+    @parameters
+        [w] [h]
+    @effect
+        Sets the aspect width and height hints for this object.
+    @endproperty
+*/
+static void st_collections_group_parts_part_box_items_item_aspect(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Pack_Element *item;
+
+   check_arg_count(2);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+
+   item = eina_list_data_get(eina_list_last(ep->items));
+   item->aspect.w = parse_int_range(0, 0, 0x7fffffff);
+   item->aspect.h = parse_int_range(1, 0, 0x7fffffff);
+}
+
+/**
+    @page edcref
+    @property
+        aspect_mode
+    @parameters
+        NONE, NEITHER, HORIZONTAL, VERTICAL, BOTH
+    @effect
+        Sets the aspect control hints for this object.
+    @endproperty
+*/
+static void st_collections_group_parts_part_box_items_item_aspect_mode(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Pack_Element *item;
+
+   check_arg_count(1);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+
+   item = eina_list_data_get(eina_list_last(ep->items));
+   item->aspect.mode = parse_enum(0,
+                                 "NONE", EDJE_ASPECT_CONTROL_NONE,
+                                 "NEITHER", EDJE_ASPECT_CONTROL_NEITHER,
+                                 "HORIZONTAL", EDJE_ASPECT_CONTROL_HORIZONTAL,
+                                 "VERTICAL", EDJE_ASPECT_CONTROL_VERTICAL,
+                                 "BOTH", EDJE_ASPECT_CONTROL_BOTH,
+                                 NULL);
+}
+
+/**
+    @page edcref
+    @property
+        options
+    @parameters
+        [extra options]
+    @effect
+        Sets extra options for the object. Unused for now.
+    @endproperty
+*/
+static void st_collections_group_parts_part_box_items_item_options(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Pack_Element *item;
+
+   check_arg_count(1);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+
+   item = eina_list_data_get(eina_list_last(ep->items));
+   item->options = parse_str(0);
+}
+
+/**
+    @page edcref
+    @property
+        position
+    @parameters
+        [col] [row]
+    @effect
+        Sets the position this item will have in the table.
+        This is required for parts of type TABLE.
+    @endproperty
+*/
+static void st_collections_group_parts_part_table_items_item_position(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Pack_Element *item;
+
+   check_arg_count(2);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+
+   if (ep->type != EDJE_PART_TYPE_TABLE)
+     {
+       ERR("%s: Error. parse error %s:%i. "
+           "table attributes in non-TABLE part.",
+           progname, file_in, line - 1);
+       exit(-1);
+     }
+   
+   item = eina_list_data_get(eina_list_last(ep->items));
+   item->col = parse_int_range(0, 0, 0xffff);
+   item->row = parse_int_range(1, 0, 0xffff);
+}
+
+/**
+    @page edcref
+    @property
+        span
+    @parameters
+        [col] [row]
+    @effect
+        Sets how many columns/rows this item will use.
+        Defaults to 1 1.
+    @endproperty
+*/
+static void st_collections_group_parts_part_table_items_item_span(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Pack_Element *item;
+
+   check_arg_count(2);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+
+   if (ep->type != EDJE_PART_TYPE_TABLE)
+     {
+       ERR("%s: Error. parse error %s:%i. "
+           "table attributes in non-TABLE part.",
+           progname, file_in, line - 1);
+       exit(-1);
+     }
+
+   item = eina_list_data_get(eina_list_last(ep->items));
+   item->colspan = parse_int_range(0, 1, 0xffff);
+   item->rowspan = parse_int_range(1, 1, 0xffff);
+}
+
+/**
+   @edcsection{description,State description sub blocks}
+ */
+
+/**
+    @page edcref
+    @block
+        description
+    @context
+        description {
+            inherit: "another_description" INDEX;
+            state: "description_name" INDEX;
+            visible: 1;
+            min: 0 0;
+            max: -1 -1;
+            align: 0.5 0.5;
+            fixed: 0 0;
+            step: 0 0;
+            aspect: 1 1;
+
+            rel1 {
+                ..
+            }
+
+            rel2 {
+                ..
+            }
+        }
+    @description
+        Every part can have one or more description blocks. Each description is
+        used to define style and layout properties of a part in a given
+        "state".
+    @endblock
+*/
+static void
+ob_collections_group_parts_part_description(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Part_Description *ed;
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+   ed = mem_alloc(SZ(Edje_Part_Description));
+   if (!ep->default_desc)
+     ep->default_desc = ed;
+   else
+     ep->other_desc = eina_list_append(ep->other_desc, ed);
+   ed->visible = 1;
+   ed->align.x = FROM_DOUBLE(0.5);
+   ed->align.y = FROM_DOUBLE(0.5);
+   ed->min.w = 0;
+   ed->min.h = 0;
+   ed->fixed.w = 0;
+   ed->fixed.h = 0;
+   ed->max.w = -1;
+   ed->max.h = -1;
+   ed->rel1.relative_x = FROM_DOUBLE(0.0);
+   ed->rel1.relative_y = FROM_DOUBLE(0.0);
+   ed->rel1.offset_x = 0;
+   ed->rel1.offset_y = 0;
+   ed->rel1.id_x = -1;
+   ed->rel1.id_y = -1;
+   ed->rel2.relative_x = FROM_DOUBLE(1.0);
+   ed->rel2.relative_y = FROM_DOUBLE(1.0);
+   ed->rel2.offset_x = -1;
+   ed->rel2.offset_y = -1;
+   ed->rel2.id_x = -1;
+   ed->rel2.id_y = -1;
+   ed->image.id = -1;
+   ed->fill.smooth = 1;
+   ed->fill.pos_rel_x = FROM_DOUBLE(0.0);
+   ed->fill.pos_abs_x = 0;
+   ed->fill.rel_x = FROM_DOUBLE(1.0);
+   ed->fill.abs_x = 0;
+   ed->fill.pos_rel_y = FROM_DOUBLE(0.0);
+   ed->fill.pos_abs_y = 0;
+   ed->fill.rel_y = FROM_DOUBLE(1.0);
+   ed->fill.abs_y = 0;
+   ed->fill.angle = 0;
+   ed->fill.spread = 0;
+   ed->fill.type = EDJE_FILL_TYPE_SCALE;
+   ed->color_class = NULL;
+   ed->color.r = 255;
+   ed->color.g = 255;
+   ed->color.b = 255;
+   ed->color.a = 255;
+   ed->color2.r = 0;
+   ed->color2.g = 0;
+   ed->color2.b = 0;
+   ed->color2.a = 255;
+   ed->color3.r = 0;
+   ed->color3.g = 0;
+   ed->color3.b = 0;
+   ed->color3.a = 128;
+   ed->text.align.x = FROM_DOUBLE(0.5);
+   ed->text.align.y = FROM_DOUBLE(0.5);
+   ed->text.id_source = -1;
+   ed->text.id_text_source = -1;
+   ed->gradient.rel1.relative_x = FROM_INT(0);
+   ed->gradient.rel1.relative_y = FROM_INT(0);
+   ed->gradient.rel1.offset_x = 0;
+   ed->gradient.rel1.offset_y = 0;
+   ed->gradient.rel2.relative_x = FROM_INT(1);
+   ed->gradient.rel2.relative_y = FROM_INT(1);
+   ed->gradient.rel2.offset_x = -1;
+   ed->gradient.rel2.offset_y = -1;
+   ed->box.layout = NULL;
+   ed->box.alt_layout = NULL;
+   ed->box.align.x = FROM_DOUBLE(0.5);
+   ed->box.align.y = FROM_DOUBLE(0.5);
+   ed->box.padding.x = 0;
+   ed->box.padding.y = 0;
+   ed->table.homogeneous = EDJE_OBJECT_TABLE_HOMOGENEOUS_NONE;
+   ed->table.align.x = FROM_DOUBLE(0.5);
+   ed->table.align.y = FROM_DOUBLE(0.5);
+   ed->table.padding.x = 0;
+   ed->table.padding.y = 0;
+   ed->map.id_persp = -1;
+   ed->map.id_light = -1;
+   ed->map.rot.id_center = -1;
+   ed->map.rot.x = FROM_DOUBLE(0.0);
+   ed->map.rot.y = FROM_DOUBLE(0.0);
+   ed->map.rot.z = FROM_DOUBLE(0.0);
+   ed->map.on = 0;
+   ed->map.smooth = 1;
+   ed->map.alpha = 1;
+   ed->map.backcull = 0;
+   ed->map.persp_on = 0;
+   ed->persp.zplane = 0;
+   ed->persp.focal = 1000;
+   ed->external_params = NULL;
+}
+
+/**
+    @page edcref
+    @property
+        inherit
+    @parameters
+        [another description's name] [another description's index]
+    @effect
+        When set, the description will inherit all the properties from the
+        named description. The properties defined in this part will override
+        the inherited properties, reducing the amount of necessary code for
+        simple state changes. Note: inheritance in Edje is single level only.
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_description_inherit(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Part_Description *ed, *parent = NULL;
+   Eina_List *l;
+   Edje_Part_Image_Id *iid;
+   char *parent_name;
+   const char *state_name;
+   double parent_val, state_val;
+
+   check_arg_count(2);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+
+   /* inherit may not be used in the default description */
+   if (!ep->other_desc)
+     {
+       ERR("%s: Error. parse error %s:%i. "
+           "inherit may not be used in the default description",
+           progname, file_in, line - 1);
+       exit(-1);
+     }
+
+   ed = eina_list_data_get(eina_list_last(ep->other_desc));
+
+   if (!ed->state.name)
+     {
+        ERR("%s: Error. parse error %s:%i. "
+           "inherit may only be used after state",
+           progname, file_in, line - 1);
+       exit(-1);
+     }
+
+   /* find the description that we inherit from */
+   parent_name = parse_str(0);
+   parent_val = parse_float_range(1, 0.0, 1.0);
+
+   if (!strcmp (parent_name, "default") && parent_val == 0.0)
+     parent = ep->default_desc;
+   else
+     {
+       double min_dst = 999.0;
+       Edje_Part_Description *d;
+
+       if (!strcmp(parent_name, "default"))
+         {
+            parent = ep->default_desc;
+            min_dst = ABS(ep->default_desc->state.value - parent_val);
+         }
+
+       EINA_LIST_FOREACH(ep->other_desc, l, d)
+         {
+            if (!strcmp (d->state.name, parent_name))
+              {
+                 double dst;
+
+                 dst = ABS(d->state.value - parent_val);
+                 if (dst < min_dst)
+                   {
+                      parent = d;
+                      min_dst = dst;
+                   }
+              }
+         }
+     }
+
+   if (!parent)
+     {
+       ERR("%s: Error. parse error %s:%i. "
+           "cannot find referenced part state %s %lf",
+           ep->name, file_in, line - 1, parent_name, parent_val);
+       exit(-1);
+     }
+
+   free (parent_name);
+
+   /* now do a full copy, only state info will be kept */
+   state_name = ed->state.name;
+   state_val = ed->state.value;
+
+   *ed = *parent;
+
+   ed->state.name = state_name;
+   ed->state.value = state_val;
+
+   data_queue_part_slave_lookup(&parent->rel1.id_x, &ed->rel1.id_x);
+   data_queue_part_slave_lookup(&parent->rel1.id_y, &ed->rel1.id_y);
+   data_queue_part_slave_lookup(&parent->rel2.id_x, &ed->rel2.id_x);
+   data_queue_part_slave_lookup(&parent->rel2.id_y, &ed->rel2.id_y);
+   data_queue_image_slave_lookup(&parent->image.id, &ed->image.id);
+   data_queue_spectrum_slave_lookup(&parent->gradient.id, &ed->gradient.id);
+
+   /* make sure all the allocated memory is getting copied, not just
+    * referenced
+    */
+   ed->image.tween_list = NULL;
+
+   EINA_LIST_FOREACH(parent->image.tween_list, l, iid)
+     {
+       Edje_Part_Image_Id *iid_new;
+
+       iid_new = mem_alloc(SZ(Edje_Part_Image_Id));
+       data_queue_image_slave_lookup(&(iid->id), &(iid_new->id));
+       ed->image.tween_list = eina_list_append(ed->image.tween_list, iid_new);
+     }
+
+#define STRDUP(x) x ? strdup(x) : NULL
+
+   ed->color_class = STRDUP(ed->color_class);
+   ed->text.text = STRDUP(ed->text.text);
+   ed->text.text_class = STRDUP(ed->text.text_class);
+   ed->text.font = STRDUP(ed->text.font);
+#undef STRDUP
+
+   data_queue_part_slave_lookup(&(parent->text.id_source), &(ed->text.id_source));
+   data_queue_part_slave_lookup(&(parent->text.id_text_source), &(ed->text.id_text_source));
+
+   if (parent->external_params)
+     {
+       Eina_List *l;
+       Edje_External_Param *param, *new_param;
+
+       ed->external_params = NULL;
+       EINA_LIST_FOREACH(parent->external_params, l, param)
+         {
+            new_param = mem_alloc(SZ(Edje_External_Param));
+            *new_param = *param;
+            ed->external_params = eina_list_append(ed->external_params, new_param);
+         }
+     }
+}
+
+/**
+    @page edcref
+    @property
+        state
+    @parameters
+        [a name for the description] [an index]
+    @effect
+        Sets a name used to identify a description inside a given part.
+        Multiple descriptions are used to declare different states of the same
+        part, like "clicked" or "invisible". All states declarations are also
+        coupled with an index number between 0.0 and 1.0. All parts must have
+        at least one description named "default 0.0".
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_description_state(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Part_Description *ed;
+   char *s;
+
+   check_arg_count(2);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+   ed = ep->default_desc;
+   if (ep->other_desc) ed = eina_list_data_get(eina_list_last(ep->other_desc));
+
+   s = parse_str(0);
+   if (!strcmp (s, "custom"))
+     {
+       ERR("%s: Error. parse error %s:%i. "
+           "invalid state name: '%s'.",
+           progname, file_in, line - 1, s);
+       exit(-1);
+     }
+
+   ed->state.name = s;
+   ed->state.value = parse_float_range(1, 0.0, 1.0);
+}
+
+/**
+    @page edcref
+    @property
+        visible
+    @parameters
+        [0 or 1]
+    @effect
+        Takes a boolean value specifying whether part is visible (1) or not
+        (0). Non-visible parts do not emit signals. The default value is 1.
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_description_visible(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Part_Description *ed;
+
+   check_arg_count(1);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+   ed = ep->default_desc;
+   if (ep->other_desc) ed = eina_list_data_get(eina_list_last(ep->other_desc));
+   ed->visible = parse_bool(0);
+}
+
+/**
+    @page edcref
+    @property
+        align
+    @parameters
+        [X axis] [Y axis]
+    @effect
+        When the displayed object's size is smaller than its container, this
+        property moves it relatively along both axis inside its container. The
+        default value is "0.5 0.5".
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_description_align(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Part_Description *ed;
+
+   check_arg_count(2);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+   ed = ep->default_desc;
+   if (ep->other_desc) ed = eina_list_data_get(eina_list_last(ep->other_desc));
+   ed->align.x = FROM_DOUBLE(parse_float_range(0, 0.0, 1.0));
+   ed->align.y = FROM_DOUBLE(parse_float_range(1, 0.0, 1.0));
+}
+
+/**
+    @page edcref
+    @property
+        fixed
+    @parameters
+        [width, 0 or 1] [height, 0 or 1]
+    @effect
+        This affects the minimum size calculation. See
+        edje_object_size_min_calc() and edje_object_size_min_restricted_calc().
+        This tells the min size calculation routine that this part does not
+        change size in width or height (1 for it doesn't, 0 for it does), so
+        the routine should not try and expand or contract the part.
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_description_fixed(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Part_Description *ed;
+
+   check_arg_count(2);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+   ed = ep->default_desc;
+   if (ep->other_desc) ed = eina_list_data_get(eina_list_last(ep->other_desc));
+   ed->fixed.w = parse_float_range(0, 0, 1);
+   ed->fixed.h = parse_float_range(1, 0, 1);
+}
+
+/**
+    @page edcref
+    @property
+        min
+    @parameters
+        [width] [height]
+    @effect
+        The minimum size of the state.
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_description_min(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Part_Description *ed;
+
+   check_arg_count(2);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+   ed = ep->default_desc;
+   if (ep->other_desc) ed = eina_list_data_get(eina_list_last(ep->other_desc));
+   ed->min.w = parse_float_range(0, 0, 0x7fffffff);
+   ed->min.h = parse_float_range(1, 0, 0x7fffffff);
+}
+
+/**
+    @page edcref
+    @property
+        max
+    @parameters
+        [width] [height]
+    @effect
+        The maximum size of the state.
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_description_max(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Part_Description *ed;
+
+   check_arg_count(2);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+   ed = ep->default_desc;
+   if (ep->other_desc) ed = eina_list_data_get(eina_list_last(ep->other_desc));
+   ed->max.w = parse_float_range(0, 0, 0x7fffffff);
+   ed->max.h = parse_float_range(1, 0, 0x7fffffff);
+}
+
+/**
+    @page edcref
+    @property
+        step
+    @parameters
+        [width] [height]
+    @effect
+        Restricts resizing of each dimension to values divisibles by its value.
+        This causes the part to jump from value to value while resizing. The
+        default value is "0 0" disabling stepping.
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_description_step(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Part_Description *ed;
+
+   check_arg_count(2);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+   ed = ep->default_desc;
+   if (ep->other_desc) ed = eina_list_data_get(eina_list_last(ep->other_desc));
+   ed->step.x = parse_float_range(0, 0, 0x7fffffff);
+   ed->step.y = parse_float_range(1, 0, 0x7fffffff);
+}
+
+/**
+    @page edcref
+    @property
+        aspect
+    @parameters
+        [min] [max]
+    @effect
+        Normally width and height can be resized to any values independently.
+        The aspect property forces the width to height ratio to be kept between
+        the minimum and maximum set. For example, "1.0 1.0" will increase the
+        width a pixel for every pixel added to heigh. The default value is
+        "0.0 0.0" disabling aspect.
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_description_aspect(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Part_Description *ed;
+
+   check_arg_count(2);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+   ed = ep->default_desc;
+   if (ep->other_desc) ed = eina_list_data_get(eina_list_last(ep->other_desc));
+   ed->aspect.min = FROM_DOUBLE(parse_float_range(0, 0.0, 999999999.0));
+   ed->aspect.max = FROM_DOUBLE(parse_float_range(1, 0.0, 999999999.0));
+}
+
+/**
+    @page edcref
+    @property
+        aspect_preference
+    @parameters
+        [DIMENSION]
+    @effect
+        Sets the scope of the "aspect" property to a given dimension. Available
+        options are BOTH, VERTICAL, HORIZONTAL and NONE
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_description_aspect_preference(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Part_Description *ed;
+
+   check_arg_count(1);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+   ed = ep->default_desc;
+   if (ep->other_desc) ed = eina_list_data_get(eina_list_last(ep->other_desc));
+   ed->aspect.prefer =  parse_enum(0,
+                                  "NONE", EDJE_ASPECT_PREFER_NONE,
+                                  "VERTICAL", EDJE_ASPECT_PREFER_VERTICAL,
+                                  "HORIZONTAL", EDJE_ASPECT_PREFER_HORIZONTAL,
+                                  "BOTH", EDJE_ASPECT_PREFER_BOTH,
+                                  NULL);
+}
+
+/**
+    @page edcref
+    @property
+        color_class
+    @parameters
+        [color class name]
+    @effect
+        The part will use the color values of the named color_class, these
+        values can be overrided by the "color", "color2" and "color3"
+        properties set below.
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_description_color_class(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Part_Description *ed;
+
+   check_arg_count(1);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+   ed = ep->default_desc;
+   if (ep->other_desc) ed = eina_list_data_get(eina_list_last(ep->other_desc));
+   ed->color_class = parse_str(0);
+}
+
+/**
+    @page edcref
+    @property
+        color
+    @parameters
+        [red] [green] [blue] [alpha]
+    @effect
+        Sets the main color to the specified values (between 0 and 255).
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_description_color(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Part_Description *ed;
+
+   check_arg_count(4);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+   ed = ep->default_desc;
+   if (ep->other_desc) ed = eina_list_data_get(eina_list_last(ep->other_desc));
+   ed->color.r = parse_int_range(0, 0, 255);
+   ed->color.g = parse_int_range(1, 0, 255);
+   ed->color.b = parse_int_range(2, 0, 255);
+   ed->color.a = parse_int_range(3, 0, 255);
+}
+
+/**
+    @page edcref
+    @property
+        color2
+    @parameters
+        [red] [green] [blue] [alpha]
+    @effect
+        Sets the text shadow color to the specified values (0 to 255).
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_description_color2(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Part_Description *ed;
+
+   check_arg_count(4);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+   ed = ep->default_desc;
+   if (ep->other_desc) ed = eina_list_data_get(eina_list_last(ep->other_desc));
+   ed->color2.r = parse_int_range(0, 0, 255);
+   ed->color2.g = parse_int_range(1, 0, 255);
+   ed->color2.b = parse_int_range(2, 0, 255);
+   ed->color2.a = parse_int_range(3, 0, 255);
+}
+
+/**
+    @page edcref
+    @property
+        color3
+    @parameters
+        [red] [green] [blue] [alpha]
+    @effect
+        Sets the text outline color to the specified values (0 to 255).
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_description_color3(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Part_Description *ed;
+
+   check_arg_count(4);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+   ed = ep->default_desc;
+   if (ep->other_desc) ed = eina_list_data_get(eina_list_last(ep->other_desc));
+   ed->color3.r = parse_int_range(0, 0, 255);
+   ed->color3.g = parse_int_range(1, 0, 255);
+   ed->color3.b = parse_int_range(2, 0, 255);
+   ed->color3.a = parse_int_range(3, 0, 255);
+}
+
+/**
+    @page edcref
+    @block
+        rel1/rel2
+    @context
+        description {
+            ..
+            rel1 {
+                relative: 0.0 0.0;
+                offset:     0   0;
+            }
+            ..
+            rel2 {
+                relative: 1.0 1.0;
+                offset:    -1  -1;
+            }
+            ..
+        }
+    @description
+        The rel1 and rel2 blocks are used to define the position of each corner
+        of the part's container. With rel1 being the left-up corner and rel2
+        being the right-down corner.
+    @endblock
+
+    @property
+        relative
+    @parameters
+        [X axis] [Y axis]
+    @effect
+        Moves a corner to a relative position inside the container of the
+        relative "to" part. Values from 0.0 (0%, begining) to 1.0 (100%, end)
+        of each axis.
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_description_rel1_relative(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Part_Description *ed;
+
+   check_arg_count(2);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+   ed = ep->default_desc;
+   if (ep->other_desc) ed = eina_list_data_get(eina_list_last(ep->other_desc));
+   ed->rel1.relative_x = FROM_DOUBLE(parse_float(0));
+   ed->rel1.relative_y = FROM_DOUBLE(parse_float(1));
+}
+
+/**
+    @page edcref
+    @property
+        offset
+    @parameters
+        [X axis] [Y axis]
+    @effect
+        Affects the corner postion a fixed number of pixels along each axis.
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_description_rel1_offset(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Part_Description *ed;
+
+   check_arg_count(2);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+   ed = ep->default_desc;
+   if (ep->other_desc) ed = eina_list_data_get(eina_list_last(ep->other_desc));
+   ed->rel1.offset_x = parse_int(0);
+   ed->rel1.offset_y = parse_int(1);
+}
+
+/**
+    @page edcref
+    @property
+        to
+    @parameters
+        [another part's name]
+    @effect
+        Causes a corner to be positioned relatively to another part's
+        container.
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_description_rel1_to(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Part_Description *ed;
+
+   check_arg_count(1);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+   ed = ep->default_desc;
+   if (ep->other_desc) ed = eina_list_data_get(eina_list_last(ep->other_desc));
+     {
+       char *name;
+
+       name = parse_str(0);
+       data_queue_part_lookup(pc, name, &(ed->rel1.id_x));
+       data_queue_part_lookup(pc, name, &(ed->rel1.id_y));
+       free(name);
+     }
+}
+
+/**
+    @page edcref
+    @property
+        to_x
+    @parameters
+        [another part's name]
+    @effect
+        Causes a corner to be positioned relatively to the X axis of another
+        part's container. Simply put affects the first parameter of "relative".
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_description_rel1_to_x(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Part_Description *ed;
+
+   check_arg_count(1);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+   ed = ep->default_desc;
+   if (ep->other_desc) ed = eina_list_data_get(eina_list_last(ep->other_desc));
+     {
+       char *name;
+
+       name = parse_str(0);
+       data_queue_part_lookup(pc, name, &(ed->rel1.id_x));
+       free(name);
+     }
+}
+
+/**
+    @page edcref
+    @property
+        to_y
+    @parameters
+        [another part's name]
+    @effect
+        Causes a corner to be positioned relatively to the Y axis of another
+        part's container. Simply put, affects the second parameter of
+        "relative".
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_description_rel1_to_y(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Part_Description *ed;
+
+   check_arg_count(1);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+   ed = ep->default_desc;
+   if (ep->other_desc) ed = eina_list_data_get(eina_list_last(ep->other_desc));
+     {
+       char *name;
+
+       name = parse_str(0);
+       data_queue_part_lookup(pc, name, &(ed->rel1.id_y));
+       free(name);
+     }
+}
+
+static void
+st_collections_group_parts_part_description_rel2_relative(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Part_Description *ed;
+
+   check_arg_count(2);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+   ed = ep->default_desc;
+   if (ep->other_desc) ed = eina_list_data_get(eina_list_last(ep->other_desc));
+   ed->rel2.relative_x = FROM_DOUBLE(parse_float(0));
+   ed->rel2.relative_y = FROM_DOUBLE(parse_float(1));
+}
+
+static void
+st_collections_group_parts_part_description_rel2_offset(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Part_Description *ed;
+
+   check_arg_count(2);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+   ed = ep->default_desc;
+   if (ep->other_desc) ed = eina_list_data_get(eina_list_last(ep->other_desc));
+   ed->rel2.offset_x = parse_int(0);
+   ed->rel2.offset_y = parse_int(1);
+}
+
+static void
+st_collections_group_parts_part_description_rel2_to(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Part_Description *ed;
+
+   check_arg_count(1);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+   ed = ep->default_desc;
+   if (ep->other_desc) ed = eina_list_data_get(eina_list_last(ep->other_desc));
+     {
+       char *name;
+
+       name = parse_str(0);
+       data_queue_part_lookup(pc, name, &(ed->rel2.id_x));
+       data_queue_part_lookup(pc, name, &(ed->rel2.id_y));
+       free(name);
+     }
+}
+
+static void
+st_collections_group_parts_part_description_rel2_to_x(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Part_Description *ed;
+
+   check_arg_count(1);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+   ed = ep->default_desc;
+   if (ep->other_desc) ed = eina_list_data_get(eina_list_last(ep->other_desc));
+     {
+       char *name;
+
+       name = parse_str(0);
+       data_queue_part_lookup(pc, name, &(ed->rel2.id_x));
+       free(name);
+     }
+}
+
+static void
+st_collections_group_parts_part_description_rel2_to_y(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Part_Description *ed;
+
+   check_arg_count(1);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+   ed = ep->default_desc;
+   if (ep->other_desc) ed = eina_list_data_get(eina_list_last(ep->other_desc));
+     {
+       char *name;
+
+       name = parse_str(0);
+       data_queue_part_lookup(pc, name, &(ed->rel2.id_y));
+       free(name);
+     }
+}
+
+/**
+   @edcsection{description_image,Image state description sub blocks}
+ */
+
+/**
+    @page edcref
+    @block
+        image
+    @context
+        description {
+            ..
+            image {
+                normal: "filename.ext";
+                tween:  "filename2.ext";
+                ..
+                tween:  "filenameN.ext";
+                border:  left right top bottom;
+                middle:  0/1/NONE/DEFAULT/SOLID;
+            }
+            ..
+        }
+    @description
+    @endblock
+
+    @property
+        normal
+    @parameters
+        [image's filename]
+    @effect
+        Name of image to be used as previously declared in the  images block.
+        In an animation, this is the first and last image displayed. It's
+        required in any image part
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_description_image_normal(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Part_Description *ed;
+
+   check_arg_count(1);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+
+   if (ep->type != EDJE_PART_TYPE_IMAGE)
+     {
+       ERR("%s: Error. parse error %s:%i. "
+           "image attributes in non-IMAGE part.",
+           progname, file_in, line - 1);
+       exit(-1);
+     }
+
+   ed = ep->default_desc;
+   if (ep->other_desc) ed = eina_list_data_get(eina_list_last(ep->other_desc));
+     {
+       char *name;
+
+       name = parse_str(0);
+       data_queue_image_lookup(name, &(ed->image.id));
+       free(name);
+     }
+}
+
+/**
+    @page edcref
+    @property
+        tween
+    @parameters
+        [image's filename]
+    @effect
+        Name of an image to be used in an animation loop, an image block can
+        have none, one or multiple tween declarations. Images are displayed in
+        the order they are listed.
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_description_image_tween(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Part_Description *ed;
+
+   check_arg_count(1);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+
+   if (ep->type != EDJE_PART_TYPE_IMAGE)
+     {
+       ERR("%s: Error. parse error %s:%i. "
+           "image attributes in non-IMAGE part.",
+           progname, file_in, line - 1);
+       exit(-1);
+     }
+
+   ed = ep->default_desc;
+   if (ep->other_desc) ed = eina_list_data_get(eina_list_last(ep->other_desc));
+     {
+       char *name;
+       Edje_Part_Image_Id *iid;
+
+       iid = mem_alloc(SZ(Edje_Part_Image_Id));
+       ed->image.tween_list = eina_list_append(ed->image.tween_list, iid);
+       name = parse_str(0);
+       data_queue_image_lookup(name, &(iid->id));
+       free(name);
+     }
+}
+
+/**
+    @page edcref
+    @property
+        border
+    @parameters
+        [left] [right] [top] [bottom]
+    @effect
+        If set, the area (in pixels) of each side of the image will be
+        displayed as a fixed size border, from the side -> inwards, preventing
+        the corners from being changed on a resize.
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_description_image_border(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Part_Description *ed;
+
+   check_arg_count(4);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+
+   if (ep->type != EDJE_PART_TYPE_IMAGE)
+     {
+       ERR("%s: Error. parse error %s:%i. "
+           "image attributes in non-IMAGE part.",
+           progname, file_in, line - 1);
+       exit(-1);
+     }
+
+   ed = ep->default_desc;
+   if (ep->other_desc) ed = eina_list_data_get(eina_list_last(ep->other_desc));
+   ed->border.l = parse_int_range(0, 0, 0x7fffffff);
+   ed->border.r = parse_int_range(1, 0, 0x7fffffff);
+   ed->border.t = parse_int_range(2, 0, 0x7fffffff);
+   ed->border.b = parse_int_range(3, 0, 0x7fffffff);
+}
+
+/**
+    @page edcref
+    @property
+        middle
+    @parameters
+        0, 1, NONE, DEFAULT, SOLID
+    @effect
+        If border is set, this value tells Edje if the rest of the
+        image (not covered by the defined border) will be displayed or not
+        or be assumed to be solid (without alpha). The default is 1/DEFAULT.
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_description_image_middle(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Part_Description *ed;
+
+   check_arg_count(1);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+
+   if (ep->type != EDJE_PART_TYPE_IMAGE)
+     {
+       ERR("%s: Error. parse error %s:%i. "
+           "image attributes in non-IMAGE part.",
+           progname, file_in, line - 1);
+       exit(-1);
+     }
+
+   ed = ep->default_desc;
+   if (ep->other_desc) ed = eina_list_data_get(eina_list_last(ep->other_desc));
+   ed->border.no_fill =  parse_enum(0,
+                                    "1", 0,
+                                    "DEFAULT", 0,
+                                    "0", 1,
+                                    "NONE", 1,
+                                    "SOLID", 2,
+                                    NULL);
+}
+
+/**
+    @page edcref
+    @property
+        border_scale
+    @parameters
+        0, 1
+    @effect
+        If border is set, this value tells Edje if the border should be scaled
+        by the object/global edje scale factors
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_description_image_border_scale(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Part_Description *ed;
+
+   check_arg_count(1);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+
+   if (ep->type != EDJE_PART_TYPE_IMAGE)
+     {
+       ERR("%s: Error. parse error %s:%i. "
+           "image attributes in non-IMAGE part.",
+           progname, file_in, line - 1);
+       exit(-1);
+     }
+
+   ed = ep->default_desc;
+   if (ep->other_desc) ed = eina_list_data_get(eina_list_last(ep->other_desc));
+   ed->border.scale =  parse_enum(0,
+                                  "1", 0,
+                                  "0", 1,
+                                  NULL);
+}
+
+/**
+    @page edcref
+    @property
+        scale_hint
+    @parameters
+        0, NONE, DYNAMIC, STATIC
+    @effect
+        Sets the evas image scale hint letting the engine more effectively save
+        cached copies of the scaled image if it makes sense
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_description_image_scale_hint(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Part_Description *ed;
+
+   check_arg_count(1);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+
+   if (ep->type != EDJE_PART_TYPE_IMAGE)
+     {
+       ERR("%s: Error. parse error %s:%i. "
+           "image attributes in non-IMAGE part.",
+           progname, file_in, line - 1);
+       exit(-1);
+     }
+
+   ed = ep->default_desc;
+   if (ep->other_desc) ed = eina_list_data_get(eina_list_last(ep->other_desc));
+   ed->image.scale_hint =  parse_enum(0,
+                                    "NONE", EVAS_IMAGE_SCALE_HINT_NONE,
+                                    "DYNAMIC", EVAS_IMAGE_SCALE_HINT_DYNAMIC,
+                                    "STATIC", EVAS_IMAGE_SCALE_HINT_STATIC,
+                                    "0", EVAS_IMAGE_SCALE_HINT_NONE,
+                                    NULL);
+}
+
+/**
+    @page edcref
+    @block
+        fill
+    @context
+        description {
+            ..
+            fill {
+                smooth: 0-1;
+                origin {
+                    relative: X-axis Y-axis;
+                    offset:   X-axis Y-axis;
+                }
+                size {
+                    relative: width  height;
+                    offset:   width  height;
+                }
+            }
+            ..
+        }
+    @description
+        The fill method is an optional block that defines the way an IMAGE or
+        GRADIENT part is going to be displayed inside its container.
+    @endblock
+
+    @property
+        smooth
+    @parameters
+        [0 or 1]
+    @effect
+        The smooth property takes a boolean value to decide if the image will
+        be smoothed on scaling (1) or not (0). The default value is 1.
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_description_fill_smooth(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Part_Description *ed;
+
+   check_arg_count(1);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+
+   if (ep->type != EDJE_PART_TYPE_IMAGE)
+     {
+       ERR("%s: Error. parse error %s:%i. "
+           "fill.type attribute in non-IMAGE part.",
+           progname, file_in, line - 1);
+       exit(-1);
+     }
+
+   ed = ep->default_desc;
+   if (ep->other_desc) ed = eina_list_data_get(eina_list_last(ep->other_desc));
+   ed->fill.smooth = parse_bool(0);
+}
+
+/**
+    @page edcref
+
+    @property
+        spread
+    @parameters
+        TODO
+    @effect
+        TODO
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_description_fill_spread(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Part_Description *ed;
+
+   check_arg_count(1);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+
+   /* XXX this will need to include IMAGES when spread support is added to evas images */
+   if (ep->type != EDJE_PART_TYPE_GRADIENT)
+     {
+       fprintf(stderr, "%s: Error. parse error %s:%i. "
+               "gradient attributes in non-GRADIENT part.\n",
+               progname, file_in, line - 1);
+       exit(-1);
+     }
+
+   ed = ep->default_desc;
+   if (ep->other_desc) ed = eina_list_data_get(eina_list_last(ep->other_desc));
+   ed->fill.spread = parse_int_range(0, 0, 1);
+}
+
+/**
+    @page edcref
+
+    @property
+        angle
+    @parameters
+        [angle]
+    @effect
+        The angle of rotation of a GRADIENT part. It is invalid in any other
+        part type. The angle is expressed as an int, in the range 0 - 360.
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_description_fill_angle(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Part_Description *ed;
+
+   check_arg_count(1);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+
+   /* XXX this will need to include IMAGES when angle support is added to evas images */
+   if (ep->type != EDJE_PART_TYPE_GRADIENT)
+     {
+       ERR("%s: Error. parse error %s:%i. "
+           "gradient attributes in non-GRADIENT part.",
+           progname, file_in, line - 1);
+       exit(-1);
+     }
+
+   ed = ep->default_desc;
+   if (ep->other_desc) ed = eina_list_data_get(eina_list_last(ep->other_desc));
+   ed->fill.angle = parse_int_range(0, 0, 360);
+}
+
+/**
+    @page edcref
+
+    @property
+        type
+    @parameters
+        TODO
+    @effect
+        TODO
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_description_fill_type(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Part_Description *ed;
+
+   check_arg_count(1);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+   ed = ep->default_desc;
+   if (ep->other_desc) ed = eina_list_data_get(eina_list_last(ep->other_desc));
+
+   if (ep->type != EDJE_PART_TYPE_IMAGE)
+     {
+       ERR("%s: Error. parse error %s:%i. "
+           "fill attributes in non-IMAGE part.",
+           progname, file_in, line - 1);
+       exit(-1);
+     }
+
+   ed->fill.type = parse_enum(0,
+                              "SCALE", EDJE_FILL_TYPE_SCALE,
+                              "TILE", EDJE_FILL_TYPE_TILE,
+                              NULL);
+}
+
+/**
+    @page edcref
+    @block
+        origin
+    @context
+        description {
+            ..
+            fill {
+                ..
+                origin {
+                    relative: 0.0 0.0;
+                    offset:   0   0;
+                }
+                ..
+            }
+            ..
+        }
+    @description
+        The origin block is used to place the starting point, inside the
+        displayed element, that will be used to render the tile. By default,
+        the origin is set at the element's left-up corner.
+    @endblock
+
+    @property
+        relative
+    @parameters
+        [X axis] [Y axis]
+    @effect
+        Sets the starting point relatively to displayed element's content.
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_description_fill_origin_relative(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Part_Description *ed;
+
+   check_arg_count(2);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+
+   if (ep->type != EDJE_PART_TYPE_IMAGE && ep->type != EDJE_PART_TYPE_GRADIENT)
+     {
+       ERR("%s: Error. parse error %s:%i. "
+           "fill attributes in non-IMAGE part.",
+           progname, file_in, line - 1);
+       exit(-1);
+     }
+
+   ed = ep->default_desc;
+   if (ep->other_desc) ed = eina_list_data_get(eina_list_last(ep->other_desc));
+   ed->fill.pos_rel_x = FROM_DOUBLE(parse_float_range(0, -999999999.0, 999999999.0));
+   ed->fill.pos_rel_y = FROM_DOUBLE(parse_float_range(1, -999999999.0, 999999999.0));
+}
+
+/**
+    @page edcref
+    @property
+        offset
+    @parameters
+        [X axis] [Y axis]
+    @effect
+        Affects the starting point a fixed number of pixels along each axis.
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_description_fill_origin_offset(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Part_Description *ed;
+
+   check_arg_count(2);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+
+   if (ep->type != EDJE_PART_TYPE_IMAGE && ep->type != EDJE_PART_TYPE_GRADIENT)
+     {
+       ERR("%s: Error. parse error %s:%i. "
+           "fill attributes in non-IMAGE part.",
+           progname, file_in, line - 1);
+       exit(-1);
+     }
+
+   ed = ep->default_desc;
+   if (ep->other_desc) ed = eina_list_data_get(eina_list_last(ep->other_desc));
+   ed->fill.pos_abs_x = parse_int(0);
+   ed->fill.pos_abs_y = parse_int(1);
+}
+
+/**
+    @page edcref
+    @block
+        size
+    @context
+        description {
+            ..
+            fill {
+                ..
+                size {
+                    relative: 1.0 1.0;
+                    offset:  -1  -1;
+                }
+                ..
+            }
+            ..
+        }
+    @description
+        The size block defines the tile size of the content that will be
+        displayed.
+    @endblock
+
+    @property
+        relative
+    @parameters
+        [width] [height]
+    @effect
+        Takes a pair of decimal values that represent the a percentual value
+        of the original size of the element. For example, "0.5 0.5" represents
+        half the size, while "2.0 2.0" represents the double. The default
+        value is "1.0 1.0".
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_description_fill_size_relative(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Part_Description *ed;
+
+   check_arg_count(2);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+   ed = ep->default_desc;
+   if (ep->other_desc) ed = eina_list_data_get(eina_list_last(ep->other_desc));
+
+   if (ep->type != EDJE_PART_TYPE_IMAGE && ep->type != EDJE_PART_TYPE_GRADIENT)
+     {
+       ERR("%s: Error. parse error %s:%i. "
+           "fill attributes in non-IMAGE part.",
+           progname, file_in, line - 1);
+       exit(-1);
+     }
+
+   ed->fill.rel_x = FROM_DOUBLE(parse_float_range(0, 0.0, 999999999.0));
+   ed->fill.rel_y = FROM_DOUBLE(parse_float_range(1, 0.0, 999999999.0));
+}
+
+/**
+    @page edcref
+    @property
+        offset
+    @parameters
+        [X axis] [Y axis]
+    @effect
+        Affects the size of the tile a fixed number of pixels along each axis.
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_description_fill_size_offset(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Part_Description *ed;
+
+   check_arg_count(2);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+   ed = ep->default_desc;
+   if (ep->other_desc) ed = eina_list_data_get(eina_list_last(ep->other_desc));
+
+   if (ep->type != EDJE_PART_TYPE_IMAGE && ep->type != EDJE_PART_TYPE_GRADIENT)
+     {
+       ERR("%s: Error. parse error %s:%i. "
+           "fill attributes in non-IMAGE part.",
+           progname, file_in, line - 1);
+       exit(-1);
+     }
+
+   ed->fill.abs_x = parse_int(0);
+   ed->fill.abs_y = parse_int(1);
+}
+
+
+/**
+   @edcsection{description_text,Text state description sub blocks}
+ */
+
+/**
+    @page edcref
+
+    @block
+        text
+    @context
+        part {
+            description {
+                ..
+                text {
+                    text:        "some string of text to display";
+                    font:        "font_name";
+                    size:         SIZE;
+                    text_class:  "class_name";
+                    fit:          horizontal vertical;
+                    min:          horizontal vertical;
+                    max:          horizontal vertical;
+                    align:        X-axis     Y-axis;
+                    source:      "part_name";
+                    text_source: "text_part_name";
+                    elipsis:      0.0-1.0;
+                    style:       "stylename";
+                }
+                ..
+            }
+        }
+    @description
+    @endblock
+
+    @property
+        text
+    @parameters
+        [a string of text, or nothing]
+    @effect
+        Sets the default content of a text part, normally the application is
+        the one changing its value.
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_description_text_text(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Part_Description *ed;
+   char *str = NULL;
+   int i;
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+
+   if ((ep->type != EDJE_PART_TYPE_TEXT) &&
+       (ep->type != EDJE_PART_TYPE_TEXTBLOCK))
+     {
+       ERR("%s: Error. parse error %s:%i. "
+           "text attributes in non-TEXT part.",
+           progname, file_in, line - 1);
+       exit(-1);
+     }
+
+   ed = ep->default_desc;
+   if (ep->other_desc) ed = eina_list_data_get(eina_list_last(ep->other_desc));
+   for (i = 0; ;i++)
+     {
+       char *s;
+
+       if (!is_param(i)) break;
+       s = parse_str(i);
+       if (!str) str = s;
+       else
+         {
+            str = realloc(str, strlen(str) + strlen(s) + 1);
+            strcat(str, s);
+            free(s);
+         }
+     }
+   ed->text.text = str;
+}
+
+/**
+    @page edcref
+
+    @property
+        text_class
+    @parameters
+        [text class name]
+    @effect
+        Similar to color_class, this is the name used by the application
+        to alter the font family and size at runtime.
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_description_text_text_class(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Part_Description *ed;
+
+   check_arg_count(1);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+
+   if ((ep->type != EDJE_PART_TYPE_TEXT) &&
+       (ep->type != EDJE_PART_TYPE_TEXTBLOCK))
+     {
+       ERR("%s: Error. parse error %s:%i. "
+           "text attributes in non-TEXT part.",
+           progname, file_in, line - 1);
+       exit(-1);
+     }
+
+   ed = ep->default_desc;
+   if (ep->other_desc) ed = eina_list_data_get(eina_list_last(ep->other_desc));
+   ed->text.text_class = parse_str(0);
+}
+
+/**
+    @page edcref
+
+    @property
+        font
+    @parameters
+        [font alias]
+    @effect
+        This sets the font family to one of the aliases set up in the "fonts"
+        block. Can be overrided by the application.
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_description_text_font(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Part_Description *ed;
+
+   check_arg_count(1);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+
+   if (ep->type != EDJE_PART_TYPE_TEXT)
+     {
+       ERR("%s: Error. parse error %s:%i. "
+           "text attributes in non-TEXT part.",
+           progname, file_in, line - 1);
+       exit(-1);
+     }
+
+   ed = ep->default_desc;
+   if (ep->other_desc) ed = eina_list_data_get(eina_list_last(ep->other_desc));
+   ed->text.font = parse_str(0);
+}
+
+/**
+    @page edcref
+
+    @property
+        style
+    @parameters
+        [the style name]
+    @effect
+        Causes the part to use the default style and tags defined in the
+        "style" block with the specified name.
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_description_text_style(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Part_Description *ed;
+
+   check_arg_count(1);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+
+   if (ep->type != EDJE_PART_TYPE_TEXTBLOCK)
+     {
+       ERR("%s: Error. parse error %s:%i. "
+           "text attributes in non-TEXTBLOCK part.",
+           progname, file_in, line - 1);
+       exit(-1);
+     }
+
+   ed = ep->default_desc;
+   if (ep->other_desc) ed = eina_list_data_get(eina_list_last(ep->other_desc));
+   ed->text.style = parse_str(0);
+}
+
+/**
+    @page edcref
+
+    @property
+        repch
+    @parameters
+        [the replacement character string]
+    @effect
+        If this is a textblock and is in PASSWORD mode this string is used
+        to replace every character to hide the details of the entry. Normally
+        you would use a "*", but you can use anything you like.
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_description_text_repch(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Part_Description *ed;
+
+   check_arg_count(1);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+
+   if (ep->type != EDJE_PART_TYPE_TEXTBLOCK)
+     {
+       ERR("%s: Error. parse error %s:%i. "
+           "text attributes in non-TEXTBLOCK part.",
+           progname, file_in, line - 1);
+       exit(-1);
+     }
+
+   ed = ep->default_desc;
+   if (ep->other_desc) ed = eina_list_data_get(eina_list_last(ep->other_desc));
+   ed->text.repch = parse_str(0);
+}
+
+/**
+    @page edcref
+
+    @property
+        size
+    @parameters
+        [font size in points (pt)]
+    @effect
+        Sets the default font size for the text part. Can be overrided by the
+        application.
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_description_text_size(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Part_Description *ed;
+
+   check_arg_count(1);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+
+   if (ep->type != EDJE_PART_TYPE_TEXT)
+     {
+       ERR("%s: Error. parse error %s:%i. "
+           "text attributes in non-TEXT part.",
+           progname, file_in, line - 1);
+       exit(-1);
+     }
+
+   ed = ep->default_desc;
+   if (ep->other_desc) ed = eina_list_data_get(eina_list_last(ep->other_desc));
+   ed->text.size = parse_int_range(0, 0, 255);
+}
+
+/**
+    @page edcref
+
+    @property
+        fit
+    @parameters
+        [horizontal] [vertical]
+    @effect
+        When any of the parameters is set to 1 edje will resize the text for it
+        to fit in it's container. Both are disabled by default.
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_description_text_fit(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Part_Description *ed;
+
+   check_arg_count(2);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+
+   if (ep->type != EDJE_PART_TYPE_TEXT)
+     {
+       ERR("%s: Error. parse error %s:%i. "
+           "text attributes in non-TEXT part.",
+           progname, file_in, line - 1);
+       exit(-1);
+     }
+
+   ed = ep->default_desc;
+   if (ep->other_desc) ed = eina_list_data_get(eina_list_last(ep->other_desc));
+   ed->text.fit_x = parse_bool(0);
+   ed->text.fit_y = parse_bool(1);
+}
+
+/**
+    @page edcref
+
+    @property
+        min
+    @parameters
+        [horizontal] [vertical]
+    @effect
+        When any of the parameters is enabled (1) it forces the minimum size of
+        the container to be equal to the minimum size of the text. The default
+        value is "0 0".
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_description_text_min(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Part_Description *ed;
+
+   check_arg_count(2);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+
+   if ((ep->type != EDJE_PART_TYPE_TEXT) &&
+       (ep->type != EDJE_PART_TYPE_TEXTBLOCK))
+     {
+       ERR("%s: Error. parse error %s:%i. "
+           "text attributes in non-TEXT part.",
+           progname, file_in, line - 1);
+       exit(-1);
+     }
+
+   ed = ep->default_desc;
+   if (ep->other_desc) ed = eina_list_data_get(eina_list_last(ep->other_desc));
+   ed->text.min_x = parse_bool(0);
+   ed->text.min_y = parse_bool(1);
+}
+
+/**
+    @page edcref
+
+    @property
+        max
+    @parameters
+        [horizontal] [vertical]
+    @effect
+        When any of the parameters is enabled (1) it forces the maximum size of
+        the container to be equal to the maximum size of the text. The default
+        value is "0 0".
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_description_text_max(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Part_Description *ed;
+
+   check_arg_count(2);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+
+   if ((ep->type != EDJE_PART_TYPE_TEXT) &&
+       (ep->type != EDJE_PART_TYPE_TEXTBLOCK))
+     {
+       ERR("%s: Error. parse error %s:%i. "
+           "text attributes in non-TEXT part.",
+           progname, file_in, line - 1);
+       exit(-1);
+     }
+
+   ed = ep->default_desc;
+   if (ep->other_desc) ed = eina_list_data_get(eina_list_last(ep->other_desc));
+   ed->text.max_x = parse_bool(0);
+   ed->text.max_y = parse_bool(1);
+}
+
+/**
+    @page edcref
+
+    @property
+        align
+    @parameters
+        [horizontal] [vertical]
+    @effect
+        Change the position of the point of balance inside the container. The
+        default value is 0.5 0.5.
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_description_text_align(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Part_Description *ed;
+
+   check_arg_count(2);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+
+   if (ep->type != EDJE_PART_TYPE_TEXT)
+     {
+       ERR("%s: Error. parse error %s:%i. "
+           "text attributes in non-TEXT part.",
+           progname, file_in, line - 1);
+       exit(-1);
+     }
+
+   ed = ep->default_desc;
+   if (ep->other_desc) ed = eina_list_data_get(eina_list_last(ep->other_desc));
+   ed->text.align.x = FROM_DOUBLE(parse_float_range(0, 0.0, 1.0));
+   ed->text.align.y = FROM_DOUBLE(parse_float_range(1, 0.0, 1.0));
+}
+
+/**
+    @page edcref
+
+    @property
+        source
+    @parameters
+        [another TEXT part's name]
+    @effect
+        Causes the part to use the text properties (like font and size) of
+        another part and update them as they change.
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_description_text_source(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Part_Description *ed;
+
+   check_arg_count(1);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+
+   if ((ep->type != EDJE_PART_TYPE_TEXT) &&
+       (ep->type != EDJE_PART_TYPE_TEXTBLOCK))
+     {
+       ERR("%s: Error. parse error %s:%i. "
+           "text attributes in non-TEXT part.",
+           progname, file_in, line - 1);
+       exit(-1);
+     }
+
+   ed = ep->default_desc;
+   if (ep->other_desc) ed = eina_list_data_get(eina_list_last(ep->other_desc));
+     {
+       char *name;
+
+       name = parse_str(0);
+       data_queue_part_lookup(pc, name, &(ed->text.id_source));
+       free(name);
+     }
+}
+
+/**
+    @page edcref
+
+    @property
+        text_source
+    @parameters
+        [another TEXT part's name]
+    @effect
+        Causes the part to display the text content of another part and update
+        them as they change.
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_description_text_text_source(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Part_Description *ed;
+
+   check_arg_count(1);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+
+   if ((ep->type != EDJE_PART_TYPE_TEXT) &&
+       (ep->type != EDJE_PART_TYPE_TEXTBLOCK))
+     {
+       ERR("%s: Error. parse error %s:%i. "
+           "text attributes in non-TEXT part.",
+           progname, file_in, line - 1);
+       exit(-1);
+     }
+
+   ed = ep->default_desc;
+   if (ep->other_desc) ed = eina_list_data_get(eina_list_last(ep->other_desc));
+     {
+       char *name;
+
+       name = parse_str(0);
+       data_queue_part_lookup(pc, name, &(ed->text.id_text_source));
+       free(name);
+     }
+}
+
+/**
+    @page edcref
+
+    @property
+        elipsis
+    @parameters
+        [point of balance]
+    @effect
+        Used to balance the text in a relative point from 0.0 to 1.0, this
+        point is the last section of the string to be cut out in case of a
+        resize that is smaller than the text itself. The default value is 0.0.
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_description_text_elipsis(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Part_Description *ed;
+
+   check_arg_count(1);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+
+   if (ep->type != EDJE_PART_TYPE_TEXT)
+     {
+       ERR("%s: Error. parse error %s:%i. "
+           "text attributes in non-TEXT part.",
+           progname, file_in, line - 1);
+       exit(-1);
+     }
+
+   ed = ep->default_desc;
+   if (ep->other_desc) ed = eina_list_data_get(eina_list_last(ep->other_desc));
+   ed->text.elipsis = parse_float_range(0, 0.0, 1.0);
+}
+
+
+/**
+   @edcsection{description_gradient,Gradient state description sub blocks}
+ */
+
+/**
+    @page edcref
+
+    @block
+        gradient
+    @context
+        part {
+            description {
+                ..
+                gradient {
+                    type:    "linear";
+                    spectrum "spectrumName";
+                    rel1 {
+                        relative: 0.0 0.0;
+                        offset:     0   0;
+                    }
+                    rel2
+                        relative: 1.0 1.0;
+                        offset:    -1  -1;
+                    }
+                }
+                ..
+            }
+        }
+    @description
+        A gradient block is used to display a given "spectrum" inside a 
+        container. The container's shape is a rect but this not mean the
+        gradient is restricted to a rectangular shape.  Gradients can use 
+        "rel1" and "rel2" blocks to layout the initial and final point 
+        relatively inside the container.
+    @endblock
+
+    @property
+        type
+    @parameters
+        [the name of the type]
+    @effect
+        Alters the gradient's rendering algorithm between:
+            @li linear (default)  
+            @li radial
+            @li rectangular
+            @li angular
+            @li sinusoidal
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_description_gradient_type(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Part_Description *ed;
+
+   check_arg_count(1);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+
+   if (ep->type != EDJE_PART_TYPE_GRADIENT)
+     {
+       ERR("%s: Error. parse error %s:%i. "
+           "gradient attributes in non-GRADIENT part.",
+           progname, file_in, line - 1);
+       exit(-1);
+     }
+
+   ed = ep->default_desc;
+   if (ep->other_desc) ed = eina_list_data_get(eina_list_last(ep->other_desc));
+   ed->gradient.type  = parse_str(0);
+}
+
+/**
+    @page edcref
+
+    @property
+        spectrum
+    @parameters
+        [an existing spectrum name]
+    @effect
+        Causes the gradient to display the colors as defined by a given 
+        "spectrum" in the "spectra" block.
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_description_gradient_spectrum(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Part_Description *ed;
+
+   check_arg_count(1);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+
+   if (ep->type != EDJE_PART_TYPE_GRADIENT)
+     {
+        ERR("%s: Error. parse error %s:%i. "
+           "gradient attributes in non-GRADIENT part.",
+           progname, file_in, line - 1);
+       exit(-1);
+     }
+
+   ed = ep->default_desc;
+   if (ep->other_desc) ed = eina_list_data_get(eina_list_last(ep->other_desc));
+
+     {
+       char *name;
+
+       name = parse_str(0);
+       data_queue_spectrum_lookup(name, &(ed->gradient.id));
+       free(name);
+     }
+}
+
+/**
+    @page edcref
+
+    @property
+        relative
+    @parameters
+        [a relative X coordinate] [a relative Y coordinate]
+    @effect
+        Inside rel1 places the initial point, or first color, of the gradient 
+        relatively to the gradient's container. Inside rel2 places the final 
+        point, or last color.
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_description_gradient_rel1_relative(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Part_Description *ed;
+
+   check_arg_count(2);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+
+   if (ep->type != EDJE_PART_TYPE_GRADIENT)
+     {
+       ERR("%s: Error. parse error %s:%i. "
+           "gradient attributes in non-GRADIENT part.",
+           progname, file_in, line - 1);
+       exit(-1);
+     }
+
+   ed = ep->default_desc;
+   if (ep->other_desc) ed = eina_list_data_get(eina_list_last(ep->other_desc));
+
+     {
+       ed->gradient.use_rel = 1;
+       ed->gradient.rel1.relative_x = parse_float(0);
+       ed->gradient.rel1.relative_y = parse_float(1);
+     }
+}
+
+/**
+    @page edcref
+
+    @property
+        offset
+    @parameters
+        [X axis] [Y axis]
+    @effect
+        Inside rel1 moves the initial point, or first color, of the gradient
+        a fixed number of pixels along either axis. Inside rel2 moves the final
+        point, or last color.
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_description_gradient_rel1_offset(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Part_Description *ed;
+
+   check_arg_count(2);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+
+   if (ep->type != EDJE_PART_TYPE_GRADIENT)
+     {
+       ERR("%s: Error. parse error %s:%i. "
+           "gradient attributes in non-GRADIENT part.",
+           progname, file_in, line - 1);
+       exit(-1);
+     }
+
+   ed = ep->default_desc;
+   if (ep->other_desc) ed = eina_list_data_get(eina_list_last(ep->other_desc));
+
+     {
+       ed->gradient.use_rel = 1;
+       ed->gradient.rel1.offset_x = parse_int(0);
+       ed->gradient.rel1.offset_y = parse_int(1);
+     }
+}
+
+static void
+st_collections_group_parts_part_description_gradient_rel2_relative(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Part_Description *ed;
+
+   check_arg_count(2);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+
+   if (ep->type != EDJE_PART_TYPE_GRADIENT)
+     {
+       ERR("%s: Error. parse error %s:%i. "
+           "gradient attributes in non-GRADIENT part.",
+           progname, file_in, line - 1);
+       exit(-1);
+     }
+   
+   ed = ep->default_desc;
+   if (ep->other_desc) ed = eina_list_data_get(eina_list_last(ep->other_desc));
+
+     {
+       ed->gradient.use_rel = 1;
+       ed->gradient.rel2.relative_x = parse_float(0);
+       ed->gradient.rel2.relative_y = parse_float(1);
+     }
+}
+
+static void
+st_collections_group_parts_part_description_gradient_rel2_offset(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Part_Description *ed;
+
+   check_arg_count(2);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+
+   if (ep->type != EDJE_PART_TYPE_GRADIENT)
+     {
+       ERR("%s: Error. parse error %s:%i. "
+           "gradient attributes in non-GRADIENT part.",
+           progname, file_in, line - 1);
+       exit(-1);
+     }
+
+   ed = ep->default_desc;
+   if (ep->other_desc) ed = eina_list_data_get(eina_list_last(ep->other_desc));
+
+     {
+       ed->gradient.use_rel = 1;
+       ed->gradient.rel2.offset_x = parse_int(0);
+       ed->gradient.rel2.offset_y = parse_int(1);
+     }
+}
+
+
+/**
+   @edcsection{description_box,Box state description sub blocks}
+ */
+
+/**
+    @page edcref
+
+    @block
+        box
+    @context
+        part {
+            description {
+                ..
+                box {
+                    layout: "vertical";
+                    padding: 0 2;
+                    align: 0.5 0.5;
+                   min: 0 0;
+                }
+                ..
+            }
+        }
+    @description
+        A box block can contain other objects and display them in different
+       layouts, any of the predefined set, or a custom one, set by the
+       application.
+    @endblock
+
+    @property
+        layout
+    @parameters
+        [primary layout] [fallback layout]
+    @effect
+        Sets the layout for the box:
+            @li horizontal (default)
+            @li vertical
+            @li horizontal_homogeneous
+            @li vertical_homogeneous
+            @li horizontal_max (homogeneous to the max sized child)
+            @li vertical_max
+            @li horizontal_flow
+            @li vertical_flow
+            @li stack
+            @li some_other_custom_layout_set_by_the_application
+        You could set a custom layout as fallback, it makes very
+        very little sense though, and if that one fails, it will
+        default to horizontal.
+    @endproperty
+
+    @property
+        align
+    @parameters
+        [horizontal] [vertical]
+    @effect
+        Change the position of the point of balance inside the container. The
+        default value is 0.5 0.5.
+    @endproperty
+
+    @property
+        padding
+    @parameters
+        [horizontal] [vertical]
+    @effect
+        Sets the space between cells in pixels. Defaults to 0 0.
+    @endproperty
+
+    @property
+        min
+    @parameters
+        [horizontal] [vertical]
+    @effect
+        When any of the parameters is enabled (1) it forces the minimum size of
+        the box to be equal to the minimum size of the items. The default
+        value is "0 0".
+    @endproperty
+*/
+static void st_collections_group_parts_part_description_box_layout(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Part_Description *ed;
+
+   check_min_arg_count(1);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+
+   if (ep->type != EDJE_PART_TYPE_BOX)
+     {
+       ERR("%s: Error. parse error %s:%i. "
+           "box attributes in non-BOX part.",
+           progname, file_in, line - 1);
+       exit(-1);
+     }
+
+   ed = ep->default_desc;
+   if (ep->other_desc) ed = eina_list_data_get(eina_list_last(ep->other_desc));
+   ed->box.layout = parse_str(0);
+   if (is_param(1))
+     ed->box.alt_layout = parse_str(1);
+}
+
+static void st_collections_group_parts_part_description_box_align(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Part_Description *ed;
+
+   check_arg_count(2);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+
+   if (ep->type != EDJE_PART_TYPE_BOX)
+     {
+       ERR("%s: Error. parse error %s:%i. "
+           "box attributes in non-BOX part.",
+           progname, file_in, line - 1);
+       exit(-1);
+     }
+
+   ed = ep->default_desc;
+   if (ep->other_desc) ed = eina_list_data_get(eina_list_last(ep->other_desc));
+   ed->box.align.x = FROM_DOUBLE(parse_float_range(0, -1.0, 1.0));
+   ed->box.align.y = FROM_DOUBLE(parse_float_range(1, -1.0, 1.0));
+}
+
+static void st_collections_group_parts_part_description_box_padding(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Part_Description *ed;
+
+   check_arg_count(2);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+
+   if (ep->type != EDJE_PART_TYPE_BOX)
+     {
+       ERR("%s: Error. parse error %s:%i. "
+           "box attributes in non-BOX part.",
+           progname, file_in, line - 1);
+       exit(-1);
+     }
+
+   ed = ep->default_desc;
+   if (ep->other_desc) ed = eina_list_data_get(eina_list_last(ep->other_desc));
+   ed->box.padding.x = parse_int_range(0, 0, 0x7fffffff);
+   ed->box.padding.y = parse_int_range(1, 0, 0x7fffffff);
+}
+
+static void
+st_collections_group_parts_part_description_box_min(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Part_Description *ed;
+
+   check_arg_count(2);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+
+   if (ep->type != EDJE_PART_TYPE_BOX)
+     {
+       ERR("%s: Error. parse error %s:%i. "
+           "box attributes in non-BOX part.",
+           progname, file_in, line - 1);
+       exit(-1);
+     }
+
+   ed = ep->default_desc;
+   if (ep->other_desc) ed = eina_list_data_get(eina_list_last(ep->other_desc));
+   ed->box.min.h = parse_bool(0);
+   ed->box.min.v = parse_bool(1);
+}
+
+
+/**
+   @edcsection{description_table,Table state description sub blocks}
+ */
+
+/**
+    @page edcref
+
+    @block
+        table
+    @context
+        part {
+            description {
+                ..
+                table {
+                    homogeneous: TABLE;
+                    padding: 0 2;
+                    align: 0.5 0.5;
+                }
+                ..
+            }
+        }
+    @description
+        A table block can contain other objects packed in multiple columns
+        and rows, and each item can span across more than one column and/or
+        row.
+    @endblock
+
+    @property
+        homogeneous
+    @parameters
+        [homogeneous mode]
+    @effect
+        Sets the homogeneous mode for the table:
+            @li NONE (default)
+            @li TABLE
+            @li ITEM
+    @endproperty
+
+    @property
+        align
+    @parameters
+        [horizontal] [vertical]
+    @effect
+        Change the position of the point of balance inside the container. The
+        default value is 0.5 0.5.
+    @endproperty
+
+    @property
+        padding
+    @parameters
+        [horizontal] [vertical]
+    @effect
+        Sets the space between cells in pixels. Defaults to 0 0.
+    @endproperty
+*/
+static void st_collections_group_parts_part_description_table_homogeneous(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Part_Description *ed;
+
+   check_min_arg_count(1);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+
+   if (ep->type != EDJE_PART_TYPE_TABLE)
+     {
+       ERR("%s: Error. parse error %s:%i. "
+           "table attributes in non-TABLE part.",
+           progname, file_in, line - 1);
+       exit(-1);
+     }
+
+   ed = ep->default_desc;
+   if (ep->other_desc) ed = eina_list_data_get(eina_list_last(ep->other_desc));
+   ed->table.homogeneous = parse_enum(0,
+                                    "NONE", EDJE_OBJECT_TABLE_HOMOGENEOUS_NONE,
+                                    "TABLE", EDJE_OBJECT_TABLE_HOMOGENEOUS_TABLE,
+                                    "ITEM", EDJE_OBJECT_TABLE_HOMOGENEOUS_ITEM,
+                                    NULL);
+}
+
+static void st_collections_group_parts_part_description_table_align(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Part_Description *ed;
+
+   check_arg_count(2);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+
+   if (ep->type != EDJE_PART_TYPE_TABLE)
+     {
+       ERR("%s: Error. parse error %s:%i. "
+           "table attributes in non-TABLE part.",
+           progname, file_in, line - 1);
+       exit(-1);
+     }
+
+   ed = ep->default_desc;
+   if (ep->other_desc) ed = eina_list_data_get(eina_list_last(ep->other_desc));
+   ed->table.align.x = FROM_DOUBLE(parse_float_range(0, -1.0, 1.0));
+   ed->table.align.y = FROM_DOUBLE(parse_float_range(1, -1.0, 1.0));
+}
+
+static void st_collections_group_parts_part_description_table_padding(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Part_Description *ed;
+
+   check_arg_count(2);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+
+   if (ep->type != EDJE_PART_TYPE_TABLE)
+     {
+       ERR("%s: Error. parse error %s:%i. "
+           "table attributes in non-TABLE part.",
+           progname, file_in, line - 1);
+       exit(-1);
+     }
+
+   ed = ep->default_desc;
+   if (ep->other_desc) ed = eina_list_data_get(eina_list_last(ep->other_desc));
+   ed->table.padding.x = parse_int_range(0, 0, 0x7fffffff);
+   ed->table.padding.y = parse_int_range(1, 0, 0x7fffffff);
+}
+
+
+/**
+   @edcsection{description_map,Map state description sub blocks}
+ */
+
+/**
+    @page edcref
+    @block
+        map
+    @context
+    description {
+        ..
+        map {
+            perspective: "name";
+            light: "name";
+            on: 1;
+            smooth: 1;
+            perspective_on: 1;
+            backface_cull: 1;
+            alpha: 1;
+            
+            rotation {
+                ..
+            }
+        }
+        ..
+    }
+    
+    @description
+    @endblock
+    
+    @property
+        perspective
+    @parameters
+        [another part's name]
+    @effect
+        This sets the part that is used as the "perspective point" for giving
+        a part a "3d look". The perspective point should have a perspective
+        section that provides zplane and focal properties. The center of this
+        part will be used as the focal point, so size, color and visibility
+        etc. are not relevant just center point, zplane and focal are used.
+        This also implicitly enables perspective transforms (see the on
+        parameter for the map section).
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_description_map_perspective(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Part_Description *ed;
+
+   check_arg_count(1);
+   
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+   
+   ed = ep->default_desc;
+   if (ep->other_desc) ed = eina_list_data_get(eina_list_last(ep->other_desc));
+     {
+       char *name;
+
+       name = parse_str(0);
+       data_queue_part_lookup(pc, name, &(ed->map.id_persp));
+       free(name);
+     }
+   ed->map.persp_on = 1;
+}
+
+/**
+    @page edcref
+    @property
+        light
+    @parameters
+        [another part's name]
+    @effect
+        This sets the part that is used as the "light" for calculating the
+        brightness (based on how directly the part's surface is facing the
+        light source point). Like the perspective point part, the center point
+        is used and zplane is used for the z position (0 being the zero-plane
+        where all 2D objects normally live) and positive values being further
+        away into the distance. The light part color is used as the light
+        color (alpha not used for light color). The color2 color is used for
+        the ambient lighting when calculating brightness (alpha also not
+        used).
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_description_map_light(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Part_Description *ed;
+
+   check_arg_count(1);
+   
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+   
+   ed = ep->default_desc;
+   if (ep->other_desc) ed = eina_list_data_get(eina_list_last(ep->other_desc));
+     {
+       char *name;
+
+       name = parse_str(0);
+       data_queue_part_lookup(pc, name, &(ed->map.id_light));
+       free(name);
+     }
+}
+
+/**
+    @page edcref
+    @property
+        on
+    @parameters
+        [1 or 0]
+    @effect
+        This enables mapping for the part. Default is 0.
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_description_map_on(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Part_Description *ed;
+
+   check_arg_count(1);
+   
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+   
+   ed = ep->default_desc;
+   if (ep->other_desc) ed = eina_list_data_get(eina_list_last(ep->other_desc));
+   ed->map.on = parse_bool(0);
+}
+
+/**
+    @page edcref
+    @property
+        smooth
+    @parameters
+        [1 or 0]
+    @effect
+        This enable smooth map rendering. This may be linear interpolation,
+        anisotropic filtering or anything the engine decides is "smooth".
+        This is a best-effort hint and may not produce precisely the same
+        results in all engines and situations. Default is 1
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_description_map_smooth(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Part_Description *ed;
+
+   check_arg_count(1);
+   
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+   
+   ed = ep->default_desc;
+   if (ep->other_desc) ed = eina_list_data_get(eina_list_last(ep->other_desc));
+   ed->map.smooth = parse_bool(0);
+}
+
+/**
+    @page edcref
+    @property
+        alpha
+    @parameters
+        [1 or 0]
+    @effect
+        This enable alpha channel when map rendering. Default is 1.
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_description_map_alpha(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Part_Description *ed;
+
+   check_arg_count(1);
+   
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+   
+   ed = ep->default_desc;
+   if (ep->other_desc) ed = eina_list_data_get(eina_list_last(ep->other_desc));
+   ed->map.alpha = parse_bool(0);
+}
+
+/**
+    @page edcref
+    @property
+        backface_cull
+    @parameters
+        [1 or 0]
+    @effect
+        This enables backface culling (when the rotated part that normally
+        faces the camera is facing away after being rotated etc.). This means
+        that the object will be hidden when "backface culled".
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_description_map_backface_cull(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Part_Description *ed;
+
+   check_arg_count(1);
+   
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+   
+   ed = ep->default_desc;
+   if (ep->other_desc) ed = eina_list_data_get(eina_list_last(ep->other_desc));
+   ed->map.backcull = parse_bool(0);
+}
+
+/**
+    @page edcref
+    @property
+        perspective_on
+    @parameters
+       [1 or 0]
+    @effect
+        Enable perspective when rotating even without a perspective point object.
+        This would use perspective set for the object itself or for the
+        canvas as a whole as the global perspective with 
+        edje_perspective_set() and edje_perspective_global_set().
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_description_map_perspective_on(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Part_Description *ed;
+
+   check_arg_count(1);
+   
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+   
+   ed = ep->default_desc;
+   if (ep->other_desc) ed = eina_list_data_get(eina_list_last(ep->other_desc));
+   ed->map.persp_on = parse_bool(0);
+}
+/**
+    @page edcref
+    @block
+        rotation
+    @context
+    map {
+        ..
+        rotation {
+            center: "name";
+            x: 45.0;
+            y: 45.0;
+            z: 45.0;
+        }
+        ..
+    }
+    @description
+        Rotates the part, optionally with the center on another part.
+    @endblock
+    
+    @property
+        center
+    @parameters
+        [another part's name]
+    @effect
+        This sets the part that is used as the center of rotation when
+        rotating the part with this description. The part's center point
+        is used as the rotation center when applying rotation around the
+        x, y and z axes. If no center is given, the parts original center
+        itself is used for the rotation center.
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_description_map_rotation_center(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Part_Description *ed;
+
+   check_arg_count(1);
+   
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+   
+   ed = ep->default_desc;
+   if (ep->other_desc) ed = eina_list_data_get(eina_list_last(ep->other_desc));
+     {
+       char *name;
+
+       name = parse_str(0);
+       data_queue_part_lookup(pc, name, &(ed->map.rot.id_center));
+       free(name);
+     }
+}
+
+/**
+    @page edcref
+    @property
+        x
+    @parameters
+        [X degrees]
+    @effect
+        This sets the rotation around the x axis of the part considering
+        the center set. In degrees.
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_description_map_rotation_x(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Part_Description *ed;
+
+   check_arg_count(1);
+   
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+   
+   ed = ep->default_desc;
+   if (ep->other_desc) ed = eina_list_data_get(eina_list_last(ep->other_desc));
+   ed->map.rot.x = FROM_DOUBLE(parse_float(0));
+}
+
+/**
+    @page edcref
+    @property
+        y
+    @parameters
+        [Y degrees]
+    @effect
+        This sets the rotation around the u axis of the part considering
+        the center set. In degrees.
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_description_map_rotation_y(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Part_Description *ed;
+
+   check_arg_count(1);
+   
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+   
+   ed = ep->default_desc;
+   if (ep->other_desc) ed = eina_list_data_get(eina_list_last(ep->other_desc));
+   ed->map.rot.y = FROM_DOUBLE(parse_float(0));
+}
+
+/**
+    @page edcref
+    @property
+        z
+    @parameters
+        [Z degrees]
+    @effect
+        This sets the rotation around the z axis of the part considering
+        the center set. In degrees.
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_description_map_rotation_z(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Part_Description *ed;
+
+   check_arg_count(1);
+   
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+   
+   ed = ep->default_desc;
+   if (ep->other_desc) ed = eina_list_data_get(eina_list_last(ep->other_desc));
+   ed->map.rot.z = FROM_DOUBLE(parse_float(0));
+}
+
+/**
+    @page edcref
+    @block
+        perspective
+    @context
+    description {
+        ..
+        perspective {
+            zplane: 0;
+            focal: 1000;
+        }
+        ..
+    }
+    @description
+        Adds focal and plane perspective to the part. Active if perspective_on is true.
+        Must be provided if the part is being used by other part as it's perspective target.
+    @endblock
+    
+    @property
+        zplane
+    @parameters
+        [unscaled Z value]
+    @effect
+        This sets the z value that will not be scaled. Normally this is 0 as
+        that is the z distance that all objects are at normally.
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_description_perspective_zplane(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Part_Description *ed;
+
+   check_arg_count(1);
+   
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+   
+   ed = ep->default_desc;
+   if (ep->other_desc) ed = eina_list_data_get(eina_list_last(ep->other_desc));
+   ed->persp.zplane = parse_int(0);
+}
+
+
+/**
+    @page edcref
+    @property
+        focal
+    @parameters
+        [distance]
+    @effect
+        This sets the distance from the focal z plane (zplane) and the
+        camera - i.e. very much equating to focal length of the camera
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_description_perspective_focal(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Part_Description *ed;
+
+   check_arg_count(1);
+   
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+   
+   ed = ep->default_desc;
+   if (ep->other_desc) ed = eina_list_data_get(eina_list_last(ep->other_desc));
+   ed->persp.focal = parse_int_range(0, 1, 0x7fffffff);
+}
+
+
+/**
+   @edcsection{description_params,Params state description sub blocks}
+ */
+
+/**
+    @page edcref
+    @block
+        params
+    @context
+    description {
+        ..
+        params {
+            int: "name" 0;
+            double: "other_name" 0.0;
+            string: "another_name" "some text";
+           bool: "name" 1;
+           choice: "some_name" "value";
+        }
+        ..
+    }
+    @description
+        Set parameters for EXTERNAL parts. The value overwrites previous
+        definitions with the same name.
+    @endblock
+*/
+static void
+_st_collections_group_parts_part_description_params(Edje_External_Param_Type type)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Part_Description *ed;
+   Edje_External_Param *param;
+   Eina_List *l;
+   const char *name;
+   int found = 0;
+
+   check_arg_count(2);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+
+   if (ep->type != EDJE_PART_TYPE_EXTERNAL)
+     {
+       ERR("%s: Error. parse error %s:%i. "
+           "params in non-EXTERNAL part.",
+           progname, file_in, line - 1);
+       exit(-1);
+     }
+
+   ed = ep->default_desc;
+   if (ep->other_desc) ed = eina_list_data_get(eina_list_last(ep->other_desc));
+
+   name = parse_str(0);
+
+   /* if a param with this name already exists, overwrite it */
+   EINA_LIST_FOREACH(ed->external_params, l, param)
+     {
+       if (!strcmp(param->name, name))
+         {
+            found = 1;
+            break;
+         }
+     }
+
+   if (!found)
+     {
+       param = mem_alloc(SZ(Edje_External_Param));
+       param->name = name;
+     }
+
+   param->type = type;
+   param->i = 0;
+   param->d = 0;
+   param->s = NULL;
+
+   switch (type)
+     {
+      case EDJE_EXTERNAL_PARAM_TYPE_BOOL:
+      case EDJE_EXTERNAL_PARAM_TYPE_INT:
+        param->i = parse_int(1);
+        break;
+      case EDJE_EXTERNAL_PARAM_TYPE_DOUBLE:
+        param->d = parse_float(1);
+        break;
+      case EDJE_EXTERNAL_PARAM_TYPE_CHOICE:
+      case EDJE_EXTERNAL_PARAM_TYPE_STRING:
+        param->s = parse_str(1);
+        break;
+      default:
+        ERR("%s: Error. parse error %s:%i. Invalid param type.\n",
+            progname, file_in, line - 1);
+        break;
+     }
+
+   if (!found)
+     ed->external_params = eina_list_append(ed->external_params, param);
+}
+
+/**
+    @page edcref
+    @property
+        int
+    @parameters
+        [param_name] [int_value]
+    @effect
+        Adds an integer parameter for an external object
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_description_params_int(void)
+{
+   _st_collections_group_parts_part_description_params(EDJE_EXTERNAL_PARAM_TYPE_INT);
+}
+
+/**
+    @page edcref
+    @property
+        double
+    @parameters
+        [param_name] [double_value]
+    @effect
+        Adds a double parameter for an external object
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_description_params_double(void)
+{
+   _st_collections_group_parts_part_description_params(EDJE_EXTERNAL_PARAM_TYPE_DOUBLE);
+}
+
+/**
+    @page edcref
+    @property
+        string
+    @parameters
+        [param_name] [string_value]
+    @effect
+        Adds a string parameter for an external object
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_description_params_string(void)
+{
+   _st_collections_group_parts_part_description_params(EDJE_EXTERNAL_PARAM_TYPE_STRING);
+}
+
+/**
+    @page edcref
+    @property
+        bool
+    @parameters
+        [param_name] [bool_value]
+    @effect
+        Adds an boolean parameter for an external object. Value must be 0 or 1.
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_description_params_bool(void)
+{
+   _st_collections_group_parts_part_description_params(EDJE_EXTERNAL_PARAM_TYPE_BOOL);
+}
+
+/**
+    @page edcref
+    @property
+        choice
+    @parameters
+        [param_name] [choice_string]
+    @effect
+        Adds a choice parameter for an external object. The possible
+        choice values are defined by external type at their register time
+        and will be validated at runtime.
+    @endproperty
+*/
+static void
+st_collections_group_parts_part_description_params_choice(void)
+{
+   _st_collections_group_parts_part_description_params(EDJE_EXTERNAL_PARAM_TYPE_CHOICE);
+}
+
+
+/**
+   @edcsection{program, Program block}
+ */
+
+/**
+    @page edcref
+    @block
+        program
+    @context
+        group {
+            programs {
+               ..
+                  program {
+                     name: "programname";
+                     signal: "signalname";
+                     source: "partname";
+                     filter: "partname" "statename";
+                     in: 0.3 0.0;
+                     action: STATE_SET "statename" state_value;
+                     transition: LINEAR 0.5;
+                     target: "partname";
+                     target: "anotherpart";
+                     after: "programname";
+                     after: "anotherprogram";
+                  }
+               ..
+            }
+        }
+    @description
+        Programs define how your interface reacts to events.
+        Programs can change the state of parts, react to events or trigger
+        other events.
+    @endblock
+*/
+static void
+ob_collections_group_programs_program(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Program *ep;
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = mem_alloc(SZ(Edje_Program));
+   pc->programs = eina_list_append(pc->programs, ep);
+   ep->id = eina_list_count(pc->programs) - 1;
+   ep->tween.mode = EDJE_TWEEN_MODE_LINEAR;
+   ep->after = NULL;
+}
+
+/**
+    @page edcref
+    @property
+        name
+    @parameters
+        [program name]
+    @effect
+        Symbolic name of program as a unique identifier.
+    @endproperty
+*/
+static void
+st_collections_group_programs_program_name(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Program *ep;
+
+   check_arg_count(1);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->programs));
+   ep->name = parse_str(0);
+     {
+       Eina_List *l;
+       Edje_Program *lep;
+
+       EINA_LIST_FOREACH(pc->programs, l, lep)
+         {
+            if ((lep != ep) && (lep->name) && (!strcmp(lep->name, ep->name)))
+              {
+                 ERR("%s: Error. parse error %s:%i. There is already a program of the name %s\n",
+                     progname, file_in, line - 1, ep->name);
+                 exit(-1);
+              }
+         }
+     }
+}
+
+/**
+    @page edcref
+    @property
+        signal
+    @parameters
+        [signal name]
+    @effect
+        Specifies signal(s) that should cause the program to run. The signal
+        received must match the specified source to run.
+        Signals may be globbed, but only one signal keyword per program
+        may be used. ex: signal: "mouse,clicked,*"; (clicking any mouse button
+        that matches source starts program).
+    @endproperty
+*/
+static void
+st_collections_group_programs_program_signal(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Program *ep;
+
+   check_arg_count(1);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->programs));
+   ep->signal = parse_str(0);
+}
+
+/**
+    @page edcref
+    @property
+        source
+    @parameters
+        [source name]
+    @effect
+        Source of accepted signal. Sources may be globbed, but only one source
+        keyword per program may be used. ex:source: "button-*"; (Signals from
+        any part or program named "button-*" are accepted).
+    @endproperty
+*/
+static void
+st_collections_group_programs_program_source(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Program *ep;
+
+   check_arg_count(1);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->programs));
+   ep->source = parse_str(0);
+}
+
+/**
+    @page edcref
+    @property
+        filter
+    @parameters
+        [part] [state]
+    @effect
+        Filter signals to be only accepted if the part [part] is in state named [state].
+        Only one filter per program can be used. If [state] is not given, the source of
+        the event will be used instead.
+    @endproperty
+*/
+static void
+st_collections_group_programs_program_filter(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Program *ep;
+
+   check_min_arg_count(1);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->programs));
+
+   if(is_param(1)) {
+          ep->filter.part = parse_str(0);
+          ep->filter.state = parse_str(1);
+   } else {
+          ep->filter.state = parse_str(0);
+   }
+}
+
+/**
+    @page edcref
+    @property
+        in
+    @parameters
+        [from] [range]
+    @effect
+        Wait 'from' seconds before executing the program. And add a random
+        number of seconds (from 0 to 'range') to the total waiting time.
+    @endproperty
+*/
+static void
+st_collections_group_programs_program_in(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Program *ep;
+
+   check_arg_count(2);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->programs));
+   ep->in.from = parse_float_range(0, 0.0, 999999999.0);
+   ep->in.range = parse_float_range(1, 0.0, 999999999.0);
+}
+
+/**
+    @page edcref
+    @property
+        action
+    @parameters
+        [type] [param1] [param2]
+    @effect
+        Action to be performed by the program. Valid actions are: STATE_SET,
+        ACTION_STOP, SIGNAL_EMIT, DRAG_VAL_SET, DRAG_VAL_STEP, DRAG_VAL_PAGE,
+        FOCUS_SET, PARAM_COPY, PARAM_SET
+        Only one action can be specified per program. Examples:\n
+           action: STATE_SET "statename" 0.5;\n
+           action: ACTION_STOP;\n
+           action: SIGNAL_EMIT "signalname" "emitter";\n
+           action: DRAG_VAL_SET 0.5 0.0;\n
+           action: DRAG_VAL_STEP 1.0 0.0;\n
+           action: DRAG_VAL_PAGE 0.0 0.0;\n
+           action: FOCUS_SET;\n
+           action: FOCUS_OBJECT;\n
+           action: PARAM_COPY "src_part" "src_param" "dst_part" "dst_param";\n
+          action: PARAM_SET "part" "param" "value";\n
+    @endproperty
+*/
+static void
+st_collections_group_programs_program_action(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Program *ep;
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->programs));
+   ep->action = parse_enum(0,
+                          "STATE_SET", EDJE_ACTION_TYPE_STATE_SET,
+                          "ACTION_STOP", EDJE_ACTION_TYPE_ACTION_STOP,
+                          "SIGNAL_EMIT", EDJE_ACTION_TYPE_SIGNAL_EMIT,
+                          "DRAG_VAL_SET", EDJE_ACTION_TYPE_DRAG_VAL_SET,
+                          "DRAG_VAL_STEP", EDJE_ACTION_TYPE_DRAG_VAL_STEP,
+                          "DRAG_VAL_PAGE", EDJE_ACTION_TYPE_DRAG_VAL_PAGE,
+                          "SCRIPT", EDJE_ACTION_TYPE_SCRIPT,
+                          "LUA_SCRIPT", EDJE_ACTION_TYPE_LUA_SCRIPT,
+                          "FOCUS_SET", EDJE_ACTION_TYPE_FOCUS_SET,
+                          "FOCUS_OBJECT", EDJE_ACTION_TYPE_FOCUS_OBJECT,
+                          "PARAM_COPY", EDJE_ACTION_TYPE_PARAM_COPY,
+                          "PARAM_SET", EDJE_ACTION_TYPE_PARAM_SET,
+                          NULL);
+   if (ep->action == EDJE_ACTION_TYPE_STATE_SET)
+     {
+       ep->state = parse_str(1);
+       ep->value = parse_float_range(2, 0.0, 1.0);
+     }
+   else if (ep->action == EDJE_ACTION_TYPE_SIGNAL_EMIT)
+     {
+       ep->state = parse_str(1);
+       ep->state2 = parse_str(2);
+     }
+   else if (ep->action == EDJE_ACTION_TYPE_DRAG_VAL_SET)
+     {
+       ep->value = parse_float(1);
+       ep->value2 = parse_float(2);
+     }
+   else if (ep->action == EDJE_ACTION_TYPE_DRAG_VAL_STEP)
+     {
+       ep->value = parse_float(1);
+       ep->value2 = parse_float(2);
+     }
+   else if (ep->action == EDJE_ACTION_TYPE_DRAG_VAL_PAGE)
+     {
+       ep->value = parse_float(1);
+       ep->value2 = parse_float(2);
+     }
+   else if (ep->action == EDJE_ACTION_TYPE_PARAM_COPY)
+     {
+       char *src_part, *dst_part;
+
+       src_part = parse_str(1);
+       ep->state = parse_str(2);
+       dst_part = parse_str(3);
+       ep->state2 = parse_str(4);
+
+       data_queue_part_lookup(pc, src_part, &(ep->param.src));
+       data_queue_part_lookup(pc, dst_part, &(ep->param.dst));
+
+       free(src_part);
+       free(dst_part);
+     }
+   else if (ep->action == EDJE_ACTION_TYPE_PARAM_SET)
+     {
+       char *part;
+
+       part = parse_str(1);
+       ep->state = parse_str(2);
+       ep->state2 = parse_str(3);
+
+       data_queue_part_lookup(pc, part, &(ep->param.dst));
+       free(part);
+     }
+
+   switch (ep->action)
+     {
+      case EDJE_ACTION_TYPE_ACTION_STOP:
+       check_arg_count(1);
+       break;
+      case EDJE_ACTION_TYPE_SCRIPT:
+       /* this is implicitly set by script {} so this is here just for
+        * completeness */
+       break;
+      case EDJE_ACTION_TYPE_LUA_SCRIPT:
+       /* this is implicitly set by lua_script {} so this is here just for
+        * completeness */
+       break;
+      case EDJE_ACTION_TYPE_FOCUS_OBJECT:
+      case EDJE_ACTION_TYPE_FOCUS_SET:
+       check_arg_count(1);
+       break;
+      case EDJE_ACTION_TYPE_PARAM_COPY:
+        check_arg_count(5);
+        break;
+      case EDJE_ACTION_TYPE_PARAM_SET:
+        check_arg_count(4);
+        break;
+      default:
+       check_arg_count(3);
+     }
+}
+
+/**
+    @page edcref
+    @property
+        transition
+    @parameters
+        [type] [length]
+    @effect
+        Defines how transitions occur using STATE_SET action.\n
+        Where 'type' is the style of the transition and 'length' is a double
+        specifying the number of seconds in which to preform the transition.\n
+        Valid types are: LINEAR, SINUSOIDAL, ACCELERATE, and DECELERATE.
+    @endproperty
+*/
+static void
+st_collections_group_programs_program_transition(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Program *ep;
+
+   check_arg_count(2);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->programs));
+   ep->tween.mode = parse_enum(0,
+                              "LINEAR", EDJE_TWEEN_MODE_LINEAR,
+                              "SINUSOIDAL", EDJE_TWEEN_MODE_SINUSOIDAL,
+                              "ACCELERATE", EDJE_TWEEN_MODE_ACCELERATE,
+                              "DECELERATE", EDJE_TWEEN_MODE_DECELERATE,
+                              NULL);
+   ep->tween.time = FROM_DOUBLE(parse_float_range(1, 0.0, 999999999.0));
+}
+
+/**
+    @page edcref
+    @property
+        target
+    @parameters
+        [target]
+    @effect
+        Program or part on which the specified action acts. Multiple target
+        keywords may be specified, one per target. SIGNAL_EMITs do not have
+        targets.
+    @endproperty
+*/
+static void
+st_collections_group_programs_program_target(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Program *ep;
+
+   check_arg_count(1);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->programs));
+     {
+       Edje_Program_Target *et;
+       char *name;
+
+       et = mem_alloc(SZ(Edje_Program_Target));
+       ep->targets = eina_list_append(ep->targets, et);
+
+       name = parse_str(0);
+       if (ep->action == EDJE_ACTION_TYPE_STATE_SET)
+         data_queue_part_lookup(pc, name, &(et->id));
+       else if (ep->action == EDJE_ACTION_TYPE_ACTION_STOP)
+         data_queue_program_lookup(pc, name, &(et->id));
+       else if (ep->action == EDJE_ACTION_TYPE_DRAG_VAL_SET)
+         data_queue_part_lookup(pc, name, &(et->id));
+       else if (ep->action == EDJE_ACTION_TYPE_DRAG_VAL_STEP)
+         data_queue_part_lookup(pc, name, &(et->id));
+       else if (ep->action == EDJE_ACTION_TYPE_DRAG_VAL_PAGE)
+         data_queue_part_lookup(pc, name, &(et->id));
+       else if (ep->action == EDJE_ACTION_TYPE_FOCUS_SET)
+         data_queue_part_lookup(pc, name, &(et->id));
+       else
+         {
+            ERR("%s: Error. parse error %s:%i. "
+                "target may only be used after action",
+                progname, file_in, line - 1);
+            exit(-1);
+         }
+       free(name);
+     }
+}
+
+/**
+    @page edcref
+    @property
+        after
+    @parameters
+        [after]
+    @effect
+        Specifies a program to run after the current program completes. The
+        source and signal parameters of a program run as an "after" are ignored.
+        Multiple "after" statements can be specified per program.
+    @endproperty
+*/
+static void
+st_collections_group_programs_program_after(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Program *ep;
+
+   check_arg_count(1);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->programs));
+     {
+       Edje_Program_After *pa;
+       char *name;
+
+       name = parse_str(0);
+
+       pa = mem_alloc(SZ(Edje_Program_After));
+       pa->id = -1;
+       ep->after = eina_list_append(ep->after, pa);
+
+       data_queue_program_lookup(pc, name, &(pa->id));
+       free(name);
+     }
+}
+
+/**
+    @page edcref
+    @property
+        api
+    @parameters
+        [name] [description]
+    @effect
+        Specifies a hint to let applications (or IDE's) know how to bind
+       things. The parameter name should contain the name of the function that
+       the application should use, and description describes how it should
+       be used.
+    @endproperty
+*/
+static void
+st_collections_group_programs_program_api(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Program *ep;
+
+   check_min_arg_count(1);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->programs));
+   ep->api.name = parse_str(0);
+
+   if (is_param(1))
+     {
+       check_arg_count(2);
+       ep->api.description = parse_str(1);
+     }
+}
+
+static void
+st_collections_group_parts_part_api(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+
+   check_min_arg_count(1);
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->parts));
+   ep->api.name = parse_str(0);
+   if (is_param(1))
+     {
+       check_arg_count(2);
+       ep->api.description = parse_str(1);
+     }
+}
+
+static void
+ob_collections_group_programs_program_script(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Program *ep;
+   Code *cd;
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->programs));
+   cd = eina_list_data_get(eina_list_last(codes));
+
+   if (!is_verbatim()) track_verbatim(1);
+   else
+     {
+       char *s;
+
+       s = get_verbatim();
+       if (s)
+         {
+            Code_Program *cp;
+
+            cp = mem_alloc(SZ(Code_Program));
+            cp->l1 = get_verbatim_line1();
+            cp->l2 = get_verbatim_line2();
+            cp->id = ep->id;
+            cp->script = s;
+            if (cd->shared && cd->is_lua)
+              {
+                 ERR("%s: Error. parse error %s:%i. You're trying to mix Embryo and Lua scripting in the same group",
+                     progname, file_in, line - 1);
+                 exit(-1);
+              }
+            cd->is_lua = 0;
+            cd->programs = eina_list_append(cd->programs, cp);
+            set_verbatim(NULL, 0, 0);
+            ep->action = EDJE_ACTION_TYPE_SCRIPT;
+         }
+     }
+}
+
+static void
+ob_collections_group_programs_program_lua_script(void)
+{
+   Edje_Part_Collection *pc;
+   Edje_Program *ep;
+   Code *cd;
+
+   pc = eina_list_data_get(eina_list_last(edje_collections));
+   ep = eina_list_data_get(eina_list_last(pc->programs));
+   cd = eina_list_data_get(eina_list_last(codes));
+
+   if (!is_verbatim()) track_verbatim(1);
+   else
+     {
+       char *s;
+
+       s = get_verbatim();
+       if (s)
+         {
+            Code_Program *cp;
+
+            cp = mem_alloc(SZ(Code_Program));
+            cp->l1 = get_verbatim_line1();
+            cp->l2 = get_verbatim_line2();
+            cp->id = ep->id;
+            cp->script = s;
+            if (cd->shared && !cd->is_lua)
+              {
+                 ERR("%s: Error. parse error %s:%i. You're trying to mix Embryo and Lua scripting in the same group",
+                     progname, file_in, line - 1);
+                 exit(-1);
+              }
+            cd->is_lua = 1;
+            cd->programs = eina_list_append(cd->programs, cp);
+            set_verbatim(NULL, 0, 0);
+            ep->action = EDJE_ACTION_TYPE_LUA_SCRIPT;
+         }
+     }
+}
+/**
+    @page edcref
+    </table>
+*/
diff --git a/src/bin/edje_cc_mem.c b/src/bin/edje_cc_mem.c
new file mode 100644 (file)
index 0000000..13e7c52
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <string.h>
+#include <errno.h>
+
+#include "edje_cc.h"
+
+void *
+mem_alloc(size_t size)
+{
+   void *mem;
+
+   mem = calloc(1, size);
+   if (mem) return mem;
+   ERR("%s: Error. %s:%i memory allocation of %zi bytes failed. %s",
+       progname, file_in, line, size, strerror(errno));
+   exit(-1);
+   return NULL;
+}
+
+char *
+mem_strdup(const char *s)
+{
+   void *str;
+
+   str = strdup(s);
+   if (str) return str;
+   ERR("%s: Error. %s:%i memory allocation of %zi bytes failed. %s. string being duplicated: \"%s\"",
+       progname, file_in, line, strlen(s) + 1, strerror(errno), s);
+   exit(-1);
+   return NULL;
+}
diff --git a/src/bin/edje_cc_out.c b/src/bin/edje_cc_out.c
new file mode 100644 (file)
index 0000000..b7b8cbc
--- /dev/null
@@ -0,0 +1,1614 @@
+/*
+ * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#ifdef HAVE_ALLOCA_H
+# include <alloca.h>
+#elif defined __GNUC__
+# define alloca __builtin_alloca
+#elif defined _AIX
+# define alloca __alloca
+#elif defined _MSC_VER
+# include <malloc.h>
+# define alloca _alloca
+#else
+# include <stddef.h>
+# ifdef  __cplusplus
+extern "C"
+# endif
+void *alloca (size_t);
+#endif
+
+#include <string.h>
+#include <limits.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+#include <Ecore_Evas.h>
+
+#include "edje_cc.h"
+#include "edje_prefix.h"
+
+#include <lua.h>
+#include <lauxlib.h>
+
+typedef struct _External_Lookup External_Lookup;
+typedef struct _Part_Lookup Part_Lookup;
+typedef struct _Program_Lookup Program_Lookup;
+typedef struct _Group_Lookup Group_Lookup;
+typedef struct _String_Lookup Image_Lookup;
+typedef struct _String_Lookup Spectrum_Lookup;
+typedef struct _Slave_Lookup Slave_Lookup;
+typedef struct _Code_Lookup Code_Lookup;
+
+
+struct _External_Lookup
+{
+   char *name;
+};
+
+struct _Part_Lookup
+{
+   Edje_Part_Collection *pc;
+   char *name;
+   int *dest;
+};
+
+struct _Program_Lookup
+{
+   Edje_Part_Collection *pc;
+   char *name;
+   int *dest;
+};
+
+struct _Group_Lookup
+{
+   char *name;
+};
+
+struct _String_Lookup
+{
+   char *name;
+   int *dest;
+};
+
+struct _Slave_Lookup
+{
+   int *master;
+   int *slave;
+};
+
+struct _Code_Lookup
+{
+   char *ptr;
+   int   len;
+   int   val;
+};
+
+static void data_process_string(Edje_Part_Collection *pc, const char *prefix, char *s, void (*func)(Edje_Part_Collection *pc, char *name, char *ptr, int len));
+
+Edje_File *edje_file = NULL;
+Eina_List *edje_collections = NULL;
+Eina_List *externals = NULL;
+Eina_List *fonts = NULL;
+Eina_List *codes = NULL;
+Eina_List *code_lookups = NULL;
+Eina_List *aliases = NULL;
+
+static Eet_Data_Descriptor *edd_edje_file = NULL;
+static Eet_Data_Descriptor *edd_edje_image_directory = NULL;
+static Eet_Data_Descriptor *edd_edje_image_directory_entry = NULL;
+static Eet_Data_Descriptor *edd_edje_spectrum_directory = NULL;
+static Eet_Data_Descriptor *edd_edje_spectrum_directory_entry = NULL;
+static Eet_Data_Descriptor *edd_edje_program = NULL;
+static Eet_Data_Descriptor *edd_edje_program_target = NULL;
+static Eet_Data_Descriptor *edd_edje_part_collection_directory = NULL;
+static Eet_Data_Descriptor *edd_edje_part_collection_directory_entry = NULL;
+static Eet_Data_Descriptor *edd_edje_part_collection = NULL;
+static Eet_Data_Descriptor *edd_edje_part = NULL;
+static Eet_Data_Descriptor *edd_edje_part_description = NULL;
+static Eet_Data_Descriptor *edd_edje_part_image_id = NULL;
+static Eet_Data_Descriptor *edd_edje_spectrum_color = NULL;
+
+static Eina_List *part_lookups = NULL;
+static Eina_List *program_lookups = NULL;
+static Eina_List *group_lookups = NULL;
+static Eina_List *image_lookups = NULL;
+static Eina_List *spectrum_lookups = NULL;
+static Eina_List *part_slave_lookups = NULL;
+static Eina_List *image_slave_lookups= NULL;
+static Eina_List *spectrum_slave_lookups= NULL;
+
+#define ABORT_WRITE(eet_file, file) \
+   eet_close(eet_file); \
+   unlink(file); \
+   exit(-1);
+
+static void
+error_and_abort(Eet_File *ef, const char *fmt, ...)
+{
+   va_list ap;
+
+   fprintf(stderr, "%s: Error. ", progname);
+
+   va_start(ap, fmt);
+   vfprintf(stderr, fmt, ap);
+   va_end(ap);
+   ABORT_WRITE(ef, file_out);
+}
+
+void
+data_setup(void)
+{
+   edd_edje_file = _edje_edd_edje_file;
+   edd_edje_image_directory = _edje_edd_edje_image_directory;
+   edd_edje_image_directory_entry = _edje_edd_edje_image_directory_entry;
+   edd_edje_spectrum_directory = _edje_edd_edje_spectrum_directory;
+   edd_edje_spectrum_directory_entry = _edje_edd_edje_spectrum_directory_entry;
+   edd_edje_program = _edje_edd_edje_program;
+   edd_edje_program_target = _edje_edd_edje_program_target;
+   edd_edje_part_collection_directory = _edje_edd_edje_part_collection_directory;
+   edd_edje_part_collection_directory_entry = _edje_edd_edje_part_collection_directory_entry;
+   edd_edje_part_collection = _edje_edd_edje_part_collection;
+   edd_edje_part = _edje_edd_edje_part;
+   edd_edje_part_description = _edje_edd_edje_part_description;
+   edd_edje_part_image_id = _edje_edd_edje_part_image_id;
+   edd_edje_spectrum_color = _edje_edd_edje_spectrum_color;
+}
+
+static void
+check_image_part_desc (Edje_Part_Collection *pc, Edje_Part *ep,
+                       Edje_Part_Description *epd, Eet_File *ef)
+{
+   Eina_List *l;
+   Edje_Part_Image_Id *iid;
+
+   return;
+   if (epd->image.id == -1)
+     error_and_abort(ef, "Collection %i: image attributes missing for "
+                    "part \"%s\", description \"%s\" %f\n",
+                    pc->id, ep->name, epd->state.name, epd->state.value);
+
+   EINA_LIST_FOREACH(epd->image.tween_list, l, iid)
+     {
+       if (iid->id == -1)
+         error_and_abort(ef, "Collection %i: tween image id missing for "
+                         "part \"%s\", description \"%s\" %f\n",
+                         pc->id, ep->name, epd->state.name, epd->state.value);
+    }
+}
+
+static void
+check_packed_items(Edje_Part_Collection *pc, Edje_Part *ep, Eet_File *ef)
+{
+   Eina_List *l;
+   Edje_Pack_Element *it;
+
+   EINA_LIST_FOREACH(ep->items, l, it)
+     {
+       if (it->type == EDJE_PART_TYPE_GROUP && !it->source)
+         error_and_abort(ef, "Collection %i: missing source on packed item "
+                         "of type GROUP in part \"%s\"\n",
+                         pc->id, ep->name);
+       if (ep->type == EDJE_PART_TYPE_TABLE && (it->col < 0 || it->row < 0))
+         error_and_abort(ef, "Collection %i: missing col/row on packed item "
+                         "for part \"%s\" of type TABLE\n",
+                         pc->id, ep->name);
+     }
+}
+
+static void
+check_part (Edje_Part_Collection *pc, Edje_Part *ep, Eet_File *ef)
+{
+   Edje_Part_Description *epd = ep->default_desc;
+   Eina_List *l;
+   Edje_Part_Description *data;
+
+   if (!epd)
+     error_and_abort(ef, "Collection %i: default description missing "
+                    "for part \"%s\"\n", pc->id, ep->name);
+
+   if (ep->type == EDJE_PART_TYPE_IMAGE)
+     {
+       check_image_part_desc (pc, ep, epd, ef);
+
+       EINA_LIST_FOREACH(ep->other_desc, l, data)
+         check_image_part_desc (pc, ep, data, ef);
+     }
+   else if ((ep->type == EDJE_PART_TYPE_BOX) ||
+           (ep->type == EDJE_PART_TYPE_TABLE))
+     check_packed_items(pc, ep, ef);
+}
+
+static void
+check_program (Edje_Part_Collection *pc, Edje_Program *ep, Eet_File *ef)
+{
+   switch (ep->action)
+     {
+      case EDJE_ACTION_TYPE_STATE_SET:
+      case EDJE_ACTION_TYPE_ACTION_STOP:
+      case EDJE_ACTION_TYPE_DRAG_VAL_SET:
+      case EDJE_ACTION_TYPE_DRAG_VAL_STEP:
+      case EDJE_ACTION_TYPE_DRAG_VAL_PAGE:
+        if (!ep->targets)
+          error_and_abort(ef, "Collection %i: target missing in program "
+                          "\"%s\"\n", pc->id, ep->name);
+        break;
+      default:
+        break;
+     }
+}
+
+static void
+check_spectrum (Edje_Spectrum_Directory_Entry *se, Eet_File *ef)
+{
+   if (!se->entry)
+     error_and_abort(ef, "Spectrum missing a name.\n");
+   else if (!se->color_list)
+     error_and_abort(ef, "Spectrum %s is empty. At least one color must be "
+                    "given.", se->entry);
+}
+
+static int
+data_write_header(Eet_File *ef)
+{
+   int bytes = 0;
+
+   if (edje_file)
+     {
+
+       if (edje_file->collection_dir)
+         {
+            /* copy aliases into collection directory */
+            while (aliases)
+              {
+                edje_file->collection_dir->entries = eina_list_append(edje_file->collection_dir->entries, eina_list_data_get(aliases));
+                 aliases = eina_list_remove_list(aliases, aliases);
+              }
+         }
+       bytes = eet_data_write(ef, edd_edje_file, "edje_file", edje_file, 1);
+       if (bytes <= 0)
+         error_and_abort(ef, "Unable to write \"edje_file\" entry to \"%s\" \n",
+                         file_out);
+     }
+
+   if (verbose)
+     {
+       printf("%s: Wrote %9i bytes (%4iKb) for \"edje_file\" header\n",
+              progname, bytes, (bytes + 512) / 1024);
+     }
+
+   return bytes;
+}
+
+static int
+data_write_fonts(Eet_File *ef, int *font_num, int *input_bytes, int *input_raw_bytes)
+{
+   Eina_List *l;;
+   int bytes = 0;
+   int total_bytes = 0;
+   Font *fn;
+
+   EINA_LIST_FOREACH(fonts, l, fn)
+     {
+       void *fdata = NULL;
+       int fsize = 0;
+       Eina_List *ll;
+       FILE *f;
+
+       f = fopen(fn->file, "rb");
+       if (f)
+         {
+            long pos;
+
+            fseek(f, 0, SEEK_END);
+            pos = ftell(f);
+            rewind(f);
+            fdata = malloc(pos);
+            if (fdata)
+              {
+                 if (fread(fdata, pos, 1, f) != 1)
+                   error_and_abort(ef, "Unable to read all of font "
+                                   "file \"%s\"\n", fn->file);
+                 fsize = pos;
+              }
+            fclose(f);
+         }
+       else
+         {
+            char *data;
+
+            EINA_LIST_FOREACH(fnt_dirs, ll, data)
+              {
+                 char buf[4096];
+
+                 snprintf(buf, sizeof(buf), "%s/%s", data, fn->file);
+                 f = fopen(buf, "rb");
+                 if (f)
+                   {
+                      long pos;
+
+                      fseek(f, 0, SEEK_END);
+                      pos = ftell(f);
+                      rewind(f);
+                      fdata = malloc(pos);
+                      if (fdata)
+                        {
+                           if (fread(fdata, pos, 1, f) != 1)
+                             error_and_abort(ef, "Unable to read all of font "
+                                             "file \"%s\"\n", buf);
+                           fsize = pos;
+                        }
+                      fclose(f);
+                      if (fdata) break;
+                   }
+              }
+         }
+       if (!fdata)
+         {
+            error_and_abort(ef, "Unable to load font part \"%s\" entry "
+                            "to %s \n", fn->file, file_out);
+         }
+       else
+         {
+            char buf[4096];
+
+            snprintf(buf, sizeof(buf), "fonts/%s", fn->name);
+            bytes = eet_write(ef, buf, fdata, fsize, 1);
+            if (bytes <= 0)
+              error_and_abort(ef, "Unable to write font part \"%s\" as \"%s\" "
+                              "part entry to %s \n", fn->file, buf, file_out);
+
+            *font_num += 1;
+            total_bytes += bytes;
+            *input_bytes += fsize;
+            *input_raw_bytes += fsize;
+
+            if (verbose)
+              {
+                 printf("%s: Wrote %9i bytes (%4iKb) for \"%s\" font entry \"%s\" compress: [real: %2.1f%%]\n",
+                        progname, bytes, (bytes + 512) / 1024, buf, fn->file,
+                        100 - (100 * (double)bytes) / ((double)(fsize))
+                        );
+              }
+            free(fdata);
+         }
+     }
+
+   return total_bytes;
+}
+
+static void
+error_and_abort_image_load_error(Eet_File *ef, const char *file, int error)
+{
+   const char *errmsg = evas_load_error_str(error);
+   char hint[1024] = "";
+
+   if (error == EVAS_LOAD_ERROR_DOES_NOT_EXIST)
+     {
+       snprintf
+         (hint, sizeof(hint),
+          " Check if path to file \"%s\" is correct "
+          "(both directory and file name).",
+          file);
+     }
+   else if (error == EVAS_LOAD_ERROR_CORRUPT_FILE)
+     {
+       snprintf
+         (hint, sizeof(hint),
+          " Check if file \"%s\" is consistent.",
+          file);
+     }
+   else if (error == EVAS_LOAD_ERROR_UNKNOWN_FORMAT)
+     {
+       const char *ext = strrchr(file, '.');
+       const char **itr, *known_loaders[] = {
+         /* list from evas_image_load.c */
+         "png",
+         "jpg",
+         "jpeg",
+         "jfif",
+         "eet",
+         "edj",
+         "eap",
+         "edb",
+         "xpm",
+         "tiff",
+         "tif",
+         "svg",
+         "svgz",
+         "gif",
+         "pbm",
+         "pgm",
+         "ppm",
+         "pnm",
+         NULL
+       };
+
+       if (!ext)
+         {
+            snprintf
+              (hint, sizeof(hint),
+               " File \"%s\" does not have an extension, "
+               "maybe it should?",
+               file);
+            goto show_err;
+         }
+
+       ext++;
+       for (itr = known_loaders; *itr; itr++)
+         {
+            if (strcasecmp(ext, *itr) == 0)
+              {
+                 snprintf
+                   (hint, sizeof(hint),
+                    " Check if Evas was compiled with %s module enabled and "
+                    "all required dependencies exist.",
+                    ext);
+                 goto show_err;
+              }
+         }
+
+       snprintf(hint, sizeof(hint),
+                " Check if Evas supports loading files of type \"%s\" (%s) "
+                "and this module was compiled and all its dependencies exist.",
+                ext, file);
+     }
+ show_err:
+   error_and_abort
+     (ef, "Unable to load image \"%s\" used by file \"%s\": %s.%s\n",
+      file, file_out, errmsg, hint);
+}
+
+static int
+data_write_images(Eet_File *ef, int *image_num, int *input_bytes, int *input_raw_bytes)
+{
+   Eina_List *l;
+   int bytes = 0;
+   int total_bytes = 0;
+
+   if ((edje_file) && (edje_file->image_dir))
+     {
+       Ecore_Evas *ee;
+       Evas *evas;
+       Edje_Image_Directory_Entry *img;
+
+       ecore_init();
+       ecore_evas_init();
+
+       ee = ecore_evas_buffer_new(1, 1);
+       if (!ee)
+         error_and_abort(ef, "Cannot create buffer engine canvas for image "
+                         "load.\n");
+
+       evas = ecore_evas_get(ee);
+       EINA_LIST_FOREACH(edje_file->image_dir->entries, l, img)
+         {
+            if (img->source_type == EDJE_IMAGE_SOURCE_TYPE_EXTERNAL)
+              {
+              }
+            else
+              {
+                 Evas_Object *im;
+                 Eina_List *ll;
+                 char *data;
+                 int load_err = EVAS_LOAD_ERROR_NONE;
+
+                 im = NULL;
+                 EINA_LIST_FOREACH(img_dirs, ll, data)
+                   {
+                      char buf[4096];
+
+                      snprintf(buf, sizeof(buf), "%s/%s",
+                               data, img->entry);
+                      im = evas_object_image_add(evas);
+                      if (im)
+                        {
+                           evas_object_image_file_set(im, buf, NULL);
+                           load_err = evas_object_image_load_error_get(im);
+                           if (load_err == EVAS_LOAD_ERROR_NONE)
+                             break;
+                           evas_object_del(im);
+                           im = NULL;
+                           if (load_err != EVAS_LOAD_ERROR_DOES_NOT_EXIST)
+                             break;
+                        }
+                   }
+                 if ((!im) && (load_err == EVAS_LOAD_ERROR_DOES_NOT_EXIST))
+                   {
+                      im = evas_object_image_add(evas);
+                      if (im)
+                        {
+                           evas_object_image_file_set(im, img->entry, NULL);
+                           load_err = evas_object_image_load_error_get(im);
+                           if (load_err != EVAS_LOAD_ERROR_NONE)
+                             {
+                                evas_object_del(im);
+                                im = NULL;
+                             }
+                        }
+                   }
+                 if (im)
+                   {
+                      void *im_data;
+                      int  im_w, im_h;
+                      int  im_alpha;
+                      char buf[256];
+
+                      evas_object_image_size_get(im, &im_w, &im_h);
+                      im_alpha = evas_object_image_alpha_get(im);
+                      im_data = evas_object_image_data_get(im, 0);
+                      if ((im_data) && (im_w > 0) && (im_h > 0))
+                        {
+                           int mode, qual;
+
+                           snprintf(buf, sizeof(buf), "images/%i", img->id);
+                           qual = 80;
+                           if ((img->source_type == EDJE_IMAGE_SOURCE_TYPE_INLINE_PERFECT) &&
+                               (img->source_param == 0))
+                             mode = 0; /* RAW */
+                           else if ((img->source_type == EDJE_IMAGE_SOURCE_TYPE_INLINE_PERFECT) &&
+                                    (img->source_param == 1))
+                             mode = 1; /* COMPRESS */
+                           else
+                             mode = 2; /* LOSSY */
+                           if ((mode == 0) && (no_raw))
+                             {
+                                mode = 1; /* promote compression */
+                                img->source_param = 95;
+                             }
+                           if ((mode == 2) && (no_lossy)) mode = 1; /* demote compression */
+                           if ((mode == 1) && (no_comp))
+                             {
+                                if (no_lossy) mode = 0; /* demote compression */
+                                else if (no_raw)
+                                  {
+                                     img->source_param = 90;
+                                     mode = 2; /* no choice. lossy */
+                                  }
+                             }
+                           if (mode == 2)
+                             {
+                                qual = img->source_param;
+                                if (qual < min_quality) qual = min_quality;
+                                if (qual > max_quality) qual = max_quality;
+                             }
+                           if (mode == 0)
+                             bytes = eet_data_image_write(ef, buf,
+                                                          im_data, im_w, im_h,
+                                                          im_alpha,
+                                                          0, 0, 0);
+                           else if (mode == 1)
+                             bytes = eet_data_image_write(ef, buf,
+                                                          im_data, im_w, im_h,
+                                                          im_alpha,
+                                                          1, 0, 0);
+                           else if (mode == 2)
+                             bytes = eet_data_image_write(ef, buf,
+                                                          im_data, im_w, im_h,
+                                                          im_alpha,
+                                                          0, qual, 1);
+                           if (bytes <= 0)
+                             error_and_abort(ef, "Unable to write image part "
+                                             "\"%s\" as \"%s\" part entry to "
+                                             "%s\n", img->entry, buf,
+                                             file_out);
+
+                           *image_num += 1;
+                           total_bytes += bytes;
+                        }
+                      else
+                        {
+                           error_and_abort_image_load_error
+                             (ef, img->entry, load_err);
+                        }
+
+                      if (verbose)
+                        {
+                           struct stat st;
+                           const char *file = NULL;
+
+                           evas_object_image_file_get(im, &file, NULL);
+                           if (!file || (stat(file, &st) != 0))
+                             st.st_size = 0;
+                           *input_bytes += st.st_size;
+                           *input_raw_bytes += im_w * im_h * 4;
+                           printf("%s: Wrote %9i bytes (%4iKb) for \"%s\" image entry \"%s\" compress: [raw: %2.1f%%] [real: %2.1f%%]\n",
+                                  progname, bytes, (bytes + 512) / 1024, buf, img->entry,
+                                  100 - (100 * (double)bytes) / ((double)(im_w * im_h * 4)),
+                                  100 - (100 * (double)bytes) / ((double)(st.st_size))
+                                  );
+                        }
+                      evas_object_del(im);
+                   }
+                 else
+                   {
+                      error_and_abort_image_load_error
+                        (ef, img->entry, load_err);
+                   }
+              }
+         }
+       ecore_evas_free(ee);
+       ecore_evas_shutdown();
+       ecore_shutdown();
+     }
+
+   return total_bytes;
+}
+
+static void
+check_groups_names(Eet_File *ef)
+{
+   Eina_List *l;
+   Edje_Part_Collection_Directory_Entry *de;
+
+   if (!edje_file->collection_dir)
+     return;
+
+   /* check that all groups have names */
+   EINA_LIST_FOREACH(edje_file->collection_dir->entries, l, de)
+       if (!de->entry)
+         error_and_abort(ef, "Collection %i: name missing.\n", de->id);
+}
+
+static void
+check_spectra(Eet_File *ef)
+{
+   Eina_List *l;
+   Edje_Spectrum_Directory_Entry *se;
+
+   if (!edje_file->spectrum_dir)
+     return;
+
+   /* check that all spectra are valid */
+   EINA_LIST_FOREACH(edje_file->spectrum_dir->entries, l, se)
+     check_spectrum(se, ef);
+}
+
+static void
+check_groups(Eet_File *ef)
+{
+   Eina_List *l;
+   Edje_Part_Collection *pc;
+
+   /* sanity checks for parts and programs */
+   EINA_LIST_FOREACH(edje_collections, l, pc)
+     {
+       Eina_List *ll;
+       Edje_Part *part;
+       Edje_Program *prog;
+
+       EINA_LIST_FOREACH(pc->parts, ll, part)
+         check_part(pc, part, ef);
+       EINA_LIST_FOREACH(pc->programs, ll, prog)
+         check_program(pc, prog, ef);
+     }
+}
+
+static int
+data_write_groups(Eet_File *ef, int *collection_num)
+{
+   Eina_List *l;
+   Edje_Part_Collection *pc;
+   int bytes = 0;
+   int total_bytes = 0;
+
+   EINA_LIST_FOREACH(edje_collections, l, pc)
+     {
+       char buf[4096];
+
+       snprintf(buf, sizeof(buf), "collections/%i", pc->id);
+       bytes = eet_data_write(ef, edd_edje_part_collection, buf, pc, 1);
+       if (bytes <= 0)
+         error_and_abort(ef, "Error. Unable to write \"%s\" part entry "
+                         "to %s\n", buf, file_out);
+
+       *collection_num += 1;
+       total_bytes += bytes;
+
+       if (verbose)
+         {
+            printf("%s: Wrote %9i bytes (%4iKb) for \"%s\" collection entry\n",
+                   progname, bytes, (bytes + 512) / 1024, buf);
+         }
+     }
+
+   return total_bytes;
+}
+
+static void
+create_script_file(Eet_File *ef, const char *filename, const Code *cd)
+{
+   FILE *f = fopen(filename, "wb");
+   if (!f)
+     error_and_abort(ef, "Unable to open temp file \"%s\" for script "
+                    "compilation.\n", filename);
+
+   Eina_List *ll;
+   Code_Program *cp;
+
+   fprintf(f, "#include <edje>\n");
+   int ln = 2;
+
+   if (cd->shared)
+     {
+       while (ln < (cd->l1 - 1))
+         {
+            fprintf(f, " \n");
+            ln++;
+         }
+       {
+          char *sp;
+          int hash = 0;
+          int newlined = 0;
+
+          for (sp = cd->shared; *sp; sp++)
+            {
+               if ((sp[0] == '#') && (newlined))
+                 {
+                    hash = 1;
+                 }
+               newlined = 0;
+               if (sp[0] == '\n') newlined = 1;
+               if (!hash) fputc(sp[0], f);
+               else if (sp[0] == '\n') hash = 0;
+            }
+          fputc('\n', f);
+       }
+       ln += cd->l2 - cd->l1 + 1;
+     }
+   EINA_LIST_FOREACH(cd->programs, ll, cp)
+     {
+       if (cp->script)
+         {
+            while (ln < (cp->l1 - 1))
+              {
+                 fprintf(f, " \n");
+                 ln++;
+              }
+            /* FIXME: this prototype needs to be */
+            /* formalised and set in stone */
+            fprintf(f, "public _p%i(sig[], src[]) {", cp->id);
+            {
+               char *sp;
+               int hash = 0;
+               int newlined = 0;
+
+               for (sp = cp->script; *sp; sp++)
+                 {
+                    if ((sp[0] == '#') && (newlined))
+                      {
+                         hash = 1;
+                      }
+                    newlined = 0;
+                    if (sp[0] == '\n') newlined = 1;
+                    if (!hash) fputc(sp[0], f);
+                    else if (sp[0] == '\n') hash = 0;
+                 }
+            }
+            fprintf(f, "}");
+            ln += cp->l2 - cp->l1 + 1;
+         }
+     }
+
+   fclose(f);
+}
+
+static void
+compile_script_file(Eet_File *ef, const char *source, const char *output,
+                   int script_num)
+{
+   FILE *f;
+   char buf[4096];
+   int ret;
+
+   snprintf(buf, sizeof(buf),
+           "embryo_cc -i %s/include -o %s %s",
+           e_prefix_data_get(), output, source);
+   ret = system(buf);
+
+   /* accept warnings in the embryo code */
+   if (ret < 0 || ret > 1)
+     error_and_abort(ef, "Compiling script code not clean.\n");
+
+   f = fopen(output, "rb");
+   if (!f)
+     error_and_abort(ef, "Unable to open script object \"%s\" for reading.\n",
+                    output);
+
+   fseek(f, 0, SEEK_END);
+   int size = ftell(f);
+   rewind(f);
+
+   if (size > 0)
+     {
+       void *data = malloc(size);
+
+       if (data)
+         {
+            if (fread(data, size, 1, f) != 1)
+              error_and_abort(ef, "Unable to read all of script object "
+                              "\"%s\"\n", output);
+
+            snprintf(buf, sizeof(buf), "scripts/%i", script_num);
+            eet_write(ef, buf, data, size, 1);
+            free(data);
+         }
+     }
+
+   fclose(f);
+}
+
+static void
+data_write_scripts(Eet_File *ef)
+{
+   Eina_List *l;
+   int i;
+
+   if (!tmp_dir)
+#ifdef HAVE_EVIL
+     tmp_dir = (char *)evil_tmpdir_get();
+#else
+     tmp_dir = "/tmp";
+#endif
+
+   for (i = 0, l = codes; l; l = eina_list_next(l), i++)
+     {
+       char tmpn[PATH_MAX];
+       char tmpo[PATH_MAX];
+       int fd;
+       Code *cd = eina_list_data_get(l);
+       
+       if (cd->is_lua)
+         continue;
+       if ((!cd->shared) && (!cd->programs))
+         continue;
+
+       snprintf(tmpn, PATH_MAX, "%s/edje_cc.sma-tmp-XXXXXX", tmp_dir);
+       fd = mkstemp(tmpn);
+       if (fd < 0)
+         error_and_abort(ef, "Unable to open temp file \"%s\" for script "
+                         "compilation.\n", tmpn);
+
+       create_script_file(ef, tmpn, cd);
+       close(fd);
+
+       snprintf(tmpo, PATH_MAX, "%s/edje_cc.amx-tmp-XXXXXX", tmp_dir);
+       fd = mkstemp(tmpo);
+       if (fd < 0)
+         {
+            unlink(tmpn);
+            error_and_abort(ef, "Unable to open temp file \"%s\" for script "
+                            "compilation.\n", tmpn);
+         }
+
+       compile_script_file(ef, tmpn, tmpo, i);
+       close(fd);
+
+       unlink(tmpn);
+       unlink(tmpo);
+     }
+}
+
+typedef struct _Edje_Lua_Script_Writer_Struct Edje_Lua_Script_Writer_Struct;
+
+struct _Edje_Lua_Script_Writer_Struct {
+   char *buf;
+   int size;
+};
+
+#ifdef LUA_BINARY
+static int
+_edje_lua_script_writer (lua_State *L __UNUSED__, const void* chunk_buf, size_t chunk_size, void* _data)
+{
+   Edje_Lua_Script_Writer_Struct *data;
+   void *old;
+
+   data = (Edje_Lua_Script_Writer_Struct *)_data;
+   old = data->buf;
+   data->buf = malloc (data->size + chunk_size);
+   memcpy (data->buf, old, data->size);
+   memcpy (&((data->buf)[data->size]), chunk_buf, chunk_size);
+   if (old)
+     free (old);
+   data->size += chunk_size;
+
+   return 0;
+}
+#endif
+
+void
+_edje_lua_error_and_abort(lua_State * L, int err_code, Eet_File *ef)
+{
+   char *err_type;
+
+   switch (err_code)
+     {
+     case LUA_ERRRUN:
+       err_type = "runtime";
+       break;
+     case LUA_ERRSYNTAX:
+       err_type = "syntax";
+       break;
+     case LUA_ERRMEM:
+       err_type = "memory allocation";
+       break;
+     case LUA_ERRERR:
+       err_type = "error handler";
+       break;
+     default:
+       err_type = "unknown";
+       break;
+     }
+   error_and_abort(ef, "Lua %s error: %s\n", err_type, lua_tostring(L, -1));
+}
+
+
+static void
+data_write_lua_scripts(Eet_File *ef)
+{
+   Eina_List *l;
+   Eina_List *ll;
+   Code_Program *cp;
+   int i;
+
+   for (i = 0, l = codes; l; l = eina_list_next(l), i++)
+     {
+       char buf[4096];
+       Code *cd;
+       lua_State *L;
+       int ln = 1;
+       luaL_Buffer b;
+       Edje_Lua_Script_Writer_Struct data;
+#ifdef LUA_BINARY
+       int err_code;
+#endif
+
+       cd = (Code *)eina_list_data_get(l);
+       if (!cd->is_lua)
+         continue;
+       if ((!cd->shared) && (!cd->programs))
+         continue;
+       
+       L = luaL_newstate();
+       if (!L)
+         error_and_abort(ef, "Lua error: Lua state could not be initialized\n");
+
+       luaL_buffinit(L, &b);
+
+       data.buf = NULL;
+       data.size = 0;
+       if (cd->shared)
+         {
+            while (ln < (cd->l1 - 1))
+              {
+                 luaL_addchar(&b, '\n');
+                 ln++;
+              }
+            luaL_addstring(&b, cd->shared);
+            ln += cd->l2 - cd->l1;
+         }
+
+       EINA_LIST_FOREACH(cd->programs, ll, cp)
+         {
+            if (cp->script)
+              {
+                 while (ln < (cp->l1 - 1))
+                   {
+                      luaL_addchar(&b, '\n');
+                      ln++;
+                   }
+                 luaL_addstring(&b, "_G[");
+                 lua_pushnumber(L, cp->id);
+                 luaL_addvalue(&b);
+                 luaL_addstring(&b, "] = function (ed, signal, source)");
+                 luaL_addstring(&b, cp->script);
+                 luaL_addstring(&b, "end\n");
+                 ln += cp->l2 - cp->l1 + 1;
+              }
+         }
+       luaL_pushresult(&b);
+#ifdef LUA_BINARY
+       if (err_code = luaL_loadstring(L, lua_tostring (L, -1)))
+         _edje_lua_error_and_abort(L, err_code, ef);
+       lua_dump(L, _edje_lua_script_writer, &data);
+#else // LUA_PLAIN_TEXT
+       data.buf = (char *)lua_tostring(L, -1);
+       data.size = strlen(data.buf);
+#endif
+       //printf("lua chunk size: %d\n", data.size);
+
+       /* 
+        * TODO load and test Lua chunk
+        */
+
+       /*
+          if (luaL_loadbuffer(L, globbuf, globbufsize, "edje_lua_script"))
+          printf("lua load error: %s\n", lua_tostring (L, -1));
+          if (lua_pcall(L, 0, 0, 0))
+          printf("lua call error: %s\n", lua_tostring (L, -1));
+        */
+       
+       snprintf(buf, sizeof(buf), "lua_scripts/%i", i);
+       eet_write(ef, buf, data.buf, data.size, 1);
+#ifdef LUA_BINARY
+       free(data.buf);
+#endif
+       lua_close(L);
+     }
+}
+
+void
+data_write(void)
+{
+   Eet_File *ef;
+   int input_bytes = 0;
+   int total_bytes = 0;
+   int src_bytes = 0;
+   int fmap_bytes = 0;
+   int input_raw_bytes = 0;
+   int image_num = 0;
+   int font_num = 0;
+   int collection_num = 0;
+
+   ef = eet_open(file_out, EET_FILE_MODE_WRITE);
+   if (!ef)
+     {
+       ERR("%s: Error. Unable to open \"%s\" for writing output",
+           progname, file_out);
+       exit(-1);
+     }
+
+   total_bytes += data_write_header(ef);
+   total_bytes += data_write_fonts(ef, &font_num, &input_bytes,
+                                  &input_raw_bytes);
+   total_bytes += data_write_images(ef, &image_num, &input_bytes,
+                                   &input_raw_bytes);
+
+   check_groups_names(ef);
+   check_spectra(ef);
+   check_groups(ef);
+
+   total_bytes += data_write_groups(ef, &collection_num);
+   data_write_scripts(ef);
+   data_write_lua_scripts(ef);
+
+   src_bytes = source_append(ef);
+   total_bytes += src_bytes;
+   fmap_bytes = source_fontmap_save(ef, fonts);
+   total_bytes += fmap_bytes;
+
+   eet_close(ef);
+
+   if (verbose)
+     {
+       struct stat st;
+
+       if (stat(file_in, &st) != 0)
+         st.st_size = 0;
+       input_bytes += st.st_size;
+       input_raw_bytes += st.st_size;
+       printf("Summary:\n"
+              "  Wrote %i collections\n"
+              "  Wrote %i images\n"
+              "  Wrote %i fonts\n"
+              "  Wrote %i bytes (%iKb) of original source data\n"
+              "  Wrote %i bytes (%iKb) of original source font map\n"
+              "Conservative compression summary:\n"
+              "  Wrote total %i bytes (%iKb) from %i (%iKb) input data\n"
+              "  Output file is %3.1f%% the size of the input data\n"
+              "  Saved %i bytes (%iKb)\n"
+              "Raw compression summary:\n"
+              "  Wrote total %i bytes (%iKb) from %i (%iKb) raw input data\n"
+              "  Output file is %3.1f%% the size of the raw input data\n"
+              "  Saved %i bytes (%iKb)\n"
+              ,
+              collection_num,
+              image_num,
+              font_num,
+              src_bytes, (src_bytes + 512) / 1024,
+              fmap_bytes, (fmap_bytes + 512) / 1024,
+              total_bytes, (total_bytes + 512) / 1024,
+              input_bytes, (input_bytes + 512) / 1024,
+              (100.0 * (double)total_bytes) / (double)input_bytes,
+              input_bytes - total_bytes,
+              (input_bytes - total_bytes + 512) / 1024,
+              total_bytes, (total_bytes + 512) / 1024,
+              input_raw_bytes, (input_raw_bytes + 512) / 1024,
+              (100.0 * (double)total_bytes) / (double)input_raw_bytes,
+              input_raw_bytes - total_bytes,
+              (input_raw_bytes - total_bytes + 512) / 1024);
+     }
+}
+
+void
+data_queue_group_lookup(char *name)
+{
+   Group_Lookup *gl;
+
+   gl = mem_alloc(SZ(Group_Lookup));
+   group_lookups = eina_list_append(group_lookups, gl);
+   gl->name = mem_strdup(name);
+}
+
+void
+data_queue_part_lookup(Edje_Part_Collection *pc, char *name, int *dest)
+{
+   Part_Lookup *pl;
+
+   pl = mem_alloc(SZ(Part_Lookup));
+   part_lookups = eina_list_append(part_lookups, pl);
+   pl->pc = pc;
+   pl->name = mem_strdup(name);
+   pl->dest = dest;
+}
+
+void
+data_queue_program_lookup(Edje_Part_Collection *pc, char *name, int *dest)
+{
+   Program_Lookup *pl;
+
+   pl = mem_alloc(SZ(Program_Lookup));
+   program_lookups = eina_list_append(program_lookups, pl);
+   pl->pc = pc;
+   pl->name = mem_strdup(name);
+   pl->dest = dest;
+}
+
+void
+data_queue_image_lookup(char *name, int *dest)
+{
+   Image_Lookup *il;
+
+   il = mem_alloc(SZ(Image_Lookup));
+   image_lookups = eina_list_append(image_lookups, il);
+   il->name = mem_strdup(name);
+   il->dest = dest;
+}
+
+void
+data_queue_spectrum_lookup(char *name, int *dest)
+{
+   Spectrum_Lookup *sl;
+
+   sl = mem_alloc(SZ(Spectrum_Lookup));
+   spectrum_lookups = eina_list_append(spectrum_lookups, sl);
+   sl->name = mem_strdup(name);
+   sl->dest = dest;
+}
+
+void
+data_queue_part_slave_lookup(int *master, int *slave)
+{
+   Slave_Lookup *sl;
+
+   sl = mem_alloc(SZ(Slave_Lookup));
+   part_slave_lookups = eina_list_append(part_slave_lookups, sl);
+   sl->master = master;
+   sl->slave = slave;
+}
+
+void
+data_queue_image_slave_lookup(int *master, int *slave)
+{
+   Slave_Lookup *sl;
+
+   sl = mem_alloc(SZ(Slave_Lookup));
+   image_slave_lookups = eina_list_append(image_slave_lookups, sl);
+   sl->master = master;
+   sl->slave = slave;
+}
+
+void
+data_queue_spectrum_slave_lookup(int *master, int *slave)
+{
+   Slave_Lookup *sl;
+
+   sl = mem_alloc(SZ(Slave_Lookup));
+   spectrum_slave_lookups = eina_list_append(spectrum_slave_lookups, sl);
+   sl->master = master;
+   sl->slave = slave;
+}
+
+void
+handle_slave_lookup(Eina_List *list, int *master, int value)
+{
+   Eina_List *l;
+   Slave_Lookup *sl;
+
+   EINA_LIST_FOREACH(list, l, sl)
+     if (sl->master == master)
+       *sl->slave = value;
+}
+
+void
+data_process_lookups(void)
+{
+   Eina_List *l;
+
+   while (part_lookups)
+     {
+       Part_Lookup *pl;
+       Edje_Part *ep;
+
+       pl = eina_list_data_get(part_lookups);
+
+       EINA_LIST_FOREACH(pl->pc->parts, l, ep)
+         {
+            if ((ep->name) && (!strcmp(ep->name, pl->name)))
+              {
+                 handle_slave_lookup(part_slave_lookups, pl->dest, ep->id);
+                 *(pl->dest) = ep->id;
+                 break;
+              }
+         }
+       if (!l)
+         {
+            ERR("%s: Error. Unable to find part name \"%s\".",
+                progname, pl->name);
+            exit(-1);
+         }
+       part_lookups = eina_list_remove(part_lookups, pl);
+       free(pl->name);
+       free(pl);
+     }
+
+   while (program_lookups)
+     {
+       Program_Lookup *pl;
+       Edje_Program *ep;
+
+       pl = eina_list_data_get(program_lookups);
+
+       EINA_LIST_FOREACH(pl->pc->programs, l, ep)
+         {
+            if ((ep->name) && (!strcmp(ep->name, pl->name)))
+              {
+                 *(pl->dest) = ep->id;
+                 break;
+              }
+         }
+       if (!l)
+         {
+            ERR("%s: Error. Unable to find program name \"%s\".",
+                progname, pl->name);
+            exit(-1);
+         }
+       program_lookups = eina_list_remove(program_lookups, pl);
+       free(pl->name);
+       free(pl);
+     }
+
+   while (group_lookups)
+     {
+        Group_Lookup *gl;
+       Edje_Part_Collection_Directory_Entry *de;
+
+        gl = eina_list_data_get(group_lookups);
+
+       EINA_LIST_FOREACH(edje_file->collection_dir->entries, l, de)
+          {
+             if (!strcmp(de->entry, gl->name))
+               {
+                  break;
+               }
+          }
+        if (!l)
+          {
+             ERR("%s: Error. Unable to find group name \"%s\".",
+                progname, gl->name);
+             exit(-1);
+          }
+        group_lookups = eina_list_remove(group_lookups, gl);
+        free(gl->name);
+        free(gl);
+     }
+
+   while (image_lookups)
+     {
+       Image_Lookup *il;
+       Edje_Image_Directory_Entry *de;
+
+       il = eina_list_data_get(image_lookups);
+
+       if (!edje_file->image_dir)
+         l = NULL;
+       else
+         {
+            EINA_LIST_FOREACH(edje_file->image_dir->entries, l, de)
+              {
+                 if ((de->entry) && (!strcmp(de->entry, il->name)))
+                   {
+                      handle_slave_lookup(image_slave_lookups, il->dest, de->id);
+                      if (de->source_type == EDJE_IMAGE_SOURCE_TYPE_EXTERNAL)
+                        *(il->dest) = -de->id - 1;
+                      else
+                        *(il->dest) = de->id;
+                      break;
+                   }
+              }
+         }
+
+       if (!l)
+         {
+            ERR("%s: Error. Unable to find image name \"%s\".",
+                progname, il->name);
+            exit(-1);
+         }
+       image_lookups = eina_list_remove(image_lookups, il);
+       free(il->name);
+       free(il);
+     }
+
+   while (spectrum_lookups)
+     {
+       Spectrum_Lookup *il;
+       Edje_Spectrum_Directory_Entry *de;
+
+       il = eina_list_data_get(spectrum_lookups);
+
+       if (!edje_file->spectrum_dir)
+         l = NULL;
+       else
+         {
+            EINA_LIST_FOREACH(edje_file->spectrum_dir->entries, l, de)
+              {
+                 *(il->dest) = 1;
+                 if ((de->entry) && (!strcmp(de->entry, il->name)))
+                   {
+                      handle_slave_lookup(spectrum_slave_lookups, il->dest, de->id);
+                      *(il->dest) = de->id;
+                      break;
+                   }
+              }
+         }
+
+       if (!l)
+         {
+            ERR("%s: Error. unable to find spectrum name %s",
+                progname, il->name);
+            exit(-1);
+         }
+       spectrum_lookups = eina_list_remove(spectrum_lookups, il);
+       free(il->name);
+       free(il);
+     }
+
+   while (part_slave_lookups)
+     {
+        free(eina_list_data_get(part_slave_lookups));
+       part_slave_lookups = eina_list_remove_list(part_slave_lookups, part_slave_lookups);
+     }
+
+   while (image_slave_lookups)
+     {
+        free(eina_list_data_get(image_slave_lookups));
+       image_slave_lookups = eina_list_remove_list(image_slave_lookups, image_slave_lookups);
+     }
+
+   while (spectrum_slave_lookups)
+     {
+        free(eina_list_data_get(spectrum_slave_lookups));
+       spectrum_slave_lookups = eina_list_remove_list(spectrum_slave_lookups, spectrum_slave_lookups);
+     }
+}
+
+static void
+data_process_string(Edje_Part_Collection *pc, const char *prefix, char *s, void (*func)(Edje_Part_Collection *pc, char *name, char* ptr, int len))
+{
+   char *p;
+   char *key;
+   int keyl;
+   int quote, escape;
+
+   key = alloca(strlen(prefix) + 2 + 1);
+   if (!key) return;
+   strcpy(key, prefix);
+   strcat(key, ":\"");
+   keyl = strlen(key);
+   quote = 0;
+   escape = 0;
+   for (p = s; (p) && (*p); p++)
+     {
+       if (!quote)
+         {
+            if (*p == '\"')
+              {
+                 quote = 1;
+                 p++;
+              }
+         }
+       if (!quote)
+         {
+            if (!strncmp(p, key, keyl))
+              {
+                  char *ptr;
+                  int len;
+                  int inesc = 0;
+                 char *name;
+
+                  ptr = p;
+                  p += keyl;
+                 while ((*p))
+                   {
+                      if (!inesc)
+                        {
+                           if (*p == '\\') inesc = 1;
+                           else if (*p == '\"')
+                             {
+                                /* string concatenation, see below */
+                                if (*(p + 1) != '\"')
+                                  break;
+                                else
+                                  p++;
+                             }
+                        }
+                       else
+                            inesc = 0;
+                       p++;
+                   }
+                 len = p - ptr + 1;
+                 name = alloca(len);
+                 if (name)
+                   {
+                      char *pp;
+                      int i;
+
+                      name[0] = 0;
+                      pp = ptr + keyl;
+                      inesc = 0;
+                      i = 0;
+                      while (*pp)
+                        {
+                           if (!inesc)
+                             {
+                                if (*pp == '\\') inesc = 1;
+                                else if (*pp == '\"')
+                                  {
+                                     /* concat strings like "foo""bar" to "foobar" */
+                                     if (*(pp + 1) == '\"')
+                                       pp++;
+                                     else
+                                       {
+                                          name[i] = 0;
+                                          break;
+                                       }
+                                  }
+                                else
+                                  {
+                                     name[i] = *pp;
+                                     name[i + 1] = 0;
+                                     i++;
+                                  }
+                             }
+                           else
+                              inesc = 0;
+                           pp++;
+                       }
+                     func(pc, name, ptr, len);
+                  }
+              }
+         }
+       else
+         {
+            if (!escape)
+              {
+                 if (*p == '\"') quote = 0;
+                 else if (*p == '\\') escape = 1;
+              }
+            else if (escape)
+              {
+                 escape = 0;
+              }
+         }
+     }
+}
+
+static void
+_data_queue_part_lookup(Edje_Part_Collection *pc, char *name, char *ptr, int len)
+{
+   Code_Lookup *cl;
+   cl = mem_alloc(SZ(Code_Lookup));
+   cl->ptr = ptr;
+   cl->len = len;
+
+   data_queue_part_lookup(pc, name, &(cl->val));
+
+   code_lookups = eina_list_append(code_lookups, cl);
+}
+static void
+_data_queue_program_lookup(Edje_Part_Collection *pc, char *name, char *ptr, int len)
+{
+   Code_Lookup *cl;
+
+   cl = mem_alloc(SZ(Code_Lookup));
+   cl->ptr = ptr;
+   cl->len = len;
+
+   data_queue_program_lookup(pc, name, &(cl->val));
+
+   code_lookups = eina_list_append(code_lookups, cl);
+}
+static void
+_data_queue_group_lookup(Edje_Part_Collection *pc __UNUSED__, char *name, char *ptr __UNUSED__, int len __UNUSED__)
+{
+   data_queue_group_lookup(name);      
+}
+static void
+_data_queue_image_pc_lookup(Edje_Part_Collection *pc __UNUSED__, char *name, char *ptr, int len)
+{
+   Code_Lookup *cl;
+
+   cl = mem_alloc(SZ(Code_Lookup));
+   cl->ptr = ptr;
+   cl->len = len;
+
+   data_queue_image_lookup(name, &(cl->val));
+
+   code_lookups = eina_list_append(code_lookups, cl);
+}
+
+void
+data_process_scripts(void)
+{
+   Eina_List *l, *l2;
+
+   for (l = codes, l2 = edje_collections; (l) && (l2); l = eina_list_next(l), l2 = eina_list_next(l2))
+     {
+       Code *cd;
+       Edje_Part_Collection *pc;
+
+       cd = eina_list_data_get(l);
+       pc = eina_list_data_get(l2);
+       if ((cd->shared) || (cd->programs))
+         {
+            Eina_List *ll;
+            Code_Program *cp;
+
+            if ((cd->shared) && (!cd->is_lua))
+              {
+                 data_process_string(pc, "PART",    cd->shared, _data_queue_part_lookup);
+                 data_process_string(pc, "PROGRAM", cd->shared, _data_queue_program_lookup);
+                 data_process_string(pc, "IMAGE",   cd->shared, _data_queue_image_pc_lookup);
+                 data_process_string(pc, "GROUP",   cd->shared, _data_queue_group_lookup);
+              }
+            EINA_LIST_FOREACH(cd->programs, ll, cp)
+              {
+                 if (cp->script)
+                   {
+                      data_process_string(pc, "PART",    cp->script, _data_queue_part_lookup);
+                      data_process_string(pc, "PROGRAM", cp->script, _data_queue_program_lookup);
+                      data_process_string(pc, "IMAGE",   cp->script, _data_queue_image_pc_lookup);
+                      data_process_string(pc, "GROUP",   cp->script, _data_queue_group_lookup);
+                   }
+              }
+         }
+     }
+}
+
+void
+data_process_script_lookups(void)
+{
+   Eina_List *l;
+   Code_Lookup *cl;
+
+   EINA_LIST_FOREACH(code_lookups, l, cl)
+     {
+       char buf[12];
+       int n;
+
+       n = eina_convert_itoa(cl->val, buf);
+       if (n > cl->len)
+         {
+            ERR("%s: Error. The unexpected happened. A numeric replacement string was larger than the original!",
+                progname);
+            exit(-1);
+         }
+       memset(cl->ptr, ' ', cl->len);
+       strncpy(cl->ptr, buf, n);
+     }
+}
diff --git a/src/bin/edje_cc_parse.c b/src/bin/edje_cc_parse.c
new file mode 100644 (file)
index 0000000..94909d1
--- /dev/null
@@ -0,0 +1,1540 @@
+/*
+ * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef HAVE_ALLOCA_H
+# include <alloca.h>
+#elif defined __GNUC__
+# define alloca __builtin_alloca
+#elif defined _AIX
+# define alloca __alloca
+#elif defined _MSC_VER
+# include <malloc.h>
+# define alloca _alloca
+#else
+# include <stddef.h>
+# ifdef  __cplusplus
+extern "C"
+# endif
+void *alloca (size_t);
+#endif
+
+#include <string.h>
+#include <ctype.h>
+#include <limits.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <math.h>
+
+#include "edje_cc.h"
+#include <Ecore.h>
+#include <Ecore_File.h>
+
+static void  new_object(void);
+static void  new_statement(void);
+static char *perform_math (char *input);
+static int   isdelim(char c);
+static char *next_token(char *p, char *end, char **new_p, int *delim);
+static char *stack_id(void);
+static void  stack_chop_top(void);
+static void  parse(char *data, off_t size);
+
+/* simple expression parsing protos */
+static int my_atoi(const char * s);
+static char * _alphai(char *s, int * val);
+static char * _betai(char *s, int * val);
+static char * _gammai(char *s, int * val);
+static char * _deltai(char *s, int * val);
+static char * _get_numi(char *s, int * val);
+static int _is_numi(char c);
+static int _is_op1i(char c);
+static int _is_op2i(char c);
+static int _calci(char op, int a, int b);
+
+static double my_atof(const char * s);
+static char * _alphaf(char *s, double * val);
+static char * _betaf(char *s, double * val);
+static char * _gammaf(char *s, double * val);
+static char * _deltaf(char *s, double * val);
+static char * _get_numf(char *s, double * val);
+static int _is_numf(char c);
+static int _is_op1f(char c);
+static int _is_op2f(char c);
+static double _calcf(char op, double a, double b);
+static int strstrip(const char *in, char *out, size_t size);
+
+
+int        line = 0;
+Eina_List *stack = NULL;
+Eina_List *params = NULL;
+
+static char  file_buf[4096];
+static int   verbatim = 0;
+static int   verbatim_line1 = 0;
+static int   verbatim_line2 = 0;
+static char *verbatim_str = NULL;
+
+static void
+new_object(void)
+{
+   char *id;
+   int i;
+   int handled = 0;
+
+   id = stack_id();
+   for (i = 0; i < object_handler_num(); i++)
+     {
+       if (!strcmp(object_handlers[i].type, id))
+         {
+            handled = 1;
+            if (object_handlers[i].func)
+              {
+                 object_handlers[i].func();
+              }
+            break;
+         }
+     }
+   if (!handled)
+     {
+       for (i = 0; i < statement_handler_num(); i++)
+         {
+            if (!strcmp(statement_handlers[i].type, id))
+              {
+                 free(id);
+                 return;
+              }
+         }
+     }
+   if (!handled)
+     {
+       ERR("%s: Error. %s:%i unhandled keyword %s",
+           progname, file_in, line - 1,
+           (char *)eina_list_data_get(eina_list_last(stack)));
+       exit(-1);
+     }
+   free(id);
+}
+
+static void
+new_statement(void)
+{
+   char *id;
+   int i;
+   int handled = 0;
+
+   id = stack_id();
+   for (i = 0; i < statement_handler_num(); i++)
+     {
+       if (!strcmp(statement_handlers[i].type, id))
+         {
+            handled = 1;
+            if (statement_handlers[i].func)
+              {
+                 statement_handlers[i].func();
+              }
+            break;
+         }
+     }
+   if (!handled)
+     {
+       ERR("%s: Error. %s:%i unhandled keyword %s",
+           progname, file_in, line - 1,
+           (char *)eina_list_data_get(eina_list_last(stack)));
+       exit(-1);
+     }
+   free(id);
+}
+
+static char *
+perform_math (char *input)
+{
+   char buf[256];
+   double res;
+
+   /* FIXME
+    * Always apply floating-point arithmetic.
+    * Does this cause problems for integer parameters? (yes it will)
+    *
+    * What we should do is, loop over the string and figure out whether
+    * there are floating point operands, too and then switch to
+    * floating point math.
+    */
+   res = my_atof(input);
+   snprintf(buf, sizeof (buf), "%lf", res);
+   return strdup(buf);
+}
+
+static int
+isdelim(char c)
+{
+   const char *delims = "{},;:";
+   char *d;
+
+   d = (char *)delims;
+   while (*d)
+     {
+       if (c == *d) return 1;
+       d++;
+     }
+   return 0;
+}
+
+static char *
+next_token(char *p, char *end, char **new_p, int *delim)
+{
+   char *tok_start = NULL, *tok_end = NULL, *tok = NULL, *sa_start = NULL;
+   int in_tok = 0;
+   int in_quote = 0;
+   int in_parens = 0;
+   int in_comment_ss  = 0;
+   int in_comment_cpp = 0;
+   int in_comment_sa  = 0;
+   int had_quote = 0;
+   int is_escaped = 0;
+   char *cpp_token_line = NULL;
+   char *cpp_token_file = NULL;
+
+   *delim = 0;
+   if (p >= end) return NULL;
+   while (p < end)
+     {
+       if (*p == '\n')
+         {
+            in_comment_ss = 0;
+            in_comment_cpp = 0;
+            cpp_token_line = NULL;
+            cpp_token_file = NULL;
+            line++;
+         }
+       if ((!in_comment_ss) && (!in_comment_sa))
+         {
+            if ((!in_quote) && (*p == '/') && (p < (end - 1)) && (*(p + 1) == '/'))
+              in_comment_ss = 1;
+            if ((!in_quote) && (*p == '#'))
+              in_comment_cpp = 1;
+            if ((!in_quote) && (*p == '/') && (p < (end - 1)) && (*(p + 1) == '*'))
+              {
+                 in_comment_sa = 1;
+                 sa_start = p;
+              }
+         }
+       if ((in_comment_cpp) && (*p == '#'))
+         {
+            char *pp, fl[4096];
+            char *tmpstr = NULL;
+            int   l, nm;
+
+            /* handle cpp comments */
+            /* their line format is
+             * # <line no. of next line> <filename from next line on> [??]
+             */
+            cpp_token_line = NULL;
+            cpp_token_file = NULL;
+
+            pp = p;
+            while ((pp < end) && (*pp != '\n'))
+              {
+                 pp++;
+              }
+            l = pp - p;
+            tmpstr = alloca(l + 1);
+            if (!tmpstr)
+              {
+                 ERR("%s: Error. %s:%i malloc %i bytes failed",
+                     progname, file_in, line - 1, l + 1);
+                 exit(-1);
+              }
+            strncpy(tmpstr, p, l);
+            tmpstr[l] = 0;
+            l = sscanf(tmpstr, "%*s %i \"%[^\"]\"", &nm, fl);
+            if (l == 2)
+              {
+                 strcpy(file_buf, fl);
+                 line = nm;
+                 file_in = file_buf;
+              }
+         }
+       else if ((!in_comment_ss) && (!in_comment_sa) && (!in_comment_cpp))
+         {
+            if (!in_tok)
+              {
+                 if (!in_quote)
+                   {
+                      if (!isspace(*p))
+                        {
+                           if (*p == '"')
+                             {
+                                in_quote = 1;
+                                had_quote = 1;
+                             }
+                           else if (*p == '(')
+                             in_parens++;
+
+                           in_tok = 1;
+                           tok_start = p;
+                           if (isdelim(*p)) *delim = 1;
+                        }
+                   }
+              }
+            else
+              {
+                 if (in_quote)
+                   {
+                      if ((*p) == '\\')
+                        is_escaped = !is_escaped;
+                      else if (((*p) == '"') && (!is_escaped))
+                        {
+                           in_quote = 0;
+                           had_quote = 1;
+                        }
+                      else if (is_escaped)
+                        is_escaped = 0;
+                   }
+                 else if (in_parens)
+                   {
+                      if (((*p) == ')') && (!is_escaped))
+                        in_parens--;
+                   }
+                 else
+                   {
+                      if (*p == '"')
+                        {
+                           in_quote = 1;
+                           had_quote = 1;
+                        }
+                      else if (*p == '(')
+                        in_parens++;
+
+                      /* check for end-of-token */
+                      if (
+                          (isspace(*p)) ||
+                          ((*delim) && (!isdelim(*p))) ||
+                          (isdelim(*p))
+                          )
+                        {
+                           in_tok = 0;
+                           tok_end = p - 1;
+                           if (*p == '\n') line--;
+                           goto done;
+                        }
+                   }
+              }
+         }
+       if (in_comment_sa)
+         {
+            if ((*p == '/') && (*(p - 1) == '*') && ((p - sa_start) > 2))
+              in_comment_sa = 0;
+         }
+       p++;
+     }
+   if (!in_tok) return NULL;
+   tok_end = p - 1;
+
+   done:
+   *new_p = p;
+
+   tok = mem_alloc(tok_end - tok_start + 2);
+   strncpy(tok, tok_start, tok_end - tok_start + 1);
+   tok[tok_end - tok_start + 1] = 0;
+
+   if (had_quote)
+     {
+       is_escaped = 0;
+       p = tok;
+
+       while (*p)
+         {
+            if ((*p == '\"') && (!is_escaped))
+              {
+                 memmove(p, p + 1, strlen(p));
+              }
+            else if ((*p == '\\') && (*(p + 1) == 'n'))
+              {
+                 memmove(p, p + 1, strlen(p));
+                 *p = '\n';
+              }
+            else if ((*p == '\\') && (*(p + 1) == 't'))
+              {
+                 memmove(p, p + 1, strlen(p));
+                 *p = '\t';
+              }
+            else if (*p == '\\')
+              {
+                 memmove(p, p + 1, strlen(p));
+                 if (*p == '\\') p++;
+                 else is_escaped = 1;
+              }
+            else
+              {
+                 if (is_escaped) is_escaped = 0;
+                 p++;
+              }
+         }
+     }
+   else if ((tok) && (*tok == '('))
+     {
+       char *tmp;
+       tmp = tok;
+       tok = perform_math(tok);
+       free(tmp);
+     }
+
+   return tok;
+}
+
+static char *
+stack_id(void)
+{
+   char *id;
+   int len;
+   Eina_List *l;
+   char *data;
+
+   len = 0;
+   EINA_LIST_FOREACH(stack, l, data)
+     len += strlen(data) + 1;
+   id = mem_alloc(len);
+   id[0] = 0;
+   EINA_LIST_FOREACH(stack, l, data)
+     {
+       strcat(id, data);
+       if (eina_list_next(l)) strcat(id, ".");
+     }
+   return id;
+}
+
+static void
+stack_chop_top(void)
+{
+   char *top;
+
+   /* remove top from stack */
+   top = eina_list_data_get(eina_list_last(stack));
+   if (top)
+     {
+       free(top);
+       stack = eina_list_remove(stack, top);
+     }
+   else
+     {
+       ERR("%s: Error. parse error %s:%i. } marker without matching { marker",
+           progname, file_in, line - 1);
+       exit(-1);
+     }
+}
+
+static void
+parse(char *data, off_t size)
+{
+   char *p, *end, *token;
+   int delim = 0;
+   int do_params = 0;
+
+   if (verbose)
+     {
+       INF("%s: Parsing input file",
+           progname);
+     }
+   p = data;
+   end = data + size;
+   line = 1;
+   while ((token = next_token(p, end, &p, &delim)) != NULL)
+     {
+       /* if we are in param mode, the only delimiter
+        * we'll accept is the semicolon
+        */
+       if (do_params && delim && *token != ';')
+         {
+            ERR("%s: Error. parse error %s:%i. %c marker before ; marker",
+                progname, file_in, line - 1, *token);
+            exit(-1);
+         }
+       else if (delim)
+         {
+            if (*token == ',' || *token == ':') do_params = 1;
+            else if (*token == '}')
+              {
+                 if (do_params)
+                   {
+                      ERR("%s: Error. parse error %s:%i. } marker before ; marker",
+                              progname, file_in, line - 1);
+                      exit(-1);
+                   }
+                 else
+                   stack_chop_top();
+              }
+            else if (*token == ';')
+              {
+                 if (do_params)
+                   {
+                      do_params = 0;
+                      new_statement();
+                      /* clear out params */
+                      while (params)
+                        {
+                           free(eina_list_data_get(params));
+                           params = eina_list_remove(params, eina_list_data_get(params));
+                        }
+                      /* remove top from stack */
+                      stack_chop_top();
+                   }
+              }
+            else if (*token == '{')
+              {
+                 if (do_params)
+                   {
+                      ERR("%s: Error. parse error %s:%i. { marker before ; marker",
+                          progname, file_in, line - 1);
+                      exit(-1);
+                   }
+              }
+            free(token);
+         }
+       else
+         {
+            if (do_params)
+              params = eina_list_append(params, token);
+            else
+              {
+                 stack = eina_list_append(stack, token);
+                 new_object();
+                 if ((verbatim == 1) && (p < (end - 2)))
+                   {
+                      int escaped = 0;
+                      int inquotes = 0;
+                      int insquotes = 0;
+                      int squigglie = 1;
+                      int l1 = 0, l2 = 0;
+                      char *verbatim_1;
+                      char *verbatim_2;
+
+                      l1 = line;
+                      while ((p[0] != '{') && (p < end))
+                        {
+                           if (*p == '\n') line++;
+                           p++;
+                        }
+                      p++;
+                      verbatim_1 = p;
+                      verbatim_2 = NULL;
+                      for (; p < end; p++)
+                        {
+                           if (*p == '\n') line++;
+                           if (escaped) escaped = 0;
+                           if (!escaped)
+                             {
+                                if (p[0] == '\\') escaped = 1;
+                                else if (p[0] == '\"')
+                                  {
+                                     if (!insquotes)
+                                       {
+                                          if (inquotes) inquotes = 0;
+                                          else inquotes = 1;
+                                       }
+                                  }
+                                else if (p[0] == '\'')
+                                  {
+                                     if (!inquotes)
+                                       {
+                                          if (insquotes) insquotes = 0;
+                                          else insquotes = 1;
+                                       }
+                                  }
+                                else if ((!inquotes) && (!insquotes))
+                                  {
+                                     if      (p[0] == '{') squigglie++;
+                                     else if (p[0] == '}') squigglie--;
+                                     if (squigglie == 0)
+                                       {
+                                          verbatim_2 = p - 1;
+                                          l2 = line;
+                                          break;
+                                       }
+                                  }
+                             }
+                        }
+                      if (verbatim_2 > verbatim_1)
+                        {
+                           int l;
+                           char *v;
+
+                           l = verbatim_2 - verbatim_1 + 1;
+                           v = malloc(l + 1);
+                           strncpy(v, verbatim_1, l);
+                           v[l] = 0;
+                           set_verbatim(v, l1, l2);
+                        }
+                      else
+                        {
+                           ERR("%s: Error. parse error %s:%i. { marker does not have matching } marker",
+                               progname, file_in, line - 1);
+                           exit(-1);
+                        }
+                      new_object();
+                      verbatim = 0;
+                   }
+              }
+         }
+     }
+   if (verbose)
+     {
+       INF("%s: Parsing done",
+              progname);
+     }
+}
+
+static char *clean_file = NULL;
+static void
+clean_tmp_file(void)
+{
+   if (clean_file) unlink(clean_file);
+}
+
+int
+is_verbatim(void)
+{
+   return verbatim;
+}
+
+void
+track_verbatim(int on)
+{
+   verbatim = on;
+}
+
+void
+set_verbatim(char *s, int l1, int l2)
+{
+   verbatim_line1 = l1;
+   verbatim_line2 = l2;
+   verbatim_str = s;
+}
+
+char *
+get_verbatim(void)
+{
+   return verbatim_str;
+}
+
+int
+get_verbatim_line1(void)
+{
+   return verbatim_line1;
+}
+
+int
+get_verbatim_line2(void)
+{
+   return verbatim_line2;
+}
+
+void
+compile(void)
+{
+   char buf[4096];
+   char inc[4096];
+   static char tmpn[4096];
+   int fd;
+   off_t size;
+   char *data, *p;
+
+   if (!tmp_dir)
+#ifdef HAVE_EVIL
+     tmp_dir = (char *)evil_tmpdir_get();
+#else
+     tmp_dir = "/tmp";
+#endif
+
+   strncpy(inc, file_in, 4000);
+   inc[4001] = 0;
+   p = strrchr(inc, '/');
+   if (!p) strcpy(inc, "./");
+   else *p = 0;
+   snprintf (tmpn, PATH_MAX, "%s/edje_cc.edc-tmp-XXXXXX", tmp_dir);
+   fd = mkstemp(tmpn);
+   if (fd >= 0)
+     {
+       int ret;
+       char *def;
+
+       clean_file = tmpn;
+       close(fd);
+       atexit(clean_tmp_file);
+       if (!defines)
+         def = mem_strdup("");
+       else
+         {
+            Eina_List *l;
+            int len;
+            char *data;
+
+            len = 0;
+            EINA_LIST_FOREACH(defines, l, data)
+              len += strlen(data) + 1;
+            def = mem_alloc(len + 1);
+            def[0] = 0;
+            EINA_LIST_FOREACH(defines, l, data)
+              {
+                 strcat(def, data);
+                 strcat(def, " ");
+              }
+         }
+
+       /*
+        * Run the input through the C pre-processor.
+        */
+
+       /*
+        * On OpenSolaris, the default cpp is located in different places.
+        * Alan Coppersmith told me to do what xorg does: using /usr/ccs/lib/cpp
+        *
+        * Also, that preprocessor is not managing C++ comments, so pass the
+        * sun cc preprocessor just after.
+        */
+        ret = -1;
+        if (ecore_file_exists("/usr/ccs/lib/cpp"))
+          {
+             snprintf(buf, sizeof(buf), "/usr/ccs/lib/cpp -I%s %s %s %s",
+                      inc, def, file_in, tmpn);
+             ret = system(buf);
+             if (ret == 0)
+               {
+                  static char tmpn2[4096];
+                  
+                  snprintf (tmpn2, PATH_MAX, "%s/edje_cc.edc-tmp-XXXXXX", tmp_dir);
+                  fd = mkstemp(tmpn2);
+                  if (fd >= 0)
+                    {
+                       close(fd); 
+                       snprintf (buf, 4096, "cc -E -I%s %s -o %s %s",
+                                 inc, def, tmpn2, tmpn);
+                       ret = system(buf);
+                       snprintf(tmpn, 4096, "%s", tmpn2);
+                    }
+               }
+          }
+       /*
+        * On some BSD based systems (MacOS, OpenBSD), the default cpp
+        * in the path is a wrapper script that chokes on the -o option.
+        * If the preprocessor is invoked via gcc -E, it will treat
+        * file_in as a linker file. The safest route seems to be to
+        * run cpp with the output as the second non-option argument.
+        *
+        * Redirecting the output is required for MacOS 10.3, and works fine
+        * on other systems.
+        *
+        * Also, the MacOS preprocessor is not managing C++ comments, so pass gcc
+        * preprocessor just after. Linux gcc seems to not like it, so guard the
+        * code so that it is compiled only on MacOS
+        *
+        */
+       if (ret != 0)
+         {
+            snprintf(buf, sizeof(buf), "cat %s | cpp -I%s %s > %s",
+                     file_in, inc, def, tmpn);
+            ret = system(buf);
+#if defined (__MacOSX__) || ( defined (__MACH__) && defined (__APPLE__))
+             if (ret == 0)
+               {
+                  static char tmpn2[4096];
+                  
+                  snprintf (tmpn2, PATH_MAX, "%s/edje_cc.edc-tmp-XXXXXX", tmp_dir);
+                  fd = mkstemp(tmpn2);
+                  if (fd >= 0)
+                    {
+                       close(fd); 
+                       snprintf (buf, 4096, "gcc -xc -I%s %s -E -o %s %s",
+                                 inc, def, tmpn2, tmpn);
+                       ret = system(buf);
+                       snprintf(tmpn, 4096, "%s", tmpn2);
+                    }
+               }
+#endif
+         }
+       if (ret != 0)
+         {
+            snprintf(buf, sizeof(buf), "gcc -I%s %s -E -o %s %s",
+                     inc, def, tmpn, file_in);
+            ret = system(buf);
+         }
+       if (ret == EXIT_SUCCESS)
+         file_in = tmpn;
+       free(def);
+/* OLD CODE
+       snprintf(buf, sizeof(buf), "cat %s | cpp -I%s %s -E -o %s",
+                file_in, inc, def, tmpn);
+       ret = system(buf);
+       if (ret < 0)
+         {
+            snprintf(buf, sizeof(buf), "gcc -I%s %s -E -o %s %s",
+                     inc, def, tmpn, file_in);
+            ret = system(buf);
+         }
+       if (ret >= 0) file_in = tmpn;
+       free(def);
+ */
+     }
+   fd = open(file_in, O_RDONLY | O_BINARY, S_IRUSR | S_IWUSR);
+   if (fd < 0)
+     {
+       ERR("%s: Error. cannot open file \"%s\" for input. %s",
+           progname, file_in, strerror(errno));
+       exit(-1);
+     }
+   if (verbose)
+     {
+       INF("%s: Opening \"%s\" for input",
+              progname, file_in);
+     }
+
+   size = lseek(fd, 0, SEEK_END);
+   lseek(fd, 0, SEEK_SET);
+   data = malloc(size);
+   if (data && (read(fd, data, size) == size))
+       parse(data, size);
+   else
+     {
+       ERR("%s: Error. cannot read file \"%s\". %s",
+           progname, file_in, strerror(errno));
+       exit(-1);
+     }
+   free(data);
+   close(fd);
+}
+
+int
+is_param(int n)
+{
+   char *str;
+
+   str = eina_list_nth(params, n);
+   if (str) return 1;
+   return 0;
+}
+
+int
+is_num(int n)
+{
+   char *str;
+   char *end;
+   long val;
+
+   str = eina_list_nth(params, n);
+   if (!str)
+     {
+       ERR("%s: Error. %s:%i no parameter supplied as argument %i",
+               progname, file_in, line - 1, n + 1);
+       exit(-1);
+     }
+   if (str[0] == 0) return 0;
+   end = str;
+   val = strtol(str, &end, 0);
+   if ((end != str) && (end[0] == 0)) return 1;
+   return 0;
+}
+
+char *
+parse_str(int n)
+{
+   char *str;
+   char *s;
+
+   str = eina_list_nth(params, n);
+   if (!str)
+     {
+       ERR("%s: Error. %s:%i no parameter supplied as argument %i",
+           progname, file_in, line - 1, n + 1);
+       exit(-1);
+     }
+   s = mem_strdup(str);
+   return s;
+}
+
+static int
+_parse_enum(char *str, va_list va)
+{
+   va_list va2;
+   va_copy(va2, va); /* iterator for the error message */
+
+   for (;;)
+     {
+       char *s;
+       int   v;
+
+       s = va_arg(va, char *);
+
+       /* End of the list, nothing matched. */
+       if (!s)
+         {
+            fprintf(stderr, "%s: Error. %s:%i token %s not one of:",
+                    progname, file_in, line - 1, str);
+            s = va_arg(va2, char *);
+            while (s)
+              {
+                 va_arg(va2, int);
+                 fprintf(stderr, " %s", s);
+                 s = va_arg(va2, char *);
+                 if (!s) break;
+              }
+            fprintf(stderr, "\n");
+            va_end(va2);
+            va_end(va);
+            exit(-1);
+         }
+
+       v = va_arg(va, int);
+       if (!strcmp(s, str))
+         {
+            va_end(va2);
+            va_end(va);
+            return v;
+         }
+     }
+   va_end(va2);
+   va_end(va);
+   return 0;
+}
+
+int
+parse_enum(int n, ...)
+{
+   char *str;
+   int result;
+   va_list va;
+
+   str = eina_list_nth(params, n);
+   if (!str)
+     {
+       ERR("%s: Error. %s:%i no parameter supplied as argument %i",
+               progname, file_in, line - 1, n + 1);
+       exit(-1);
+     }
+
+   va_start(va, n);
+   result = _parse_enum(str, va);
+   va_end(va);
+
+   return result;
+}
+
+int
+parse_flags(int n, ...)
+{
+   Eina_List *lst;
+   int result = 0;
+   va_list va;
+   char *data;
+
+   va_start(va, n);
+   EINA_LIST_FOREACH(eina_list_nth_list(params, n), lst, data)
+     result |= _parse_enum(data, va);
+   va_end(va);
+
+   return result;
+}
+
+int
+parse_int(int n)
+{
+   char *str;
+   int i;
+
+   str = eina_list_nth(params, n);
+   if (!str)
+     {
+       ERR("%s: Error. %s:%i no parameter supplied as argument %i",
+           progname, file_in, line - 1, n + 1);
+       exit(-1);
+     }
+   i = my_atoi(str);
+   return i;
+}
+
+int
+parse_int_range(int n, int f, int t)
+{
+   char *str;
+   int i;
+
+   str = eina_list_nth(params, n);
+   if (!str)
+     {
+       ERR("%s: Error. %s:%i no parameter supplied as argument %i",
+           progname, file_in, line - 1, n + 1);
+       exit(-1);
+     }
+   i = my_atoi(str);
+   if ((i < f) || (i > t))
+     {
+       ERR("%s: Error. %s:%i integer %i out of range of %i to %i inclusive",
+           progname, file_in, line - 1, i, f, t);
+       exit(-1);
+     }
+   return i;
+}
+
+int
+parse_bool(int n)
+{
+   char *str, buf[4096];
+   int i;
+
+   str = eina_list_nth(params, n);
+   if (!str)
+     {
+       ERR("%s: Error. %s:%i no parameter supplied as argument %i",
+           progname, file_in, line - 1, n + 1);
+       exit(-1);
+     }
+
+   if (!strstrip(str, buf, sizeof (buf)))
+     {
+       ERR("%s: Error. %s:%i expression is too long",
+           progname, file_in, line - 1);
+       return 0;
+     }
+
+   if (!strcasecmp(buf, "false") || !strcasecmp(buf, "off"))
+      return 0;
+   if (!strcasecmp(buf, "true") || !strcasecmp(buf, "on"))
+      return 1;
+
+   i = my_atoi(str);
+   if ((i < 0) || (i > 1))
+     {
+       ERR("%s: Error. %s:%i integer %i out of range of 0 to 1 inclusive",
+           progname, file_in, line - 1, i);
+       exit(-1);
+     }
+   return i;
+}
+
+double
+parse_float(int n)
+{
+   char *str;
+   double i;
+
+   str = eina_list_nth(params, n);
+   if (!str)
+     {
+       ERR("%s: Error. %s:%i no parameter supplied as argument %i",
+           progname, file_in, line - 1, n + 1);
+       exit(-1);
+     }
+   i = my_atof(str);
+   return i;
+}
+
+double
+parse_float_range(int n, double f, double t)
+{
+   char *str;
+   double i;
+
+   str = eina_list_nth(params, n);
+   if (!str)
+     {
+       ERR("%s: Error. %s:%i no parameter supplied as argument %i",
+           progname, file_in, line - 1, n + 1);
+       exit(-1);
+     }
+   i = my_atof(str);
+   if ((i < f) || (i > t))
+     {
+       ERR("%s: Error. %s:%i float %3.3f out of range of %3.3f to %3.3f inclusive",
+           progname, file_in, line - 1, i, f, t);
+       exit(-1);
+     }
+   return i;
+}
+
+void
+check_arg_count(int required_args)
+{
+   int num_args = eina_list_count (params);
+
+   if (num_args != required_args)
+     {
+       ERR("%s: Error. %s:%i got %i arguments, but expected %i",
+          progname, file_in, line - 1, num_args, required_args);
+       exit(-1);
+     }
+}
+
+void
+check_min_arg_count(int min_required_args)
+{
+   int num_args = eina_list_count (params);
+
+   if (num_args < min_required_args)
+     {
+       ERR("%s: Error. %s:%i got %i arguments, "
+               "but expected at least %i",
+           progname, file_in, line - 1, num_args, min_required_args);
+       exit(-1);
+     }
+}
+
+/* simple expression parsing stuff */
+
+/*
+ * alpha ::= beta + beta || beta
+ * beta  ::= gamma + gamma || gamma
+ * gamma ::= num || delta
+ * delta ::= '(' alpha ')'
+ *
+ */
+
+/* int set of function */
+
+static int
+my_atoi(const char *s)
+{
+   int res = 0;
+   char buf[4096];
+   
+   if (!s) return 0;
+   if (!strstrip(s, buf, sizeof(buf)))
+     {
+       ERR("%s: Error. %s:%i expression is too long\n",
+           progname, file_in, line - 1);
+       return 0;
+     }
+   _alphai(buf, &res);
+   return res;
+}
+
+static char *
+_deltai(char *s, int *val)
+{
+   if (!val) return NULL;
+   if ('(' != s[0])
+     {
+       ERR("%s: Error. %s:%i unexpected character at %s\n",
+           progname, file_in, line - 1, s);
+       return s;
+     }
+   else
+     {
+       s++;
+       s = _alphai(s, val);
+       s++;
+       return s;
+     }
+   return s;
+}
+
+static char *
+_funci(char *s, int *val)
+{
+   if (!strncmp(s, "floor(", 6))
+     {
+        s += 5;
+        s = _deltai(s, val);
+        *val = *val;
+     }
+   else if (!strncmp(s, "ceil(", 5))
+     {
+        s += 4;
+        s = _deltai(s, val);
+        *val = *val;
+     }
+   else
+     {
+        ERR("%s: Error. %s:%i unexpected character at %s\n",
+           progname, file_in, line - 1, s);
+     }
+   return s;
+}
+
+static char *
+_gammai(char *s, int *val)
+{
+   if (!val) return NULL;
+   if (_is_numi(s[0]))
+     {
+       s = _get_numi(s, val);
+       return s;
+     }
+   else if ('(' == s[0])
+     {
+       s = _deltai(s, val);
+       return s;
+     }
+   else
+     {
+        s = _funci(s, val);
+//        ERR("%s: Error. %s:%i unexpected character at %s\n",
+//                progname, file_in, line - 1, s);
+     }
+   return s;
+}
+
+static char *
+_betai(char *s, int *val)
+{
+   int a1, a2;
+   char op;
+
+   if (!val) return NULL;
+   s = _gammai(s, &a1);
+   while (_is_op1i(s[0]))
+     {
+       op = s[0];
+       s++;
+       s = _gammai(s, &a2);
+       a1 = _calci(op, a1, a2);
+     }
+   (*val) = a1;
+   return s;
+}
+
+static char *
+_alphai(char *s, int *val)
+{
+   int a1, a2;
+   char op;
+   
+   if (!val) return NULL;
+   s = _betai(s, &a1);
+   while (_is_op2i(s[0]))
+     {
+       op = s[0];
+       s++;
+       s = _betai(s, &a2);
+       a1 = _calci(op, a1, a2);
+     }
+   (*val) = a1;
+   return s;
+}
+
+char *
+_get_numi(char *s, int *val)
+{
+   char buf[4096];
+   int pos = 0;
+   
+   if (!val) return s;
+   while ((('0' <= s[pos]) && ('9' >= s[pos])) ||
+         ((0 == pos) && ('-' == s[pos])))
+     {
+       buf[pos] = s[pos];
+       pos++;
+     }
+   buf[pos] = '\0';
+   (*val) = atoi(buf);
+   return (s + pos);
+}
+
+int
+_is_numi(char c)
+{
+   if (((c >= '0') && (c <= '9')) || ('-' == c) || ('+' == c))
+     return 1;
+   else
+     return 0;
+}
+
+int
+_is_op1i(char c)
+{
+   switch(c)
+     {
+     case '*':;
+     case '%':;
+     case '/': return 1;
+     default: return 0;
+     }
+   return 0;
+}
+
+int
+_is_op2i(char c)
+{
+   switch(c)
+     {
+     case '+':;
+     case '-': return 1;
+     default: return 0;
+     }
+   return 0;
+}
+
+int
+_calci(char op, int a, int b)
+{
+   switch(op)
+     {
+     case '+':
+       a += b;
+       return a;
+     case '-':
+       a -= b;
+       return a;
+     case '/':
+       if (0 != b) a /= b;
+       else
+         ERR("%s: Error. %s:%i divide by zero\n",
+             progname, file_in, line - 1);
+       return a;
+     case '*':
+       a *= b;
+       return a;
+     case '%':
+       if (0 != b) a = a % b;
+       else
+         ERR("%s: Error. %s:%i modula by zero\n",
+             progname, file_in, line - 1);
+       return a;
+     default:
+       ERR("%s: Error. %s:%i unexpected character '%c'\n",
+           progname, file_in, line - 1, op);
+       return a;
+     }
+}
+
+/* float set of functoins */
+
+double
+my_atof(const char *s)
+{
+   double res = 0;
+   char buf[4096];
+   
+   if (!s) return 0;
+
+   if (!strstrip(s, buf, sizeof (buf)))
+     {
+       ERR("%s: Error. %s:%i expression is too long",
+           progname, file_in, line - 1);
+       return 0;
+     }
+   _alphaf(buf, &res);
+   return res;
+}
+
+static char *
+_deltaf(char *s, double *val)
+{
+   if (!val) return NULL;
+   if ('(' != s[0])
+     {
+       ERR("%s: Error. %s:%i unexpected character at %s",
+           progname, file_in, line - 1, s);
+       return s;
+     }
+   else
+     {
+       s++;
+       s = _alphaf(s, val);
+       s++;
+       return s;
+     }
+   return s;
+}
+
+static char *
+_funcf(char *s, double *val)
+{
+   if (!strncmp(s, "floor(", 6))
+     {
+        s += 5;
+        s = _deltaf(s, val);
+        *val = floor(*val);
+     }
+   else if (!strncmp(s, "ceil(", 5))
+     {
+        s += 4;
+        s = _deltaf(s, val);
+        *val = ceil(*val);
+     }
+   else
+     {
+        ERR("%s: Error. %s:%i unexpected character at %s\n",
+           progname, file_in, line - 1, s);
+     }
+   return s;
+}
+
+static char *
+_gammaf(char *s, double *val)
+{
+   if (!val) return NULL;
+   
+   if (_is_numf(s[0]))
+     {
+       s = _get_numf(s, val);
+       return s;
+     }
+   else if ('(' == s[0])
+     {
+       s = _deltaf(s, val);
+       return s;
+     }
+   else
+     {
+        s = _funcf(s, val);
+//        ERR("%s: Error. %s:%i unexpected character at %s\n",
+//                progname, file_in, line - 1, s);
+     }
+   return s;
+}
+
+static char *
+_betaf(char *s, double *val)
+{
+   double a1=0, a2=0;
+   char op;
+   
+   if (!val) return NULL;
+   s = _gammaf(s, &a1);
+   while (_is_op1f(s[0]))
+     {
+       op = s[0];
+       s++;
+       s = _gammaf(s, &a2);
+       a1 = _calcf(op, a1, a2);
+     }
+   (*val) = a1;
+   return s;
+}
+
+static char *
+_alphaf(char *s, double *val)
+{
+   double a1=0, a2=0;
+   char op;
+
+   if (!val) return NULL;
+   s = _betaf(s, &a1);
+   while (_is_op2f(s[0]))
+     {
+       op = s[0];
+       s++;
+       s = _betaf(s, &a2);
+       a1 = _calcf(op, a1, a2);
+     }
+   (*val) = a1;
+   return s;
+}
+
+static char *
+_get_numf(char *s, double *val)
+{
+   char buf[4096];
+   int pos = 0;
+
+   if (!val) return s;
+
+   while ((('0' <= s[pos]) && ('9' >= s[pos])) ||
+         ('.' == s[pos]) ||
+         ((0 == pos) && ('-' == s[pos])))
+     {
+       buf[pos] = s[pos];
+       pos++;
+     }
+   buf[pos] = '\0';
+   (*val) = atof(buf);
+   return (s+pos);
+}
+
+static int
+_is_numf(char c)
+{
+   if (((c >= '0') && (c <= '9'))
+       || ('-' == c)
+       || ('.' == c)
+       || ('+' == c))
+     return 1;
+   else
+     return 0;
+}
+
+static int
+_is_op1f(char c)
+{
+   switch(c)
+     {
+     case '*':;
+     case '%':;
+     case '/': return 1;
+     default: return 0;
+     }
+   return 0;
+}
+
+static int
+_is_op2f(char c)
+{
+   switch(c)
+     {
+     case '+':;
+     case '-': return 1;
+     default: return 0;
+     }
+   return 0;
+}
+
+static double
+_calcf(char op, double a, double b)
+{
+   switch(op)
+     {
+     case '+':
+       a += b;
+       return a;
+     case '-':
+       a -= b;
+       return a;
+     case '/':
+       if (b != 0) a /= b;
+       else
+         ERR("%s: Error. %s:%i divide by zero\n",
+             progname, file_in, line - 1);
+       return a;
+     case '*':
+       a *= b;
+       return a;
+     case '%':
+       if (0 != b) a = (double)((int)a % (int)b);
+       else
+         ERR("%s: Error. %s:%i modula by zero\n",
+             progname, file_in, line - 1);
+       return a;
+     default:
+       ERR("%s: Error. %s:%i unexpected character '%c'\n",
+           progname, file_in, line - 1, op);
+       return a;
+     }
+}
+
+static int
+strstrip(const char *in, char *out, size_t size)
+{
+   if ((size -1 ) < strlen(in))
+     {
+       ERR("%s: Error. %s:%i expression is too long",
+               progname, file_in, line - 1);
+       return 0;
+     }
+   /* remove spaces and tabs */
+   while (*in)
+     {
+       if ((0x20 != *in) && (0x09 != *in))
+         {
+            *out = *in;
+            out++;
+         }
+       in++;
+     }
+   *out = '\0';
+   return 1;
+}
diff --git a/src/bin/edje_cc_sources.c b/src/bin/edje_cc_sources.c
new file mode 100644 (file)
index 0000000..ba88bc9
--- /dev/null
@@ -0,0 +1,263 @@
+/*
+ * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <string.h>
+#include <ctype.h>
+#include <limits.h>
+
+#include "edje_cc.h"
+
+static Eet_Data_Descriptor *_srcfile_edd = NULL;
+static Eet_Data_Descriptor *_srcfile_list_edd = NULL;
+
+static Eet_Data_Descriptor *_external_edd = NULL;
+static Eet_Data_Descriptor *_external_list_edd = NULL;
+
+static Eet_Data_Descriptor *_font_edd = NULL;
+static Eet_Data_Descriptor *_font_list_edd = NULL;
+
+static SrcFile_List srcfiles = {NULL};
+
+void
+source_edd(void)
+{
+   Eet_Data_Descriptor_Class eddc;
+
+   eet_eina_stream_data_descriptor_class_set(&eddc, "srcfile", sizeof (SrcFile));
+   _srcfile_edd = eet_data_descriptor_stream_new(&eddc);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_srcfile_edd, SrcFile, "name", name, EET_T_INLINED_STRING);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_srcfile_edd, SrcFile, "file", file, EET_T_INLINED_STRING);
+
+   eet_eina_stream_data_descriptor_class_set(&eddc, "srcfile_list", sizeof (SrcFile_List));
+   _srcfile_list_edd = eet_data_descriptor_stream_new(&eddc);
+   EET_DATA_DESCRIPTOR_ADD_LIST(_srcfile_list_edd, SrcFile_List, "list", list, _srcfile_edd);
+
+   eet_eina_stream_data_descriptor_class_set(&eddc, "external", sizeof (External));
+   _external_edd = eet_data_descriptor_stream_new(&eddc);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_external_edd, External, "name", name, EET_T_INLINED_STRING);
+
+   eet_eina_stream_data_descriptor_class_set(&eddc, "external_list", sizeof (External_List));
+   _external_list_edd = eet_data_descriptor_stream_new(&eddc);
+   EET_DATA_DESCRIPTOR_ADD_LIST(_external_list_edd, External_List, "list", list, _external_edd);
+
+   eet_eina_stream_data_descriptor_class_set(&eddc, "font", sizeof (Font));
+   _font_edd = eet_data_descriptor_stream_new(&eddc);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_font_edd, Font, "file", file, EET_T_INLINED_STRING);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_font_edd, Font, "name", name, EET_T_INLINED_STRING);
+
+   eet_eina_stream_data_descriptor_class_set(&eddc, "font_list", sizeof (Font_List));
+   _font_list_edd = eet_data_descriptor_stream_new(&eddc);
+   EET_DATA_DESCRIPTOR_ADD_LIST(_font_list_edd, Font_List, "list", list, _font_edd);
+}
+
+static void source_fetch_file(const char *fil, const char *filname);
+
+static void
+source_fetch_file(const char *fil, const char *filname)
+{
+   FILE *f;
+   char buf[16 * 1024], *dir = NULL;
+   long sz;
+   size_t tmp;
+   ssize_t dir_len = 0;
+   SrcFile *sf;
+
+   f = fopen(fil, "rb");
+   if (!f)
+     {
+       ERR("%s: Warning. Cannot open file '%s'",
+           progname, fil);
+       exit(-1);
+     }
+
+   fseek(f, 0, SEEK_END);
+   sz = ftell(f);
+   fseek(f, 0, SEEK_SET);
+   sf = mem_alloc(SZ(SrcFile));
+   sf->name = mem_strdup(filname);
+   sf->file = mem_alloc(sz + 1);
+   if (sz > 0)
+     {
+       tmp = fread(sf->file, sz, 1, f);
+       if (tmp != 1)
+         {
+            ERR("%s: Warning file length for (%s) doesn't match !",
+                    progname, filname);
+            exit(-1);
+         }
+     }
+
+   sf->file[sz] = '\0';
+   fseek(f, 0, SEEK_SET);
+   srcfiles.list = eina_list_append(srcfiles.list, sf);
+
+   while (fgets(buf, sizeof(buf), f))
+     {
+       char *p, *pp;
+       int got_hash = 0;
+       int forgetit = 0;
+       int haveinclude = 0;
+       char *file = NULL, *fname = NULL;
+
+       p = buf;
+       while ((!forgetit) && (*p))
+         {
+            if (!got_hash)
+              {
+                 if (!isspace(*p))
+                   {
+                      if (*p == '#')
+                        got_hash = 1;
+                      else
+                        forgetit = 1;
+                   }
+                 p++;
+              }
+
+            if (!haveinclude)
+              {
+                 if (!isspace(*p))
+                   {
+                      if (!strncmp(p, "include", 7))
+                        {
+                           haveinclude = 1;
+                           p += 7;
+                        }
+                      /* HACK! the logic above should be fixed so
+                       * preprocessor statements don't have to begin
+                       * in column 0.
+                       * otoh, edje_cc should print a warning in that case,
+                       * since according to the standard, preprocessor
+                       * statements need to be put in column 0.
+                       */
+                      else if (!strncmp(p, "#include", 8))
+                        {
+                           haveinclude = 1;
+                           p += 8;
+                        }
+                      else
+                        forgetit = 1;
+                   }
+              }
+            else
+              {
+                 if (!isspace(*p))
+                   {
+                      char end = '\0';
+
+                      if (*p == '"') end = '"';
+                      else if (*p == '<') end = '>';
+
+                      if (end)
+                        {
+                           pp = strchr(p + 1, end);
+                           if (!pp)
+                             forgetit = 1;
+                           else
+                             {
+                                char *slash;
+                                ssize_t l = 0;
+
+                                /* get the directory of the current file
+                                 * if we haven't already done so
+                                 */
+                                if ((!dir) && (strrchr(fil, '/')))
+                                  {
+                                     dir = mem_strdup(fil);
+                                     slash = strrchr(dir, '/');
+                                     *slash = '\0';
+                                     dir_len = strlen(dir);
+                                  }
+
+                                l = pp - p + dir_len + 1;
+                                file = mem_alloc(l);
+
+                                if (!dir_len)
+                                  {
+                                     snprintf(file, l - 1, "%s", p + 1);
+                                     file[l - 2] = 0;
+                                  }
+                                else
+                                  {
+                                     snprintf(file, l, "%s/%s", dir, p + 1);
+                                     file[l - 1] = 0;
+                                  }
+
+
+                                fname = strdup(p + 1);
+                                pp = strrchr(fname, end);
+                                if (pp) *pp = 0;
+                                forgetit = 1;
+                             }
+                        }
+                      else
+                        forgetit = 1;
+                   }
+                 else
+                   p++;
+              }
+
+            got_hash = 0;
+         }
+       if ((file) && (fname))
+         {
+            source_fetch_file(file, fname);
+            free(file);
+            free(fname);
+         }
+     }
+   free(dir);
+   fclose(f);
+}
+
+void
+source_fetch(void)
+{
+   char buf[PATH_MAX] = {0}, *ptr;
+
+   ptr = strrchr(file_in, '/');
+   if (ptr)
+     {
+       snprintf(buf, sizeof (buf), "%s", ptr + 1);
+     }
+
+   source_fetch_file(file_in, buf[0] ? buf : file_in);
+}
+
+int
+source_append(Eet_File *ef)
+{
+   return eet_data_write(ef, _srcfile_list_edd, "edje_sources", &srcfiles, 1);
+}
+
+SrcFile_List *
+source_load(Eet_File *ef)
+{
+   SrcFile_List *s;
+
+   s = eet_data_read(ef, _srcfile_list_edd, "edje_sources");
+   return s;
+}
+
+int
+source_fontmap_save(Eet_File *ef, Eina_List *fonts)
+{
+   Font_List fl;
+
+   fl.list = fonts;
+   return eet_data_write(ef, _font_list_edd, "edje_source_fontmap", &fl, 1);
+}
+
+Font_List *
+source_fontmap_load(Eet_File *ef)
+{
+   Font_List *fl;
+
+   fl = eet_data_read(ef, _font_list_edd, "edje_source_fontmap");
+   return fl;
+}
diff --git a/src/bin/edje_decc.c b/src/bin/edje_decc.c
new file mode 100644 (file)
index 0000000..7a1f7a8
--- /dev/null
@@ -0,0 +1,404 @@
+/*
+ * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
+ */
+
+/* ugly ugly. avert your eyes. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <locale.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+
+
+#include <Ecore_File.h>
+#include <Ecore_Evas.h>
+
+#include "edje_decc.h"
+
+int _edje_cc_log_dom = -1;
+char *progname = NULL;
+char *file_in = NULL;
+char *file_out = NULL;
+
+Edje_File *edje_file = NULL;
+SrcFile_List *srcfiles = NULL;
+Font_List *fontlist = NULL;
+
+int line = 0;
+int build_sh = 1;
+int new_dir = 1;
+
+int        decomp(void);
+void       output(void);
+static int compiler_cmd_is_sane();
+static int root_filename_is_sane();
+
+static void
+main_help(void)
+{
+   printf
+     ("Usage:\n"
+      "\t%s input_file.edj [-main-out file.edc] [-no-build-sh] [-current-dir]\n"
+      "\n"
+      ,progname);
+}
+
+Eet_File *ef;
+Eet_Dictionary *ed;
+
+int
+main(int argc, char **argv)
+{
+   int i;
+
+   setlocale(LC_NUMERIC, "C");
+   if (!eina_init())
+     exit(-1);
+   _edje_cc_log_dom = eina_log_domain_register("edje_decc", EDJE_CC_DEFAULT_LOG_COLOR);
+   if(_edje_cc_log_dom < 0)
+     {
+       EINA_LOG_ERR("Edje_decc: Impossible to create a log domain for edje_decc");
+       eina_shutdown();
+       exit(-1);
+     }
+   eina_log_level_set(EINA_LOG_LEVEL_INFO);
+   progname = argv[0];
+   for (i = 1; i < argc; i++)
+     {
+       if (!file_in)
+         file_in = argv[i];
+       else if ((!strcmp(argv[i], "-main-out")) && (i < (argc - 1)))
+         {
+            i++;
+            file_out = argv[i];
+         }
+       else if (!strcmp(argv[i], "-no-build-sh"))
+         build_sh = 0;
+       else if (!strcmp(argv[i], "-current-dir"))
+         new_dir = 0;
+     }
+   if (!file_in)
+     {
+       ERR("%s: Error: no input file specified.", progname);
+       main_help();
+       exit(-1);
+     }
+
+   if (!edje_init())
+     exit(-1);
+   source_edd();
+
+   if (!decomp()) return -1;
+   output();
+
+   eet_close(ef);
+   edje_shutdown();
+   eina_log_domain_unregister(_edje_cc_log_dom);
+   _edje_cc_log_dom = -1;
+   eina_shutdown();
+   return 0;
+}
+
+int
+decomp(void)
+{
+   ef = eet_open(file_in, EET_FILE_MODE_READ);
+   if (!ef)
+     {
+       ERR("ERROR: cannot open %s", file_in);
+       return 0;
+     }
+
+   srcfiles = source_load(ef);
+   if (!srcfiles || !srcfiles->list)
+     {
+       ERR("ERROR: %s has no decompile information", file_in);
+       eet_close(ef);
+       return 0;
+     }
+   if (!eina_list_data_get(srcfiles->list) || !root_filename_is_sane())
+     {
+        ERR("ERROR: Invalid root filename: '%s'", (char *) eina_list_data_get(srcfiles->list));
+       eet_close(ef);
+       return 0;
+     }
+   edje_file = eet_data_read(ef, _edje_edd_edje_file, "edje_file");
+   if (!edje_file)
+     {
+        ERR("ERROR: %s does not appear to be an edje file", file_in);
+       eet_close(ef);
+       return 0;
+     }
+   if (!edje_file->compiler)
+     {
+       edje_file->compiler = strdup("edje_cc");
+     }
+   else if (!compiler_cmd_is_sane())
+     {
+       ERR("ERROR: invalid compiler executable: '%s'", edje_file->compiler);
+       eet_close(ef);
+       return 0;
+     }
+   fontlist = source_fontmap_load(ef);
+   return 1;
+}
+
+void
+output(void)
+{
+   Eina_List *l;
+   Eet_File *ef;
+   SrcFile *sf;
+   char *outdir, *p;
+
+   if (!new_dir)
+     outdir = strdup(".");
+   else
+     {
+       p = strrchr(file_in, '/');
+       if (p)
+         outdir = strdup(p + 1);
+       else
+         outdir = strdup(file_in);
+       p = strrchr(outdir, '.');
+       if (p) *p = 0;
+       ecore_file_mkpath(outdir);
+     }
+
+
+   ef = eet_open(file_in, EET_FILE_MODE_READ);
+
+   if (edje_file->image_dir)
+     {
+        Edje_Image_Directory_Entry *ei;
+
+       EINA_LIST_FOREACH(edje_file->image_dir->entries, l, ei)
+         {
+            if ((ei->source_type > EDJE_IMAGE_SOURCE_TYPE_NONE) &&
+                (ei->source_type < EDJE_IMAGE_SOURCE_TYPE_LAST) &&
+                (ei->source_type != EDJE_IMAGE_SOURCE_TYPE_EXTERNAL) &&
+                (ei->entry))
+              {
+                 Ecore_Evas *ee;
+                 Evas *evas;
+                 Evas_Object *im;
+                 char buf[4096];
+                 char out[4096];
+                 char *pp;
+
+                 ecore_init();
+                 ecore_evas_init();
+                 ee = ecore_evas_buffer_new(1, 1);
+                 if (!ee)
+                   {
+                      ERR("Cannot create buffer engine canvas for image save.");
+                      exit(-1);
+                   }
+                 evas = ecore_evas_get(ee);
+                 im = evas_object_image_add(evas);
+                 if (!im)
+                   {
+                      ERR("Cannot create image object for save.");
+                      exit(-1);
+                   }
+                 snprintf(buf, sizeof(buf), "images/%i", ei->id);
+                 evas_object_image_file_set(im, file_in, buf);
+                 snprintf(out, sizeof(out), "%s/%s", outdir, ei->entry);
+                 printf("Output Image: %s\n", out);
+                 pp = strdup(out);
+                 p = strrchr(pp, '/');
+                 *p = 0;
+                 if (strstr(pp, "../"))
+                   {
+                      ERR("Potential security violation. attempt to write in parent dir.");
+                      exit(-1);
+                   }
+                 ecore_file_mkpath(pp);
+                 free(pp);
+                 if (!evas_object_image_save(im, out, NULL, "quality=100 compress=9"))
+                   {
+                      ERR("Cannot write file %s. Perhaps missing JPEG or PNG saver modules for Evas.", out);
+                      exit(-1);
+                   }
+                 evas_object_del(im);
+                 ecore_evas_free(ee);
+                 ecore_evas_shutdown();
+                 ecore_shutdown();
+              }
+         }
+     }
+
+   EINA_LIST_FOREACH(srcfiles->list, l, sf)
+     {
+       char out[4096];
+       FILE *f;
+       char *pp;
+
+       snprintf(out, sizeof(out), "%s/%s", outdir, sf->name);
+       INF("Output Source File: %s\n", out);
+       pp = strdup(out);
+       p = strrchr(pp, '/');
+       *p = 0;
+       if (strstr(pp, "../"))
+         {
+            ERR("Potential security violation. attempt to write in parent dir.");
+            exit (-1);
+         }
+       ecore_file_mkpath(pp);
+       free(pp);
+       if (strstr(out, "../"))
+         {
+            ERR("Potential security violation. attempt to write in parent dir.");
+            exit (-1);
+         }
+       f = fopen(out, "wb");
+       if (!f)
+         {
+            ERR("Unable to write file (%s).", out);
+            exit (-1);
+         }
+
+       /* if the file is empty, sf->file will be NULL.
+        * note that that's not an error
+        */
+       if (sf->file) fputs(sf->file, f);
+       fclose(f);
+     }
+   if (fontlist)
+     {
+        Font *fn;
+
+       EINA_LIST_FOREACH(fontlist->list, l, fn)
+         {
+            void *font;
+            int fontsize;
+            char out[4096];
+
+            snprintf(out, sizeof(out), "fonts/%s", fn->name);
+            font = eet_read(ef, out, &fontsize);
+            if (font)
+              {
+                 FILE *f;
+                 char *pp;
+
+                 snprintf(out, sizeof(out), "%s/%s", outdir, fn->file);
+                 INF("Output Font: %s", out);
+                 pp = strdup(out);
+                 p = strrchr(pp, '/');
+                 *p = 0;
+                 if (strstr(pp, "../"))
+                   {
+                      ERR("Potential security violation. attempt to write in parent dir.");
+                      exit (-1);
+                   }
+                 ecore_file_mkpath(pp);
+                 free(pp);
+                 if (strstr(out, "../"))
+                   {
+                      ERR("Potential security violation. attempt to write in parent dir.");
+                      exit (-1);
+                   }
+                 f = fopen(out, "wb");
+                 if (fwrite(font, fontsize, 1, f) != 1)
+                   ERR("Could not write font: %s", strerror(errno));
+                 fclose(f);
+                 free(font);
+              }
+         }
+     }
+     {
+       char out[4096];
+       FILE *f;
+       SrcFile *sf = eina_list_data_get(srcfiles->list);
+
+
+       if (build_sh)
+         {
+            snprintf(out, sizeof(out), "%s/build.sh", outdir);
+            printf("Output Build Script: %s\n", out);
+            if (strstr(out, "../"))
+              {
+                 ERR("potential security violation. attempt to write in parent dir.\n");
+                 exit (-1);
+              }
+            f = fopen(out, "wb");
+            fprintf(f, "#!/bin/sh\n");
+            fprintf(f, "%s $@ -id . -fd . %s -o %s.edj\n", edje_file->compiler, sf->name, outdir);
+            fclose(f);
+
+            WRN("\n*** CAUTION ***\n"
+                "Please check the build script for anything malicious "
+                "before running it!\n\n");
+         }
+
+       if (file_out)
+         {
+            snprintf(out, sizeof(out), "%s/%s", outdir, file_out);
+            if (symlink(sf->name, out) != 0)
+               {
+                  ERR("symlink %s -> %s failed\n", sf->name, out);
+               }
+         }
+
+       chmod(out, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP);
+
+     }
+   eet_close(ef);
+}
+
+static int
+compiler_cmd_is_sane()
+{
+   char *c = edje_file->compiler, *ptr;
+
+   if (!c || !*c)
+     {
+       return 0;
+     }
+
+   for (ptr = c; ptr && *ptr; ptr++)
+     {
+       /* only allow [a-z][A-Z][0-9]_- */
+       if (!isalnum(*ptr) && *ptr != '_' && *ptr != '-')
+         {
+            return 0;
+         }
+     }
+
+   return 1;
+}
+
+static int
+root_filename_is_sane()
+{
+   SrcFile *sf = eina_list_data_get(srcfiles->list);
+   char *f = sf->name, *ptr;
+
+   if (!f || !*f)
+     {
+       return 0;
+     }
+
+   for (ptr = f; ptr && *ptr; ptr++)
+     {
+       /* only allow [a-z][A-Z][0-9]_-./ */
+       switch (*ptr)
+         {
+          case '_': case '-':  case '.': case '/':
+             break;
+          default:
+             if (!isalnum(*ptr))
+               {
+                  return 0;
+               }
+         }
+     }
+   return 1;
+}
diff --git a/src/bin/edje_decc.h b/src/bin/edje_decc.h
new file mode 100644 (file)
index 0000000..43e988d
--- /dev/null
@@ -0,0 +1,61 @@
+#ifndef EDJE_DECC_H
+#define EDJE_DECC_H
+
+#include <edje_private.h>
+
+/* logging variables */
+extern int _edje_cc_log_dom ;
+#define EDJE_CC_DEFAULT_LOG_COLOR EINA_COLOR_CYAN
+#ifdef ERR
+# undef ERR
+#endif
+#define ERR(...) EINA_LOG_DOM_ERR(_edje_cc_log_dom, __VA_ARGS__)
+#ifdef INF
+# undef INF
+#endif
+#define INF(...) EINA_LOG_DOM_INFO(_edje_cc_log_dom, __VA_ARGS__)
+#ifdef WRN
+# undef WRN
+#endif
+#define WRN(...) EINA_LOG_DOM_WARN(_edje_cc_log_dom, __VA_ARGS__)
+
+/* types */
+typedef struct _Font                  Font;
+typedef struct _Font_List             Font_List;
+typedef struct _SrcFile               SrcFile;
+typedef struct _SrcFile_List          SrcFile_List;
+
+struct _Font
+{
+   char *file;
+   char *name;
+};
+
+struct _Font_List
+{
+   Eina_List *list;
+};
+
+struct _SrcFile
+{
+   char *name;
+   char *file;
+};
+
+struct _SrcFile_List
+{
+   Eina_List *list;
+};
+
+void    source_edd(void);
+void    source_fetch(void);
+int     source_append(Eet_File *ef);
+SrcFile_List *source_load(Eet_File *ef);
+int     source_fontmap_save(Eet_File *ef, Eina_List *fonts);
+Font_List *source_fontmap_load(Eet_File *ef);
+
+void   *mem_alloc(size_t size);
+char   *mem_strdup(const char *s);
+#define SZ sizeof
+
+#endif
diff --git a/src/bin/edje_player.c b/src/bin/edje_player.c
new file mode 100644 (file)
index 0000000..8ff86ab
--- /dev/null
@@ -0,0 +1,730 @@
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <Edje.h>
+#include <Ecore_Evas.h>
+#include <Ecore.h>
+#include <Ecore_Getopt.h>
+#include <Evas.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <ctype.h>
+
+struct opts {
+   char *file;
+   char *group;
+   Eina_Bool list_groups;
+   char *engine;
+   Eina_Rectangle size;
+   unsigned char color[3];
+   Eina_Bool borderless;
+   Eina_Bool sticky;
+   Eina_Bool shaped;
+   Eina_Bool alpha;
+   Eina_Bool print;
+   Eina_Bool slave_mode;
+   char *title;
+};
+
+static char *
+_slave_mode_tok(char **p_arg)
+{
+   char *s, *e;
+   Eina_Bool is_quoted;
+
+   if (!*p_arg) return NULL;
+
+   s = *p_arg;
+   while (isspace(*s))
+     s++;
+
+   if (*s == '\0')
+     {
+       *p_arg = NULL;
+       return NULL;
+     }
+   else if (*s == '"')
+     {
+       is_quoted = EINA_TRUE;
+       s++;
+       *p_arg = s;
+     }
+   else
+     {
+       is_quoted = EINA_FALSE;
+       *p_arg = s;
+     }
+
+   for (e = s; *e != '\0'; e++)
+     {
+       if ((!is_quoted) && (isspace(*e)))
+         break;
+       else if ((is_quoted) && (*e == '"'))
+         break;
+     }
+
+   if (*e == '\0') return NULL;
+
+   *e = '\0';
+   return e + 1;
+}
+
+static void
+_slave_mode_signal(Evas_Object *edje, char *args)
+{
+   char *emission, *source;
+
+   emission = args;
+   source = _slave_mode_tok(&emission);
+   _slave_mode_tok(&source);
+
+   if ((!emission) || (!source))
+     {
+       fputs("ERROR: Invalid command arguments.\n", stderr);
+       return;
+     }
+
+   edje_object_signal_emit(edje, emission, source);
+}
+
+static void
+_slave_mode_info(Evas_Object *edje, char *args)
+{
+   _slave_mode_tok(&args);
+
+   if (!args)
+     {
+       fputs("ERROR: Invalid command arguments.\n", stderr);
+       return;
+     }
+
+   if (!edje_object_part_exists(edje, args))
+     {
+       printf("INFO: \"%s\" does not exist.\n", args);
+     }
+   else
+     {
+       Evas_Coord x, y, w, h;
+       edje_object_part_geometry_get(edje, args, &x, &y, &w, &h);
+       printf("INFO: \"%s\" %d,%d,%d,%d\n", args, x, y, w, h);
+     }
+}
+
+static void
+_slave_mode_quit(Evas_Object *edje __UNUSED__, char *args __UNUSED__)
+{
+   puts("Bye!");
+   ecore_main_loop_quit();
+}
+
+static void
+_slave_mode_help(Evas_Object *edje __UNUSED__, char *args __UNUSED__)
+{
+   puts("Help:\n"
+       "One command per line, arguments separated by space. Strings may have "
+       "spaces if enclosed in quotes (\").\n"
+       "\n"
+       "\t<command> [arguments]\n"
+       "\n"
+       "Available commands:\n"
+       "\tsignal <source> <emission>\n"
+       "\t   sends a signal to edje\n"
+       "\tinfo <part>\n"
+       "\t   Print part geometry: <x>,<y>,<w>,<h>\n"
+       "\tquit\n"
+       "\t   exit edje player.\n"
+       "\thelp\n"
+       "\t   shows this message.\n");
+   /*
+    * Extension ideas (are they useful?):
+    *  - message: send a message
+    *  - data: show data value
+    *  - color_class: set color class values (maybe also list?)
+    *  - text_class: set text class values (maybe also list?)
+    *  - play_set: change play state
+    *  - animation_set: change animation state
+    */
+}
+
+struct slave_cmd
+{
+   const char *cmd;
+   void (*func)(Evas_Object *edje, char *args);
+} _slave_mode_commands[] = {
+  {"signal", _slave_mode_signal},
+  {"info", _slave_mode_info},
+  {"quit", _slave_mode_quit},
+  {"help", _slave_mode_help},
+  {NULL, NULL}
+};
+
+static int
+_slave_mode(void *data, Ecore_Fd_Handler *fd_handler)
+{
+   Evas_Object *edje = data;
+   char buf[1024], *p;
+   const struct slave_cmd *itr;
+   size_t len;
+
+   if (ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_ERROR))
+     {
+       fputs("ERROR: error on stdin! Exit.\n", stderr);
+       ecore_main_loop_quit();
+       return 0;
+     }
+   if (!ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_READ))
+     return 1;
+
+   if (!fgets(buf, sizeof(buf), stdin))
+     {
+       fputs("ERROR: end of stdin! Exit.\n", stderr);
+       ecore_main_loop_quit();
+       return 0;
+     }
+
+   len = strlen(buf);
+   if (len < 1)
+     {
+       fputs("ERROR: no input! Try: help\n", stderr);
+       return 1;
+     }
+   if (buf[len - 1] == '\n')
+     {
+       len--;
+       buf[len] = '\0';
+     }
+
+   p = strchr(buf, ' ');
+   if (p)
+     {
+       *p = '\0';
+       p++;
+
+       while (isspace(*p))
+         p++;
+       if (*p == '\0')
+         p = NULL;
+
+       if (p)
+         {
+            char *q = p + strlen(p) - 1;
+            while (isspace(*q))
+              {
+                 *q = '\0';
+                 q--;
+              }
+         }
+     }
+
+   for (itr = _slave_mode_commands; itr->cmd != NULL; itr++)
+     {
+       if (strcmp(itr->cmd, buf) == 0)
+         {
+            itr->func(edje, p);
+            break;
+         }
+     }
+
+   return 1;
+}
+
+static void
+_print_signal(void *data __UNUSED__, Evas_Object *o __UNUSED__, const char *emission, const char *source)
+{
+   printf("SIGNAL: \"%s\" \"%s\"\n", emission, source);
+}
+
+static void
+_print_message(void *data __UNUSED__, Evas_Object *edje __UNUSED__, Edje_Message_Type type, int id, void *msg)
+{
+   const char *typestr;
+   char buf[64];
+
+   switch (type)
+     {
+      case EDJE_MESSAGE_NONE:
+        typestr = "NONE";
+        break;
+      case EDJE_MESSAGE_SIGNAL:
+        typestr = "SIGNAL";
+        break;
+      case EDJE_MESSAGE_STRING:
+        typestr = "STRING";
+        break;
+      case EDJE_MESSAGE_INT:
+        typestr = "INT";
+        break;
+      case EDJE_MESSAGE_FLOAT:
+        typestr = "FLOAT";
+        break;
+      case EDJE_MESSAGE_STRING_SET:
+        typestr = "STRING_SET";
+        break;
+      case EDJE_MESSAGE_INT_SET:
+        typestr = "INT_SET";
+        break;
+      case EDJE_MESSAGE_FLOAT_SET:
+        typestr = "FLOAT_SET";
+        break;
+      case EDJE_MESSAGE_STRING_INT:
+        typestr = "STRING_INT";
+        break;
+      case EDJE_MESSAGE_STRING_FLOAT:
+        typestr = "STRING_FLOAT";
+        break;
+      case EDJE_MESSAGE_STRING_INT_SET:
+        typestr = "INT_SET";
+        break;
+      case EDJE_MESSAGE_STRING_FLOAT_SET:
+        typestr = "FLOAT_SET";
+        break;
+      default:
+        snprintf(buf, sizeof(buf), "UNKNOWN(%d)", type);
+        typestr = buf;
+     }
+
+   printf("MESSAGE: type=%s, id=%d", typestr, id);
+
+   switch (type)
+     {
+      case EDJE_MESSAGE_NONE: break;
+      case EDJE_MESSAGE_SIGNAL: break;
+      case EDJE_MESSAGE_STRING:
+       {
+          Edje_Message_String *m = msg;
+          printf(" \"%s\"", m->str);
+       }
+       break;
+      case EDJE_MESSAGE_INT:
+       {
+          Edje_Message_Int *m = msg;
+          printf(" %d", m->val);
+       }
+       break;
+      case EDJE_MESSAGE_FLOAT:
+       {
+          Edje_Message_Float *m = msg;
+          printf(" %f", m->val);
+       }
+       break;
+      case EDJE_MESSAGE_STRING_SET:
+       {
+          Edje_Message_String_Set *m = msg;
+          int i;
+          for (i = 0; i < m->count; i++)
+            printf(" \"%s\"", m->str[i]);
+       }
+       break;
+      case EDJE_MESSAGE_INT_SET:
+       {
+          Edje_Message_Int_Set *m = msg;
+          int i;
+          for (i = 0; i < m->count; i++)
+            printf(" %d", m->val[i]);
+       }
+       break;
+      case EDJE_MESSAGE_FLOAT_SET:
+       {
+          Edje_Message_Float_Set *m = msg;
+          int i;
+          for (i = 0; i < m->count; i++)
+            printf(" %f", m->val[i]);
+       }
+       break;
+      case EDJE_MESSAGE_STRING_INT:
+       {
+          Edje_Message_String_Int *m = msg;
+          printf(" \"%s\" %d", m->str, m->val);
+       }
+       break;
+      case EDJE_MESSAGE_STRING_FLOAT:
+       {
+          Edje_Message_String_Float *m = msg;
+          printf(" \"%s\" %f", m->str, m->val);
+       }
+       break;
+      case EDJE_MESSAGE_STRING_INT_SET:
+       {
+          Edje_Message_String_Int_Set *m = msg;
+          int i;
+          printf(" \"%s\"", m->str);
+          for (i = 0; i < m->count; i++)
+            printf(" %d", m->val[i]);
+       }
+       break;
+      case EDJE_MESSAGE_STRING_FLOAT_SET:
+       {
+          Edje_Message_String_Float_Set *m = msg;
+          int i;
+          printf(" \"%s\"", m->str);
+          for (i = 0; i < m->count; i++)
+            printf(" %f", m->val[i]);
+       }
+       break;
+      default:
+       break;
+     }
+
+   putchar('\n');
+}
+
+static void
+_reset_size_hints(void *data, Evas *e __UNUSED__, Evas_Object *stack, void *event_info __UNUSED__)
+{
+   Evas_Coord minw, minh;
+   Evas_Object *edje = data;
+
+   edje_object_size_min_get(edje, &minw, &minh);
+   if ((minw <= 0) && (minh <= 0))
+     edje_object_size_min_calc(edje, &minw, &minh);
+
+   evas_object_size_hint_min_set(stack, minw, minh);
+}
+
+static Evas_Object *
+_create_stack(Evas *evas, const struct opts *opts)
+{
+   Evas_Object *stack = evas_object_box_add(evas);
+   if (!stack)
+     {
+       fputs("ERROR: could not create object stack (box).\n", stderr);
+       return NULL;
+     }
+   evas_object_box_layout_set(stack, evas_object_box_layout_stack, NULL, NULL);
+   evas_object_resize(stack, opts->size.w, opts->size.h);
+   evas_object_size_hint_weight_set(stack, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+   evas_object_size_hint_align_set(stack, EVAS_HINT_FILL, EVAS_HINT_FILL);
+   evas_object_show(stack);
+   return stack;
+}
+
+static Evas_Object *
+_create_bg(Evas *evas, const struct opts *opts)
+{
+   const unsigned char *color = opts->color;
+   Evas_Object *bg = evas_object_rectangle_add(evas);
+   if (!bg)
+     {
+       fputs("ERROR: could not create background.\n", stderr);
+       return NULL;
+     }
+   evas_object_resize(bg, opts->size.w, opts->size.h);
+   evas_object_color_set(bg, color[0], color[1], color[2], 255);
+   evas_object_size_hint_weight_set(bg, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+   evas_object_size_hint_align_set(bg, EVAS_HINT_FILL, EVAS_HINT_FILL);
+   evas_object_show(bg);
+   return bg;
+}
+
+static Eina_Bool
+_edje_load_or_show_error(Evas_Object *edje, const char *file, const char *group)
+{
+   const char *errmsg;
+   int err;
+
+   if (edje_object_file_set(edje, file, group))
+     return EINA_TRUE;
+
+   err = edje_object_load_error_get(edje);
+   errmsg = edje_load_error_str(err);
+   fprintf(stderr, "ERROR: could not load edje file '%s', group '%s': %s\n",
+          file, group, errmsg);
+   return EINA_FALSE;
+}
+
+static Evas_Object *
+_create_edje(Evas *evas, const struct opts *opts)
+{
+   Evas_Coord minw, minh, maxw, maxh;
+   Evas_Object *edje = edje_object_add(evas);
+   if (!edje)
+     {
+       fputs("ERROR: could not create edje.\n", stderr);
+       return NULL;
+     }
+
+   if (opts->group)
+     {
+       if (!_edje_load_or_show_error(edje, opts->file, opts->group))
+         {
+            evas_object_del(edje);
+            return NULL;
+         }
+     }
+   else
+     {
+       if (edje_file_group_exists(opts->file, "main"))
+         {
+            if (!_edje_load_or_show_error(edje, opts->file, "main"))
+              {
+                 evas_object_del(edje);
+                 return NULL;
+              }
+         }
+       else
+         {
+            Eina_List *groups = edje_file_collection_list(opts->file);
+            const char *group;
+            if (!groups)
+              {
+                 fprintf(stderr, "ERROR: file '%s' has no groups!\n",
+                         opts->file);
+                 evas_object_del(edje);
+                 return NULL;
+              }
+            group = groups->data;
+            if (!_edje_load_or_show_error(edje, opts->file, group))
+              {
+                 edje_file_collection_list_free(groups);
+                 evas_object_del(edje);
+                 return NULL;
+              }
+            edje_file_collection_list_free(groups);
+         }
+     }
+
+   edje_object_size_max_get(edje, &maxw, &maxh);
+   edje_object_size_min_get(edje, &minw, &minh);
+   if ((minw <= 0) && (minh <= 0))
+     edje_object_size_min_calc(edje, &minw, &minh);
+
+   evas_object_size_hint_max_set(edje, maxw, maxh);
+   evas_object_size_hint_min_set(edje, minw, minh);
+
+   evas_object_size_hint_weight_set(edje, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+   evas_object_size_hint_align_set(edje, EVAS_HINT_FILL, EVAS_HINT_FILL);
+   evas_object_show(edje);
+
+   return edje;
+}
+
+static  unsigned char _parse_color(const Ecore_Getopt *parser, const Ecore_Getopt_Desc *desc, const char *str, void *data, Ecore_Getopt_Value *storage)
+{
+   unsigned char *color = (unsigned char *)storage->ptrp;
+
+   if (sscanf(str, "%hhu,%hhu,%hhu", color, color + 1, color + 2) != 3)
+     {
+       fprintf(stderr, "ERROR: incorrect color value '%s'\n", str);
+       return 0;
+     }
+
+   return 1;
+}
+
+const Ecore_Getopt optdesc = {
+  "edje_player",
+  "%prog [options] <filename.edj>",
+  PACKAGE_VERSION,
+  "(C) 2010 Enlightenment",
+  "BSD with advertisement clause",
+  "Simple application to view edje files.",
+  0,
+  {
+    ECORE_GETOPT_STORE_STR
+    ('g', "group", "The edje group to view (defaults to 'main')."),
+    ECORE_GETOPT_STORE_TRUE
+    ('G', "list-groups", "The groups in the given file."),
+    ECORE_GETOPT_STORE_STR
+    ('e', "engine", "The Ecore-Evas engine to use (see --list-engines)"),
+    ECORE_GETOPT_CALLBACK_NOARGS
+    ('E', "list-engines", "list Ecore-Evas engines",
+     ecore_getopt_callback_ecore_evas_list_engines, NULL),
+    ECORE_GETOPT_CALLBACK_ARGS
+    ('Z', "size", "size to use in wxh form.", "WxH",
+     ecore_getopt_callback_size_parse, NULL),
+    ECORE_GETOPT_CALLBACK_ARGS
+    ('c', "bg-color", "Color of the background (if not shaped or alpha)",
+     "RRGGBB", _parse_color, NULL),
+    ECORE_GETOPT_STORE_TRUE
+    ('b', "borderless", "Display window without border."),
+    ECORE_GETOPT_STORE_TRUE
+    ('y', "sticky", "Display window sticky."),
+    ECORE_GETOPT_STORE_TRUE
+    ('s', "shaped", "Display window shaped."),
+    ECORE_GETOPT_STORE_TRUE
+    ('a', "alpha", "Display window with alpha channel "
+     "(needs composite manager!)"),
+    ECORE_GETOPT_STORE_STR
+    ('t', "title", "Define the window title string"),
+    ECORE_GETOPT_STORE_TRUE
+    ('p', "print", "Print signals and messages to stdout"),
+    ECORE_GETOPT_STORE_TRUE
+    ('S', "slave-mode", "Listen for commands on stdin"),
+    ECORE_GETOPT_LICENSE('L', "license"),
+    ECORE_GETOPT_COPYRIGHT('C', "copyright"),
+    ECORE_GETOPT_VERSION('V', "version"),
+    ECORE_GETOPT_HELP('h', "help"),
+    ECORE_GETOPT_SENTINEL
+  }
+};
+
+int main(int argc, char **argv)
+{
+   Ecore_Evas *win;
+   Evas *evas;
+   Evas_Object *stack, *edje;
+   struct opts opts;
+   Eina_Bool quit_option = EINA_FALSE;
+   int args, ret;
+   Ecore_Getopt_Value values[] = {
+     ECORE_GETOPT_VALUE_STR(opts.group),
+     ECORE_GETOPT_VALUE_BOOL(opts.list_groups),
+     ECORE_GETOPT_VALUE_STR(opts.engine),
+     ECORE_GETOPT_VALUE_BOOL(quit_option),
+     ECORE_GETOPT_VALUE_PTR_CAST(opts.size),
+     ECORE_GETOPT_VALUE_PTR_CAST(opts.color),
+     ECORE_GETOPT_VALUE_BOOL(opts.borderless),
+     ECORE_GETOPT_VALUE_BOOL(opts.sticky),
+     ECORE_GETOPT_VALUE_BOOL(opts.shaped),
+     ECORE_GETOPT_VALUE_BOOL(opts.alpha),
+     ECORE_GETOPT_VALUE_STR(opts.title),
+     ECORE_GETOPT_VALUE_BOOL(opts.print),
+     ECORE_GETOPT_VALUE_BOOL(opts.slave_mode),
+     ECORE_GETOPT_VALUE_BOOL(quit_option),
+     ECORE_GETOPT_VALUE_BOOL(quit_option),
+     ECORE_GETOPT_VALUE_BOOL(quit_option),
+     ECORE_GETOPT_VALUE_BOOL(quit_option),
+     ECORE_GETOPT_VALUE_NONE
+   };
+
+   memset(&opts, 0, sizeof(opts));
+
+   evas_init();
+   ecore_init();
+   ecore_evas_init();
+   edje_init();
+
+   args = ecore_getopt_parse(&optdesc, values, argc, argv);
+   if (args < 0)
+     {
+       fputs("Could not parse arguments.\n", stderr);
+       ret = -1;
+       goto end;
+     }
+   else if (quit_option)
+     {
+       ret = 0;
+       goto end;
+     }
+   else if (args >= argc)
+     {
+       fputs("Missing edje file to load.\n", stderr);
+       ret = -2;
+       goto end;
+     }
+
+   ecore_app_args_set(argc, (const char **)argv);
+
+   ret = 0;
+   opts.file = argv[args];
+   if (opts.list_groups)
+     {
+       Eina_List *groups, *n;
+       const char *group;
+       groups = edje_file_collection_list(opts.file);
+       printf("%d groups in file '%s':\n", eina_list_count(groups), opts.file);
+       EINA_LIST_FOREACH(groups, n, group)
+         printf("\t'%s'\n", group);
+       edje_file_collection_list_free(groups);
+       goto end;
+     }
+
+   win = ecore_evas_new(opts.engine, 0, 0, opts.size.w, opts.size.h, NULL);
+   if (!win)
+     {
+       fprintf(stderr,
+               "ERROR: could not create window of "
+               "size %dx%d using engine %s.\n",
+               opts.size.w, opts.size.h, opts.engine ? opts.engine : "(auto)");
+       ret = -3;
+       goto end;
+     }
+
+   evas = ecore_evas_get(win);
+   stack = _create_stack(evas, &opts);
+   if (!stack)
+     {
+       ret = -4;
+       goto end_win;
+     }
+
+   ecore_evas_object_associate(win, stack, ECORE_EVAS_OBJECT_ASSOCIATE_BASE);
+
+   if (opts.alpha)
+     ecore_evas_alpha_set(win, EINA_TRUE);
+   else if (opts.shaped)
+     ecore_evas_shaped_set(win, EINA_TRUE);
+   else
+     {
+       Evas_Object *bg = _create_bg(evas, &opts);
+       if (bg) evas_object_box_append(stack, bg);
+     }
+
+   edje = _create_edje(evas, &opts);
+   if (edje)
+     evas_object_box_append(stack, edje);
+   else
+     {
+       ret = -5;
+       goto end_win;
+     }
+
+   evas_object_event_callback_add(stack, EVAS_CALLBACK_CHANGED_SIZE_HINTS,
+                                 _reset_size_hints, edje);
+
+   if (opts.print)
+     {
+       edje_object_signal_callback_add(edje, "*", "*", _print_signal, NULL);
+       edje_object_message_handler_set(edje, _print_message, NULL);
+     }
+
+   if (opts.slave_mode)
+     {
+       int flags;
+       flags = fcntl(STDIN_FILENO, F_GETFL, 0);
+       flags |= O_NONBLOCK;
+       if (fcntl(STDIN_FILENO, F_SETFL, flags) < 0)
+         {
+            fprintf(stderr, "ERROR: Could not set stdin to non-block: %s\n",
+                    strerror(errno));
+            ret = -6;
+            goto end_win;
+         }
+       ecore_main_fd_handler_add(STDIN_FILENO, ECORE_FD_READ | ECORE_FD_ERROR,
+                                 _slave_mode, edje, NULL, NULL);
+     }
+
+   ecore_evas_borderless_set(win, opts.borderless);
+   ecore_evas_sticky_set(win, opts.sticky);
+   if (opts.title)
+     ecore_evas_title_set(win, opts.title);
+   else
+     {
+       char buf[1024];
+       snprintf(buf, sizeof(buf), "Edje_Player - %s of %s",
+                opts.group, opts.file);
+       ecore_evas_title_set(win, buf);
+     }
+
+   if (opts.size.w <= 0) opts.size.w = 320;
+   if (opts.size.h <= 0) opts.size.h = 240;
+   ecore_evas_resize(win, opts.size.w, opts.size.h);
+   ecore_evas_show(win);
+   ecore_main_loop_begin();
+
+ end_win:
+   ecore_evas_free(win);
+ end:
+   edje_shutdown();
+   ecore_evas_shutdown();
+   ecore_shutdown();
+   evas_shutdown();
+
+   return ret;
+}
diff --git a/src/bin/edje_prefix.c b/src/bin/edje_prefix.c
new file mode 100644 (file)
index 0000000..0819ee1
--- /dev/null
@@ -0,0 +1,452 @@
+/*
+ * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/param.h>
+#include <math.h>
+#include <limits.h>
+#include <ctype.h>
+#include <time.h>
+#include <dirent.h>
+
+#ifdef HAVE_EVIL
+# include <Evil.h>
+#endif
+
+#include "edje_prefix.h"
+#include "edje_cc.h"
+#ifdef _WIN32
+# define EDJE_DIR_SEPARATOR '\\'
+# define EDJE_DIR_SEPARATOR_S "\\"
+#else
+# define EDJE_DIR_SEPARATOR '/'
+# define EDJE_DIR_SEPARATOR_S "/"
+#endif /* _WIN32 */
+
+/* local subsystem functions */
+static int _e_prefix_share_hunt(void);
+static int _e_prefix_fallbacks(void);
+static int _e_prefix_try_proc(void);
+static int _e_prefix_try_argv(char *argv0);
+
+/* local subsystem globals */
+static char *_exe_path = NULL;
+static char *_prefix_path = NULL;
+static char *_prefix_path_bin = NULL;
+static char *_prefix_path_data = NULL;
+static char *_prefix_path_lib = NULL;
+
+#define E_FREE(p) { if (p) {free(p); p = NULL;} }
+
+/*#define PREFIX_CACHE_FILE 1*/
+#define SHARE_D "share/edje"
+#define MAGIC_FILE "include/edje.inc"
+#define MAGIC_DAT SHARE_D"/"MAGIC_FILE
+
+/* externally accessible functions */
+int
+e_prefix_determine(char *argv0)
+{
+   char *p, buf[4096];
+   struct stat st;
+
+   e_prefix_shutdown();
+
+   /* if user provides E_PREFIX - then use that or also more specific sub
+    * dirs for bin, lib, data and locale */
+   if (getenv("EDJE_PREFIX"))
+     {
+       _prefix_path = strdup(getenv("EDJE_PREFIX"));
+       if (getenv("EDJE_BIN_DIR"))
+         snprintf(buf, sizeof(buf), "%s" EDJE_DIR_SEPARATOR_S "bin", getenv("EDJE_BIN_DIR"));
+       else
+         snprintf(buf, sizeof(buf), "%s" EDJE_DIR_SEPARATOR_S "bin", _prefix_path);
+       _prefix_path_bin = strdup(buf);
+
+       if (getenv("EDJE_LIB_DIR"))
+         snprintf(buf, sizeof(buf), "%s" EDJE_DIR_SEPARATOR_S "lib", getenv("EDJE_LIB_DIR"));
+       else
+         snprintf(buf, sizeof(buf), "%s" EDJE_DIR_SEPARATOR_S "lib", _prefix_path);
+       _prefix_path_lib = strdup(buf);
+
+       if (getenv("EDJE_DATA_DIR"))
+         snprintf(buf, sizeof(buf), "%s" EDJE_DIR_SEPARATOR_S SHARE_D, getenv("EDJE_DATA_DIR"));
+       else
+         snprintf(buf, sizeof(buf), "%s" EDJE_DIR_SEPARATOR_S SHARE_D, _prefix_path);
+       _prefix_path_data = strdup(buf);
+       return 1;
+     }
+   /* no env var - examine process and possible argv0 */
+   if (!_e_prefix_try_proc())
+     {
+       if (!_e_prefix_try_argv(argv0))
+         {
+            _e_prefix_fallbacks();
+            return 0;
+         }
+     }
+   /* _exe_path is now a full absolute path TO this exe - figure out rest */
+   /*   if
+    * exe        = /blah/whatever/bin/exe
+    *   then
+    * prefix     = /blah/whatever
+    * bin_dir    = /blah/whatever/bin
+    * data_dir   = /blah/whatever/share/enlightenment
+    * lib_dir    = /blah/whatever/lib
+    */
+   p = strrchr(_exe_path, EDJE_DIR_SEPARATOR);
+   if (p)
+     {
+       p--;
+       while (p >= _exe_path)
+         {
+            if (*p == EDJE_DIR_SEPARATOR)
+              {
+                 _prefix_path = malloc(p - _exe_path + 1);
+                 if (_prefix_path)
+                   {
+                      strncpy(_prefix_path, _exe_path, p - _exe_path);
+                      _prefix_path[p - _exe_path] = 0;
+
+                      /* bin and lib always together */
+                      snprintf(buf, sizeof(buf), "%s" EDJE_DIR_SEPARATOR_S "bin", _prefix_path);
+                      _prefix_path_bin = strdup(buf);
+                      snprintf(buf, sizeof(buf), "%s" EDJE_DIR_SEPARATOR_S "lib", _prefix_path);
+                      _prefix_path_lib = strdup(buf);
+
+                      /* check if AUTHORS file is there - then our guess is right */
+                      snprintf(buf, sizeof(buf), "%s" EDJE_DIR_SEPARATOR_S MAGIC_DAT, _prefix_path);
+                      if (stat(buf, &st) == 0)
+                        {
+                           snprintf(buf, sizeof(buf), "%s" EDJE_DIR_SEPARATOR_S SHARE_D, _prefix_path);
+                           _prefix_path_data = strdup(buf);
+                        }
+                      /* AUTHORS file not there. time to start hunting! */
+                      else
+                        {
+                           if (_e_prefix_share_hunt())
+                             {
+                                return 1;
+                             }
+                           else
+                             {
+                                e_prefix_fallback();
+                                return 0;
+                             }
+                        }
+                      return 1;
+                   }
+                 else
+                   {
+                      e_prefix_fallback();
+                      return 0;
+                   }
+              }
+            p--;
+         }
+     }
+   e_prefix_fallback();
+   return 0;
+}
+
+void
+e_prefix_shutdown(void)
+{
+   E_FREE(_exe_path);
+   E_FREE(_prefix_path);
+   E_FREE(_prefix_path_bin);
+   E_FREE(_prefix_path_data);
+   E_FREE(_prefix_path_lib);
+}
+
+void
+e_prefix_fallback(void)
+{
+   e_prefix_shutdown();
+   _e_prefix_fallbacks();
+}
+
+const char *
+e_prefix_get(void)
+{
+   return _prefix_path;
+}
+
+const char *
+e_prefix_bin_get(void)
+{
+   return _prefix_path_bin;
+}
+
+const char *
+e_prefix_data_get(void)
+{
+   return _prefix_path_data;
+}
+
+const char *
+e_prefix_lib_get(void)
+{
+   return _prefix_path_lib;
+}
+
+/* local subsystem functions */
+static int
+_e_prefix_share_hunt(void)
+{
+   char buf[4096], buf2[4096], *p;
+   struct stat st;
+
+   /* sometimes this isnt the case - so we need to do a more exhaustive search
+    * through more parent and subdirs. hre is an example i have seen:
+    *
+    * /blah/whatever/exec/bin/exe
+    * ->
+    * /blah/whatever/exec/bin
+    * /blah/whatever/common/share/enlightenment
+    * /blah/whatever/exec/lib
+    */
+
+   /* this is pure black magic to try and find data shares */
+   /* 2. cache file doesn't exist or is invalid - we need to search - this is
+    * where the real black magic begins */
+
+   /* BLACK MAGIC 1:
+    * /blah/whatever/dir1/bin
+    * /blah/whatever/dir2/share/enlightenment
+    */
+   if (!_prefix_path_data)
+     {
+       DIR                *dirp;
+       struct dirent      *dp;
+
+       snprintf(buf, sizeof(buf), "%s", _prefix_path);
+       p = strrchr(buf, '/');
+       if (p) *p = 0;
+       dirp = opendir(buf);
+       if (dirp)
+         {
+            char *file;
+
+            while ((dp = readdir(dirp)))
+              {
+                 if ((strcmp(dp->d_name, ".")) && (strcmp(dp->d_name, "..")))
+                   {
+                      file = dp->d_name;
+                      snprintf(buf2, sizeof(buf2), "%s/%s/"MAGIC_DAT, buf, file);
+                      if (stat(buf2, &st) == 0)
+                        {
+                           snprintf(buf2, sizeof(buf2), "%s/%s/"SHARE_D, buf, file);
+                           _prefix_path_data = strdup(buf2);
+                           break;
+                        }
+                   }
+              }
+            closedir(dirp);
+         }
+     }
+
+   /* BLACK MAGIC 2:
+    * /blah/whatever/dir1/bin
+    * /blah/whatever/share/enlightenment
+    */
+   if (!_prefix_path_data)
+     {
+       snprintf(buf, sizeof(buf), "%s", _prefix_path);
+       p = strrchr(buf, '/');
+       if (p) *p = 0;
+       snprintf(buf2, sizeof(buf2), "%s/"MAGIC_DAT, buf);
+       if (stat(buf, &st) == 0)
+         {
+            snprintf(buf2, sizeof(buf2), "%s/"SHARE_D, buf);
+            _prefix_path_data = strdup(buf2);
+         }
+     }
+
+   /* add more black magic as required as we discover weridnesss - remember
+    * this is to save users having to set environment variables to tell
+    * e where it lives, so e auto-adapts. so these code snippets are just
+    * logic to figure that out for the user
+    */
+
+   /* done. we found it - write cache file */
+   if (_prefix_path_data)
+     {
+       return 1;
+     }
+   /* fail. everything failed */
+   return 0;
+}
+
+static int
+_e_prefix_fallbacks(void)
+{
+   char *p;
+
+   _prefix_path = strdup(PACKAGE_BIN_DIR);
+   p = strrchr(_prefix_path, '/');
+   if (p) *p = 0;
+   _prefix_path_bin    = strdup(PACKAGE_BIN_DIR);
+   _prefix_path_data   = strdup(PACKAGE_DATA_DIR);
+   _prefix_path_lib    = strdup(PACKAGE_LIB_DIR);
+   WRN("WARNING: Edje could not determine its installed prefix\n"
+         "         and is falling back on the compiled in default:\n"
+         "           %s\n"
+         "         You might like to try setting the following environment variables:\n"
+         "           EDJE_PREFIX  - points to the base prefix of install\n"
+         "           EDJE_BIN_DIR - optional in addition to E_PREFIX to provide\n"
+         "                          a more specific binary directory\n"
+         "           EDJE_LIB_DIR - optional in addition to E_PREFIX to provide\n"
+         "                          a more specific library dir\n"
+         "           EDJE_DATA_DIR- optional in addition to E_PREFIX to provide\n"
+         "                          a more specific location for shared data",
+       _prefix_path);
+   return 1;
+}
+
+static int
+_e_prefix_try_proc(void)
+{
+   FILE *f;
+   char buf[4096];
+   void *func = NULL;
+
+   func = (void *)_e_prefix_try_proc;
+   f = fopen("/proc/self/maps", "rb");
+   if (!f) return 0;
+   while (fgets(buf, sizeof(buf), f))
+     {
+       int len;
+       char *p, mode[5] = "";
+       unsigned long ptr1 = 0, ptr2 = 0;
+
+       len = strlen(buf);
+       if (buf[len - 1] == '\n')
+         {
+            buf[len - 1] = 0;
+            len--;
+         }
+       if (sscanf(buf, "%lx-%lx %4s", &ptr1, &ptr2, mode) == 3)
+         {
+            if (!strcmp(mode, "r-xp"))
+              {
+                 if (((void *)ptr1 <= func) && (func < (void *)ptr2))
+                   {
+                      p = strchr(buf, '/');
+                      if (p)
+                        {
+                           if (len > 10)
+                             {
+                                if (!strcmp(buf + len - 10, " (deleted)"))
+                                  buf[len - 10] = 0;
+                             }
+                           _exe_path = strdup(p);
+                           fclose(f);
+                           return 1;
+                        }
+                      else
+                        break;
+                   }
+              }
+         }
+     }
+   fclose(f);
+   return 0;
+}
+
+static int
+_e_prefix_try_argv(char *argv0)
+{
+   char *path, *p, *cp, *s;
+   int len, lenexe;
+   char buf[4096], buf2[4096], buf3[4096];
+
+   /* 1. is argv0 abs path? */
+#ifdef _WIN32
+   if (argv0[1] == ':')
+#else
+   if (argv0[0] == '/')
+#endif
+     {
+       _exe_path = strdup(argv0);
+       if (access(_exe_path, X_OK) == 0) return 1;
+       free(_exe_path);
+       _exe_path = NULL;
+       return 0;
+     }
+   /* 2. relative path */
+   if (strchr(argv0, '/'))
+     {
+       if (getcwd(buf3, sizeof(buf3)))
+         {
+            snprintf(buf2, sizeof(buf2), "%s/%s", buf3, argv0);
+            if (realpath(buf2, buf))
+              {
+                 _exe_path = strdup(buf);
+                 if (access(_exe_path, X_OK) == 0) return 1;
+                 free(_exe_path);
+                 _exe_path = NULL;
+              }
+         }
+     }
+   /* 3. argv0 no path - look in PATH */
+   path = getenv("PATH");
+   if (!path) return 0;
+   p = path;
+   cp = p;
+   lenexe = strlen(argv0);
+   while ((p = strchr(cp, ':')))
+     {
+       len = p - cp;
+       s = malloc(len + 1 + lenexe + 1);
+       if (s)
+         {
+            strncpy(s, cp, len);
+            s[len] = '/';
+            strcpy(s + len + 1, argv0);
+            if (realpath(s, buf))
+              {
+                 if (access(buf, X_OK) == 0)
+                   {
+                      _exe_path = strdup(buf);
+                      free(s);
+                      return 1;
+                   }
+              }
+            free(s);
+         }
+        cp = p + 1;
+     }
+   len = strlen(cp);
+   s = malloc(len + 1 + lenexe + 1);
+   if (s)
+     {
+       strncpy(s, cp, len);
+       s[len] = '/';
+       strcpy(s + len + 1, argv0);
+       if (realpath(s, buf))
+         {
+            if (access(buf, X_OK) == 0)
+              {
+                 _exe_path = strdup(buf);
+                 free(s);
+                 return 1;
+              }
+         }
+       free(s);
+     }
+   /* 4. big problems. arg[0] != executable - weird execution */
+   return 0;
+}
diff --git a/src/bin/edje_prefix.h b/src/bin/edje_prefix.h
new file mode 100644 (file)
index 0000000..4bea3f9
--- /dev/null
@@ -0,0 +1,11 @@
+/*
+ * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
+ */
+
+int         e_prefix_determine(char *argv0);
+void        e_prefix_shutdown(void);
+void        e_prefix_fallback(void);
+const char *e_prefix_get(void);
+const char *e_prefix_bin_get(void);
+const char *e_prefix_data_get(void);
+const char *e_prefix_lib_get(void);
diff --git a/src/bin/edje_recc b/src/bin/edje_recc
new file mode 100644 (file)
index 0000000..2ae81ad
--- /dev/null
@@ -0,0 +1,69 @@
+#!/bin/sh
+
+set -e
+
+usage () {
+  echo "Usage:"
+  echo "        edje_recc [OPTIONS] input_file.edj"
+  echo ""
+  echo "Where OPTIONS is one or more of:"
+  echo ""
+  echo "-v                       Verbose output"
+  echo "-no-lossy                Do NOT allow images to be lossy"
+  echo "-no-comp                 Do NOT allow images to be lossless compression"
+  echo "-no-raw                  Do NOT allow images to be zero compression"
+  echo "-min-quality VAL         Do NOT allow lossy images with quality < VAL (0-100)"
+  echo "-max-quality VAL         Do NOT allow lossy images with quality > VAL (0-100)"
+  exit -1
+}
+
+if [ $# -lt 1 ]; then
+  usage
+fi
+
+OPT=""
+if [ $# -ge 1 ]; then
+  for I in $@; do
+    case "$I" in
+      -h)
+        usage
+      ;;
+
+      -help)
+        usage
+      ;;
+
+      --help)
+        usage
+      ;;
+
+      *.edj)
+        IN=$I
+      ;;
+
+      *)
+        OPT=$OPT" "$I
+      ;;
+    esac
+  done
+fi
+
+if [ -z "$IN" ]; then
+  echo "ERROR: NO input file.edj provided!"
+  echo ""
+  usage;
+fi
+
+F=`basename $IN`
+B=`basename $F .edj`
+T="./...edje_tmp"
+rm -rf $T
+mkdir -p $T
+cp $IN $T
+cd $T
+edje_decc $F
+cd $B
+./build.sh $OPT
+cd ../..
+mv $T/$B/$F $IN
+rm -rf $T
diff --git a/src/lib/.cvsignore b/src/lib/.cvsignore
new file mode 100644 (file)
index 0000000..09980ae
--- /dev/null
@@ -0,0 +1,6 @@
+.deps
+.libs
+Makefile
+Makefile.in
+*.lo
+*.la
diff --git a/src/lib/Edje.h b/src/lib/Edje.h
new file mode 100644 (file)
index 0000000..bdd4bf8
--- /dev/null
@@ -0,0 +1,603 @@
+#ifndef _EDJE_H
+#define _EDJE_H
+
+#include <stdint.h>
+#include <math.h>
+
+#include <Evas.h>
+
+#ifdef EAPI
+# undef EAPI
+#endif
+
+#ifdef _WIN32
+# ifdef EFL_EDJE_BUILD
+#  ifdef DLL_EXPORT
+#   define EAPI __declspec(dllexport)
+#  else
+#   define EAPI
+#  endif /* ! DLL_EXPORT */
+# else
+#  define EAPI __declspec(dllimport)
+# endif /* ! EFL_EDJE_BUILD */
+#else
+# ifdef __GNUC__
+#  if __GNUC__ >= 4
+#   define EAPI __attribute__ ((visibility("default")))
+#  else
+#   define EAPI
+#  endif
+# else
+#  define EAPI
+# endif
+#endif
+
+/**
+ * @file Edje.h
+ * @brief Edje Graphical Design Library
+ *
+ * These routines are used for Edje.
+ */
+
+
+/* FIXDOC: Define these? */
+enum _Edje_Message_Type
+{
+   EDJE_MESSAGE_NONE = 0,
+
+     EDJE_MESSAGE_SIGNAL = 1, /* DONT USE THIS */
+
+     EDJE_MESSAGE_STRING = 2,
+     EDJE_MESSAGE_INT = 3,
+     EDJE_MESSAGE_FLOAT = 4,
+
+     EDJE_MESSAGE_STRING_SET = 5,
+     EDJE_MESSAGE_INT_SET = 6,
+     EDJE_MESSAGE_FLOAT_SET = 7,
+
+     EDJE_MESSAGE_STRING_INT = 8,
+     EDJE_MESSAGE_STRING_FLOAT = 9,
+
+     EDJE_MESSAGE_STRING_INT_SET = 10,
+     EDJE_MESSAGE_STRING_FLOAT_SET = 11
+};
+typedef enum _Edje_Message_Type Edje_Message_Type;
+
+enum _Edje_Aspect_Control
+{
+   EDJE_ASPECT_CONTROL_NONE = 0,
+   EDJE_ASPECT_CONTROL_NEITHER = 1,
+   EDJE_ASPECT_CONTROL_HORIZONTAL = 2,
+   EDJE_ASPECT_CONTROL_VERTICAL = 3,
+   EDJE_ASPECT_CONTROL_BOTH = 4
+};
+typedef enum _Edje_Aspect_Control Edje_Aspect_Control;
+
+enum _Edje_Object_Table_Homogeneous_Mode
+{
+   EDJE_OBJECT_TABLE_HOMOGENEOUS_NONE = 0,
+   EDJE_OBJECT_TABLE_HOMOGENEOUS_TABLE = 1,
+   EDJE_OBJECT_TABLE_HOMOGENEOUS_ITEM = 2
+};
+typedef enum _Edje_Object_Table_Homogeneous_Mode Edje_Object_Table_Homogeneous_Mode;
+
+typedef enum _Edje_Part_Type
+{
+   EDJE_PART_TYPE_NONE      = 0,
+   EDJE_PART_TYPE_RECTANGLE = 1,
+   EDJE_PART_TYPE_TEXT      = 2,
+   EDJE_PART_TYPE_IMAGE     = 3,
+   EDJE_PART_TYPE_SWALLOW   = 4,
+   EDJE_PART_TYPE_TEXTBLOCK = 5,
+   EDJE_PART_TYPE_GRADIENT  = 6,
+   EDJE_PART_TYPE_GROUP     = 7,
+   EDJE_PART_TYPE_BOX       = 8,
+   EDJE_PART_TYPE_TABLE     = 9,
+   EDJE_PART_TYPE_EXTERNAL  = 10,
+   EDJE_PART_TYPE_LAST      = 11
+} Edje_Part_Type;
+
+typedef enum _Edje_Text_Effect
+{
+   EDJE_TEXT_EFFECT_NONE                = 0,
+   EDJE_TEXT_EFFECT_PLAIN               = 1,
+   EDJE_TEXT_EFFECT_OUTLINE             = 2,
+   EDJE_TEXT_EFFECT_SOFT_OUTLINE        = 3,
+   EDJE_TEXT_EFFECT_SHADOW              = 4,
+   EDJE_TEXT_EFFECT_SOFT_SHADOW         = 5,
+   EDJE_TEXT_EFFECT_OUTLINE_SHADOW      = 6,
+   EDJE_TEXT_EFFECT_OUTLINE_SOFT_SHADOW = 7,
+   EDJE_TEXT_EFFECT_FAR_SHADOW          = 8,
+   EDJE_TEXT_EFFECT_FAR_SOFT_SHADOW     = 9,
+   EDJE_TEXT_EFFECT_GLOW                = 10,
+   EDJE_TEXT_EFFECT_LAST                = 11
+} Edje_Text_Effect;
+
+typedef enum _Edje_Action_Type
+{
+   EDJE_ACTION_TYPE_NONE          = 0,
+   EDJE_ACTION_TYPE_STATE_SET     = 1,
+   EDJE_ACTION_TYPE_ACTION_STOP   = 2,
+   EDJE_ACTION_TYPE_SIGNAL_EMIT   = 3,
+   EDJE_ACTION_TYPE_DRAG_VAL_SET  = 4,
+   EDJE_ACTION_TYPE_DRAG_VAL_STEP = 5,
+   EDJE_ACTION_TYPE_DRAG_VAL_PAGE = 6,
+   EDJE_ACTION_TYPE_SCRIPT        = 7,
+   EDJE_ACTION_TYPE_FOCUS_SET     = 8,
+   EDJE_ACTION_TYPE_LUA_SCRIPT    = 9,
+   EDJE_ACTION_TYPE_FOCUS_OBJECT  = 10,
+   EDJE_ACTION_TYPE_PARAM_COPY    = 11,
+   EDJE_ACTION_TYPE_PARAM_SET     = 12,
+   EDJE_ACTION_TYPE_LAST          = 13
+} Edje_Action_Type;
+
+typedef enum _Edje_Tween_Mode
+{
+   EDJE_TWEEN_MODE_NONE       = 0,
+   EDJE_TWEEN_MODE_LINEAR     = 1,
+   EDJE_TWEEN_MODE_SINUSOIDAL = 2,
+   EDJE_TWEEN_MODE_ACCELERATE = 3,
+   EDJE_TWEEN_MODE_DECELERATE = 4,
+   EDJE_TWEEN_MODE_LAST       = 5
+} Edje_Tween_Mode;
+
+enum _Edje_Cursor
+{
+   EDJE_CURSOR_MAIN,
+   EDJE_CURSOR_SELECTION_BEGIN,
+   EDJE_CURSOR_SELECTION_END
+   // more later
+};
+typedef enum _Edje_Cursor Edje_Cursor;
+
+typedef struct _Edje_Message_String           Edje_Message_String;
+typedef struct _Edje_Message_Int              Edje_Message_Int;
+typedef struct _Edje_Message_Float            Edje_Message_Float;
+typedef struct _Edje_Message_String_Set       Edje_Message_String_Set;
+typedef struct _Edje_Message_Int_Set          Edje_Message_Int_Set;
+typedef struct _Edje_Message_Float_Set        Edje_Message_Float_Set;
+typedef struct _Edje_Message_String_Int       Edje_Message_String_Int;
+typedef struct _Edje_Message_String_Float     Edje_Message_String_Float;
+typedef struct _Edje_Message_String_Int_Set   Edje_Message_String_Int_Set;
+typedef struct _Edje_Message_String_Float_Set Edje_Message_String_Float_Set;
+
+struct _Edje_Message_String
+{
+   char *str;
+};
+
+struct _Edje_Message_Int
+{
+   int val;
+};
+
+struct _Edje_Message_Float
+{
+   double val;
+};
+
+struct _Edje_Message_String_Set
+{
+   int count;
+   char *str[1];
+};
+
+struct _Edje_Message_Int_Set
+{
+   int count;
+   int val[1];
+};
+
+struct _Edje_Message_Float_Set
+{
+   int count;
+   double val[1];
+};
+
+struct _Edje_Message_String_Int
+{
+   char *str;
+   int val;
+};
+
+struct _Edje_Message_String_Float
+{
+   char *str;
+   double val;
+};
+
+struct _Edje_Message_String_Int_Set
+{
+   char *str;
+   int count;
+   int val[1];
+};
+
+struct _Edje_Message_String_Float_Set
+{
+   char *str;
+   int count;
+   double val[1];
+};
+
+enum
+{
+   EDJE_DRAG_DIR_NONE = 0,
+     EDJE_DRAG_DIR_X = 1,
+     EDJE_DRAG_DIR_Y = 2,
+     EDJE_DRAG_DIR_XY = 3
+};
+
+enum
+{
+   EDJE_LOAD_ERROR_NONE = 0,
+     EDJE_LOAD_ERROR_GENERIC = 1,
+     EDJE_LOAD_ERROR_DOES_NOT_EXIST = 2,
+     EDJE_LOAD_ERROR_PERMISSION_DENIED = 3,
+     EDJE_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED = 4,
+     EDJE_LOAD_ERROR_CORRUPT_FILE = 5,
+     EDJE_LOAD_ERROR_UNKNOWN_FORMAT = 6,
+     EDJE_LOAD_ERROR_INCOMPATIBLE_FILE = 7,
+     EDJE_LOAD_ERROR_UNKNOWN_COLLECTION = 8,
+     EDJE_LOAD_ERROR_RECURSIVE_REFERENCE = 9
+};
+
+enum _Edje_External_Param_Type
+{
+  EDJE_EXTERNAL_PARAM_TYPE_INT,
+  EDJE_EXTERNAL_PARAM_TYPE_DOUBLE,
+  EDJE_EXTERNAL_PARAM_TYPE_STRING,
+  EDJE_EXTERNAL_PARAM_TYPE_BOOL,
+  EDJE_EXTERNAL_PARAM_TYPE_CHOICE,
+  EDJE_EXTERNAL_PARAM_TYPE_MAX
+};
+typedef enum _Edje_External_Param_Type Edje_External_Param_Type;
+
+EAPI const char *edje_external_param_type_str(Edje_External_Param_Type type) EINA_PURE;
+
+struct _Edje_External_Param
+{
+   const char *name;
+   Edje_External_Param_Type type;
+   // XXX these could be in a union, but eet doesn't support them (or does it?)
+   int i; /**< used by both integer and boolean */
+   double d;
+   const char *s; /**< used by both string and choice */
+};
+typedef struct _Edje_External_Param Edje_External_Param;
+
+#define EDJE_EXTERNAL_INT_UNSET 0xffffffff
+#define EDJE_EXTERNAL_DOUBLE_UNSET HUGE_VAL
+
+struct _Edje_External_Param_Info
+{
+   const char *name;
+   Edje_External_Param_Type type;
+   union
+     {
+        struct
+          {
+             int def, min, max, step;
+          } i;
+        struct
+          {
+             double def, min, max, step;
+          } d;
+        struct
+          {
+             const char *def;
+             const char *accept_fmt;
+             const char *deny_fmt;
+          } s;
+        struct
+          {
+             int def;
+             const char *false_str;
+             const char *true_str;
+          } b;
+       struct
+         {
+            const char *def;
+            const char **choices; /* NULL terminated array */
+         } c;
+     } info;
+};
+typedef struct _Edje_External_Param_Info Edje_External_Param_Info;
+
+#define EDJE_EXTERNAL_PARAM_INFO_INT_FULL(name, def, min, max, step) \
+  {name, EDJE_EXTERNAL_PARAM_TYPE_INT, {.i = {def, min, max, step}}}
+#define EDJE_EXTERNAL_PARAM_INFO_DOUBLE_FULL(name, def, min, max, step) \
+  {name, EDJE_EXTERNAL_PARAM_TYPE_DOUBLE, {.d = {def, min, max, step}}}
+#define EDJE_EXTERNAL_PARAM_INFO_STRING_FULL(name, def, accept, deny) \
+  {name, EDJE_EXTERNAL_PARAM_TYPE_STRING, {.s = {def, accept, deny}}}
+#define EDJE_EXTERNAL_PARAM_INFO_BOOL_FULL(name, def, false_str, true_str) \
+  {name, EDJE_EXTERNAL_PARAM_TYPE_BOOL, {.b = {def, false_str, true_str}}}
+#define EDJE_EXTERNAL_PARAM_INFO_CHOICE_FULL(name, def, choices) \
+  {name, EDJE_EXTERNAL_PARAM_TYPE_CHOICE, {.c = {def, choices}}}
+
+#define EDJE_EXTERNAL_PARAM_INFO_INT_DEFAULT(name, def) \
+   EDJE_EXTERNAL_PARAM_INFO_INT_FULL(name, def, EDJE_EXTERNAL_INT_UNSET, EDJE_EXTERNAL_INT_UNSET, EDJE_EXTERNAL_INT_UNSET)
+#define EDJE_EXTERNAL_PARAM_INFO_DOUBLE_DEFAULT(name, def) \
+   EDJE_EXTERNAL_PARAM_INFO_DOUBLE_FULL(name, def, EDJE_EXTERNAL_DOUBLE_UNSET, EDJE_EXTERNAL_DOUBLE_UNSET, EDJE_EXTERNAL_DOUBLE_UNSET)
+#define EDJE_EXTERNAL_PARAM_INFO_STRING_DEFAULT(name, def) \
+   EDJE_EXTERNAL_PARAM_INFO_STRING_FULL(name, def, NULL, NULL)
+#define EDJE_EXTERNAL_PARAM_INFO_BOOL_DEFAULT(name, def) \
+   EDJE_EXTERNAL_PARAM_INFO_BOOL_FULL(name, def, "false", "true")
+
+#define EDJE_EXTERNAL_PARAM_INFO_INT(name) \
+   EDJE_EXTERNAL_PARAM_INFO_INT_DEFAULT(name, 0)
+#define EDJE_EXTERNAL_PARAM_INFO_DOUBLE(name) \
+   EDJE_EXTERNAL_PARAM_INFO_DOUBLE_DEFAULT(name, 0.0)
+#define EDJE_EXTERNAL_PARAM_INFO_STRING(name) \
+   EDJE_EXTERNAL_PARAM_INFO_STRING_DEFAULT(name, NULL)
+#define EDJE_EXTERNAL_PARAM_INFO_BOOL(name) \
+   EDJE_EXTERNAL_PARAM_INFO_BOOL_DEFAULT(name, 0)
+
+#define EDJE_EXTERNAL_PARAM_INFO_SENTINEL {NULL, 0, {.s = {NULL, NULL, NULL}}}
+
+/**
+ * @struct _Edje_External_Type information about an external type to be used.
+ *
+ * This structure provides information on how to display and modify a
+ * third party Evas_Object in Edje.
+ *
+ * Some function pointers are not really used by Edje, but provide
+ * means for Edje users to better interact with such objects. For
+ * instance, an editor may use label_get() and icon_get() to list all
+ * registered external types.
+ *
+ * @note The function pointers provided in this structure must check
+ *       for errors and invalid or out-of-range values as for
+ *       performance reasons Edje will not enforce hints provided as
+ *       #Edje_External_Param_Info in the member parameters_info.
+ */
+struct _Edje_External_Type
+{
+#define EDJE_EXTERNAL_TYPE_ABI_VERSION (2)
+  unsigned int abi_version; /**< always use:
+                            *  - #EDJE_EXTERNAL_TYPE_ABI_VERSION to declare.
+                            *  - edje_external_type_abi_version_get() to check.
+                            */
+
+  const char *module;
+  const char *module_name;
+  Evas_Object *(*add) (void *data, Evas *evas, Evas_Object *parent, const Eina_List *params, const char *part_name); /**< creates the object to be used by Edje as the part */
+  void (*state_set) (void *data, Evas_Object *obj, const void *from_params, const void *to_params, float pos); /**< called upon state changes, including the initial "default" 0.0 state. Parameters are the value returned by params_parse() */
+  void (*signal_emit) (void *data, Evas_Object *obj, const char *emission, const char *source); /**< Feed a signal emitted with emission originally set as part_name:signal to this object (without the "part_name:" prefix) */
+  Eina_Bool (*param_set) (void *data, Evas_Object *obj, const Edje_External_Param *param); /**< dynamically change a parameter of this external, called by scripts and user code. Returns @c EINA_TRUE on success */
+  Eina_Bool (*param_get) (void *data, const Evas_Object *obj, Edje_External_Param *param); /**< dynamically fetch a parameter of this external, called by scripts and user code. Returns @c EINA_TRUE on success. (Must check parameter name and type!) */
+  void *(*params_parse) (void *data, Evas_Object *obj, const Eina_List *params); /**< parses the list of parameters, converting into a friendly representation. Used with state_set() */
+  void (*params_free) (void *params); /**< free parameters parsed with params_parse() */
+
+  /* The following callbacks aren't used by Edje itself, but by UI design
+     tools instead */
+  const char *(*label_get) (void *data);
+  const char *(*description_get) (void *data);
+  Evas_Object *(*icon_add) (void *data, Evas *e);
+  Evas_Object *(*preview_add) (void *data, Evas *e);
+  const char *(*translate) (void *data, const char *orig); /**< called to translate parameters_info name properties for use in user interfaces that support internationalization (i18n) */
+
+  Edje_External_Param_Info *parameters_info;
+
+  void *data;
+};
+typedef struct _Edje_External_Type Edje_External_Type;
+
+
+struct _Edje_External_Type_Info
+{
+   const char *name;
+   const Edje_External_Type *info;
+};
+typedef struct _Edje_External_Type_Info Edje_External_Type_Info;
+
+
+
+typedef void (*Edje_Signal_Cb) (void *data, Evas_Object *obj, const char *emission, const char *source);
+typedef void (*Edje_Text_Change_Cb) (void *data, Evas_Object *obj, const char *part);
+typedef void (*Edje_Message_Handler_Cb) (void *data, Evas_Object *obj, Edje_Message_Type type, int id, void *msg);
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+   /* edje_main.c */
+   EAPI int          edje_init                       (void);
+   EAPI int          edje_shutdown                   (void);
+
+   /* edje_program.c */
+   EAPI void         edje_frametime_set              (double t);
+   EAPI double       edje_frametime_get              (void);
+
+   /* edje_util.c */
+   EAPI void         edje_freeze                     (void);
+   EAPI void         edje_thaw                       (void);
+   EAPI void         edje_fontset_append_set         (const char *fonts);
+   EAPI const char  *edje_fontset_append_get         (void);
+   EAPI void         edje_scale_set                  (double scale);
+   EAPI double       edje_scale_get                  (void);
+   EAPI Eina_Bool    edje_object_scale_set           (Evas_Object *obj, double scale);
+   EAPI double       edje_object_scale_get           (const Evas_Object *obj);
+
+   /* edje_load.c */
+   EAPI Eina_List   *edje_file_collection_list       (const char *file);
+   EAPI void         edje_file_collection_list_free  (Eina_List *lst);
+   EAPI Eina_Bool    edje_file_group_exists          (const char *file, const char *glob);
+   EAPI char        *edje_file_data_get              (const char *file, const char *key);
+   EAPI void         edje_file_cache_set             (int count);
+   EAPI int          edje_file_cache_get             (void);
+   EAPI void         edje_file_cache_flush           (void);
+   EAPI void         edje_collection_cache_set       (int count);
+   EAPI int          edje_collection_cache_get       (void);
+   EAPI void         edje_collection_cache_flush     (void);
+
+
+   /* edje_util.c */
+   EAPI Eina_Bool    edje_color_class_set(const char *color_class, int r, int g, int b, int a, int r2, int g2, int b2, int a2, int r3, int g3, int b3, int a3);
+   EAPI Eina_Bool    edje_color_class_get(const char *color_class, int *r, int *g, int *b, int *a, int *r2, int *g2, int *b2, int *a2, int *r3, int *g3, int *b3, int *a3);
+   EAPI void         edje_color_class_del(const char *color_class);
+   EAPI Eina_List *  edje_color_class_list(void);
+   EAPI Eina_Bool    edje_text_class_set(const char *text_class, const char *font, Evas_Font_Size size);
+   EAPI void         edje_text_class_del(const char *text_class);
+   EAPI Eina_List *  edje_text_class_list(void);
+   EAPI void         edje_extern_object_min_size_set (Evas_Object *obj, Evas_Coord minw, Evas_Coord minh);
+   EAPI void         edje_extern_object_max_size_set (Evas_Object *obj, Evas_Coord maxw, Evas_Coord maxh);
+   EAPI void         edje_extern_object_aspect_set(Evas_Object *obj, Edje_Aspect_Control aspect, Evas_Coord aw, Evas_Coord ah);
+   EAPI void         edje_box_layout_register(const char *name, Evas_Object_Box_Layout func, void *(*layout_data_get)(void *), void (*layout_data_free)(void *), void (*free_data)(void *), void *data);
+
+   /* edje_smart.c */
+   EAPI Evas_Object *edje_object_add                 (Evas *evas);
+
+   /* edje_util.c */
+   EAPI const char  *edje_object_data_get            (const Evas_Object *obj, const char *key);
+
+   /* edje_load.c */
+   EAPI Eina_Bool    edje_object_file_set            (Evas_Object *obj, const char *file, const char *group);
+   EAPI void         edje_object_file_get            (const Evas_Object *obj, const char **file, const char **group);
+   EAPI int          edje_object_load_error_get      (const Evas_Object *obj);
+   EAPI const char  *edje_load_error_str             (int error);
+
+   /* edje_util.c */
+   EAPI Eina_Bool    edje_object_preload             (Evas_Object *obj, Eina_Bool cancel);
+
+   /* edje_program.c */
+   EAPI void         edje_object_signal_callback_add (Evas_Object *obj, const char *emission, const char *source, Edje_Signal_Cb func, void *data);
+   EAPI void        *edje_object_signal_callback_del (Evas_Object *obj, const char *emission, const char *source, Edje_Signal_Cb func);
+   EAPI void         edje_object_signal_emit         (Evas_Object *obj, const char *emission, const char *source);
+   EAPI void         edje_object_play_set            (Evas_Object *obj, Eina_Bool play);
+   EAPI Eina_Bool    edje_object_play_get            (const Evas_Object *obj);
+   EAPI void         edje_object_animation_set       (Evas_Object *obj, Eina_Bool on);
+   EAPI Eina_Bool    edje_object_animation_get       (const Evas_Object *obj);
+
+   /* edje_util.c */
+   EAPI int          edje_object_freeze              (Evas_Object *obj);
+   EAPI int          edje_object_thaw                (Evas_Object *obj);
+   EAPI Eina_Bool    edje_object_color_class_set     (Evas_Object *obj, const char *color_class, int r, int g, int b, int a, int r2, int g2, int b2, int a2, int r3, int g3, int b3, int a3);
+   EAPI Eina_Bool     edje_object_color_class_get    (const Evas_Object *o, const char *color_class, int *r, int *g, int *b, int *a, int *r2, int *g2, int *b2, int *a2, int *r3, int *g3, int *b3, int *a3);
+   EAPI void         edje_object_color_class_del     (Evas_Object *obj, const char *color_class);
+   EAPI Eina_Bool    edje_object_text_class_set      (Evas_Object *obj, const char *text_class, const char *font, Evas_Font_Size size);
+   EAPI void         edje_object_size_min_get        (const Evas_Object *obj, Evas_Coord *minw, Evas_Coord *minh);
+   EAPI void         edje_object_size_max_get        (const Evas_Object *obj, Evas_Coord *maxw, Evas_Coord *maxh);
+   EAPI void         edje_object_calc_force          (Evas_Object *obj);
+   EAPI void         edje_object_size_min_calc       (Evas_Object *obj, Evas_Coord *minw, Evas_Coord *minh);
+   EAPI Eina_Bool    edje_object_parts_extends_calc(Evas_Object *obj, Evas_Coord *x, Evas_Coord *y, Evas_Coord *w, Evas_Coord *h);
+   EAPI void         edje_object_size_min_restricted_calc(Evas_Object *obj, Evas_Coord *minw, Evas_Coord *minh, Evas_Coord restrictedw, Evas_Coord restrictedh);
+   EAPI Eina_Bool    edje_object_part_exists         (const Evas_Object *obj, const char *part);
+   EAPI const Evas_Object *edje_object_part_object_get     (const Evas_Object *obj, const char *part);
+   EAPI Eina_Bool    edje_object_part_geometry_get   (const Evas_Object *obj, const char *part, Evas_Coord *x, Evas_Coord *y, Evas_Coord *w, Evas_Coord *h);
+   EAPI void         edje_object_text_change_cb_set  (Evas_Object *obj, Edje_Text_Change_Cb func, void *data);
+   EAPI Eina_Bool    edje_object_part_text_set       (Evas_Object *obj, const char *part, const char *text);
+   EAPI const char  *edje_object_part_text_get       (const Evas_Object *obj, const char *part);
+   EAPI Eina_Bool    edje_object_part_text_unescaped_set(Evas_Object *obj, const char *part, const char *text_to_escape);
+   EAPI char        *edje_object_part_text_unescaped_get(const Evas_Object *obj, const char *part);
+
+   EAPI const char      *edje_object_part_text_selection_get           (const Evas_Object *obj, const char *part);
+   EAPI void             edje_object_part_text_select_none             (const Evas_Object *obj, const char *part);
+   EAPI void             edje_object_part_text_select_all              (const Evas_Object *obj, const char *part);
+   EAPI void             edje_object_part_text_insert                  (Evas_Object *obj, const char *part, const char *text);
+   EAPI void             edje_object_item_provider_set                 (Evas_Object *obj, Evas_Object *(*func) (void *data, Evas_Object *obj, const char *part, const char *item), void *data);
+   EAPI const Eina_List *edje_object_part_text_anchor_list_get         (const Evas_Object *obj, const char *part);
+   EAPI const Eina_List *edje_object_part_text_anchor_geometry_get     (const Evas_Object *obj, const char *part, const char *anchor);
+   EAPI const Eina_List *edje_object_part_text_item_list_get           (const Evas_Object *obj, const char *part);
+   EAPI Eina_Bool        edje_object_part_text_item_geometry_get       (const Evas_Object *obj, const char *part, const char *item, Evas_Coord *cx, Evas_Coord *cy, Evas_Coord *cw, Evas_Coord *ch);
+   EAPI void             edje_object_part_text_cursor_geometry_get     (const Evas_Object *obj, const char *part, Evas_Coord *x, Evas_Coord *y, Evas_Coord *w, Evas_Coord *h);
+   EAPI void             edje_object_part_text_select_allow_set        (const Evas_Object *obj, const char *part, Eina_Bool allow);
+   EAPI void             edje_object_part_text_select_abort            (const Evas_Object *obj, const char *part);
+   EAPI void             edje_object_part_text_select_begin            (const Evas_Object *obj, const char *part);
+   EAPI void             edje_object_part_text_select_extend           (const Evas_Object *obj, const char *part);
+       
+   EAPI Eina_Bool        edje_object_part_text_cursor_next(const Evas_Object *obj, const char *part, Edje_Cursor cur);
+   EAPI Eina_Bool        edje_object_part_text_cursor_prev(const Evas_Object *obj, const char *part, Edje_Cursor cur);
+   EAPI Eina_Bool        edje_object_part_text_cursor_up(const Evas_Object *obj, const char *part, Edje_Cursor cur);
+   EAPI Eina_Bool        edje_object_part_text_cursor_down(const Evas_Object *obj, const char *part, Edje_Cursor cur);
+   EAPI void             edje_object_part_text_cursor_begin_set(const Evas_Object *obj, const char *part, Edje_Cursor cur);
+   EAPI void             edje_object_part_text_cursor_end_set(const Evas_Object *obj, const char *part, Edje_Cursor cur);
+   EAPI void             edje_object_part_text_cursor_copy(const Evas_Object *obj, const char *part, Edje_Cursor src, Edje_Cursor dst);
+   EAPI void             edje_object_part_text_cursor_line_begin_set(const Evas_Object *obj, const char *part, Edje_Cursor cur);
+   EAPI void             edje_object_part_text_cursor_line_end_set(const Evas_Object *obj, const char *part, Edje_Cursor cur);
+   EAPI Eina_Bool        edje_object_part_text_cursor_is_format_get(const Evas_Object *obj, const char *part, Edje_Cursor cur);
+   EAPI Eina_Bool        edje_object_part_text_cursor_is_visible_format_get(const Evas_Object *obj, const char *part, Edje_Cursor cur);
+   EAPI const char      *edje_object_part_text_cursor_content_get(const Evas_Object *obj, const char *part, Edje_Cursor cur);
+
+   EAPI Eina_Bool    edje_object_part_swallow        (Evas_Object *obj, const char *part, Evas_Object *obj_swallow);
+   EAPI void         edje_object_part_unswallow      (Evas_Object *obj, Evas_Object *obj_swallow);
+   EAPI Evas_Object *edje_object_part_swallow_get    (const Evas_Object *obj, const char *part);
+   EAPI const char  *edje_object_part_state_get      (const Evas_Object *obj, const char *part, double *val_ret);
+   EAPI int          edje_object_part_drag_dir_get   (const Evas_Object *obj, const char *part);
+   EAPI Eina_Bool    edje_object_part_drag_value_set (Evas_Object *obj, const char *part, double dx, double dy);
+   EAPI Eina_Bool    edje_object_part_drag_value_get (const Evas_Object *obj, const char *part, double *dx, double *dy);
+   EAPI Eina_Bool    edje_object_part_drag_size_set  (Evas_Object *obj, const char *part, double dw, double dh);
+   EAPI Eina_Bool    edje_object_part_drag_size_get  (const Evas_Object *obj, const char *part, double *dw, double *dh);
+   EAPI Eina_Bool    edje_object_part_drag_step_set  (Evas_Object *obj, const char *part, double dx, double dy);
+   EAPI Eina_Bool    edje_object_part_drag_step_get  (const Evas_Object *obj, const char *part, double *dx, double *dy);
+   EAPI Eina_Bool    edje_object_part_drag_page_set  (Evas_Object *obj, const char *part, double dx, double dy);
+   EAPI Eina_Bool    edje_object_part_drag_page_get  (const Evas_Object *obj, const char *part, double *dx, double *dy);
+   EAPI Eina_Bool    edje_object_part_drag_step      (Evas_Object *obj, const char *part, double dx, double dy);
+   EAPI Eina_Bool    edje_object_part_drag_page      (Evas_Object *obj, const char *part, double dx, double dy);
+
+   EAPI Evas_Object *edje_object_part_external_object_get(const Evas_Object *obj, const char *part);
+   EAPI Eina_Bool    edje_object_part_external_param_set(Evas_Object *obj, const char *part, const Edje_External_Param *param);
+   EAPI Eina_Bool    edje_object_part_external_param_get(const Evas_Object *obj, const char *part, Edje_External_Param *param);
+   EAPI Edje_External_Param_Type edje_object_part_external_param_type_get(const Evas_Object *obj, const char *part, const char *param);
+
+   EAPI Eina_Bool    edje_object_part_box_append     (Evas_Object *obj, const char *part, Evas_Object *child);
+   EAPI Eina_Bool    edje_object_part_box_prepend    (Evas_Object *obj, const char *part, Evas_Object *child);
+   EAPI Eina_Bool    edje_object_part_box_insert_before (Evas_Object *obj, const char *part, Evas_Object *child, const Evas_Object *reference);
+   EAPI Eina_Bool    edje_object_part_box_insert_at  (Evas_Object *obj, const char *part, Evas_Object *child, unsigned int pos);
+   EAPI Evas_Object *edje_object_part_box_remove     (Evas_Object *obj, const char *part, Evas_Object *child);
+   EAPI Evas_Object *edje_object_part_box_remove_at  (Evas_Object *obj, const char *part, unsigned int pos);
+   EAPI Eina_Bool    edje_object_part_box_remove_all (Evas_Object *obj, const char *part, Eina_Bool clear);
+   EAPI Evas_Object *edje_object_part_table_child_get(Evas_Object *obj, const char *part, unsigned int col, unsigned int row);
+   EAPI Eina_Bool    edje_object_part_table_pack     (Evas_Object *obj, const char *part, Evas_Object *child_obj, unsigned short col, unsigned short row, unsigned short colspan, unsigned short rowspan);
+   EAPI Eina_Bool    edje_object_part_table_unpack   (Evas_Object *obj, const char *part, Evas_Object *child_obj);
+   EAPI Eina_Bool    edje_object_part_table_col_row_size_get (const Evas_Object *obj, const char *part, int *cols, int *rows);
+   EAPI Eina_Bool    edje_object_part_table_clear    (Evas_Object *obj, const char *part, Eina_Bool clear);
+
+   /* edje_message_queue.c */
+   EAPI void         edje_object_message_send           (Evas_Object *obj, Edje_Message_Type type, int id, void *msg);
+   EAPI void         edje_object_message_handler_set    (Evas_Object *obj, Edje_Message_Handler_Cb func, void *data);
+   EAPI void         edje_object_message_signal_process (Evas_Object *obj);
+
+   EAPI void         edje_message_signal_process        (void);
+
+   /* edje_external.c */
+   EAPI Eina_Bool edje_external_type_register(const char *type_name, const Edje_External_Type *type_info);
+   EAPI Eina_Bool edje_external_type_unregister(const char *type_name);
+   
+   EAPI void      edje_external_type_array_register(const Edje_External_Type_Info *array);
+   EAPI void      edje_external_type_array_unregister(const Edje_External_Type_Info *array);
+   
+   EAPI unsigned int edje_external_type_abi_version_get(void) EINA_CONST;
+   
+   
+   EAPI Eina_Iterator *edje_external_iterator_get(void);
+   EAPI Edje_External_Param *edje_external_param_find(const Eina_List *params, const char *key);
+   EAPI Eina_Bool edje_external_param_int_get(const Eina_List *params, const char *key, int *ret);
+   EAPI Eina_Bool edje_external_param_double_get(const Eina_List *params, const char *key, double *ret);
+   EAPI Eina_Bool edje_external_param_string_get(const Eina_List *params, const char *key, const char **ret);
+   EAPI Eina_Bool edje_external_param_bool_get(const Eina_List *params, const char *key, Eina_Bool *ret);
+   EAPI Eina_Bool edje_external_param_choice_get(const Eina_List *params, const char *key, const char **ret);
+   EAPI const Edje_External_Param_Info *edje_external_param_info_get(const char *type_name);
+   EAPI const Edje_External_Type *edje_external_type_get(const char *type_name);
+
+   /* edje_module.c */
+   EAPI Eina_Bool edje_module_load(const char *module);
+   EAPI const Eina_List *edje_available_modules_get(void);
+
+   /* perspective info for maps inside edje objects */
+   typedef struct _Edje_Perspective Edje_Perspective;
+   
+   EAPI Edje_Perspective       *edje_perspective_new            (Evas *e);
+   EAPI void                    edje_perspective_free           (Edje_Perspective *ps);
+   EAPI void                    edje_perspective_set            (Edje_Perspective *ps, Evas_Coord px, Evas_Coord py, Evas_Coord z0, Evas_Coord foc);
+   EAPI void                    edje_perspective_global_set     (Edje_Perspective *ps, Eina_Bool global);
+   EAPI Eina_Bool               edje_perspective_global_get     (const Edje_Perspective *ps);
+   EAPI const Edje_Perspective *edje_evas_global_perspective_get(const Evas *e);
+   EAPI void                    edje_object_perspective_set     (Evas_Object *obj, Edje_Perspective *ps);
+   EAPI const Edje_Perspective *edje_object_perspective_get     (const Evas_Object *obj);
+   
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/lib/Edje_Edit.h b/src/lib/Edje_Edit.h
new file mode 100644 (file)
index 0000000..a0d0a82
--- /dev/null
@@ -0,0 +1,3266 @@
+#ifndef _EDJE_EDIT_H
+#define _EDJE_EDIT_H
+
+#include <Edje.h>
+
+#ifdef EAPI
+# undef EAPI
+#endif
+
+#ifdef _WIN32
+# ifdef EFL_EDJE_BUILD
+#  ifdef DLL_EXPORT
+#   define EAPI __declspec(dllexport)
+#  else
+#   define EAPI
+#  endif /* ! DLL_EXPORT */
+# else
+#  define EAPI __declspec(dllimport)
+# endif /* ! EFL_EDJE_BUILD */
+#else
+# ifdef __GNUC__
+#  if __GNUC__ >= 4
+#   define EAPI __attribute__ ((visibility("default")))
+#  else
+#   define EAPI
+#  endif
+# else
+#  define EAPI
+# endif
+#endif
+
+
+typedef enum _Edje_Edit_Image_Comp
+{
+   EDJE_EDIT_IMAGE_COMP_RAW,
+   EDJE_EDIT_IMAGE_COMP_USER,
+   EDJE_EDIT_IMAGE_COMP_COMP,
+   EDJE_EDIT_IMAGE_COMP_LOSSY
+} Edje_Edit_Image_Comp;
+
+/**
+ * @file
+ * @brief Functions to deal with edje internal object. Don't use in standard
+ * situations. The use of any of the edje_edit_* functions can break your
+ * theme ability, remember that the program must be separated from the interface!
+ *
+ * The API can be used to query or set every part of an edje object in real time.
+ * You can manage every aspect of parts, part states, programs, script and whatever
+ * is contained in the edje file. For a reference of what all parameter means
+ * look at the complete @ref edcref.
+ *
+ * Don't forget to free all the strings and the lists returned by any edje_edit_*()
+ * functions using edje_edit_string_free() and edje_edit_string_list_free() when
+ * you don't need anymore.
+ *
+ * Example: print all the part in a loaded edje_object
+ * @code
+ *  Eina_List *parts, *l;
+ *  char *part;
+ *
+ *  parts = edje_edit_parts_list_get(edje_object);
+ *  EINA_LIST_FOREACH(parts, l, part)
+ *  {
+ *     printf("Part: %s\n", part);
+ *  }
+ *  edje_edit_string_list_free(parts);
+ * @endcode
+ *
+ * Example: Change the color of a rect inside an edje file
+ * @code
+ * Evas_Object *edje;
+ *
+ * edje = edje_edit_object_add(evas);
+ * edje_object_file_set(edje, "edj/file/name", "group to load");
+ * edje_edit_state_color_set(edje, "MyRectName", "default", 0.00, 255, 255, 0, 255);
+ * edje_edit_save(edje);
+ * @endcode
+ *
+*/
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/******************************************************************************/
+/**************************   GENERAL API   ***********************************/
+/******************************************************************************/
+/** @name General API
+ *  General functions that don't fit in other cateories.
+ */ //@{
+
+/** Adds an editable Edje object to the canvas.
+ *
+ * An Edje_Edit object is, for the most part, a standard Edje object. Only
+ * difference is you can use the Edje_Edit API on them.
+ *
+ * @param e Evas canvas where to add the object.
+ *
+ * @return An Evas_Object of type Edje_Edit, or NULL if an error occurred.
+ */
+EAPI Evas_Object * edje_edit_object_add(Evas *e);
+
+/** Free a generic Eina_List of (char *) allocated by an edje_edit_*_get() function.
+ *
+ * @param lst List of strings to free.
+ */
+EAPI void edje_edit_string_list_free(Eina_List *lst);
+
+/** Free a generic string (char *) allocated by an edje_edit_*_get() function.
+ *
+ * @param str String to free.
+ */
+EAPI void edje_edit_string_free(const char *str);
+
+/** Get the name of the program that compiled the edje file.
+  * Can be 'edje_cc' or 'edje_edit'
+  *
+  * @param obj Object being edited.
+  *
+  * @return Compiler stored in the Edje file
+  */
+EAPI const char * edje_edit_compiler_get(Evas_Object *obj);
+
+/** Save the modified edje object back to his file.
+ *
+ * Use this function when you are done with your editing, all the change made
+ * to the current loaded group will be saved back to the original file.
+ *
+ * @note Source for the whole file will be auto generated and will overwrite
+ * any previously stored source.
+ *
+ * @param obj Object to save back to the file it was loaded from.
+ *
+ * @return EINA_TRUE if succesful, EINA_FALSE otherwise.
+ *
+ * @todo Add a way to check what the error actually was, the way Edje Load does.
+ */
+EAPI Eina_Bool edje_edit_save(Evas_Object *obj);
+
+/** Saves every group back into the file.
+ *
+ * @param obj Object to save.
+ *
+ * @return EINA_TRUE if succesful, EINA_FALSE otherwise.
+ *
+ * @see edje_edit_save()
+ */
+EAPI Eina_Bool edje_edit_save_all(Evas_Object *obj);
+
+/** Print on standard output many information about the internal status
+ * of the edje object.
+ *
+ * This is probably only useful to debug.
+ *
+ * @param obj Object being edited.
+ */
+EAPI void edje_edit_print_internal_status(Evas_Object *obj);
+
+
+//@}
+/******************************************************************************/
+/**************************   GROUPS API   ************************************/
+/******************************************************************************/
+/** @name Groups API
+ *  Functions to deal with groups property (see @ref edcref).
+ */ //@{
+
+/** Create a new empty group in the given edje.
+ *
+ * If a group with the same name exist none is created.
+ *
+ * @param obj Object being edited.
+ * @param name Name of the new group.
+ *
+ * @return EINA_TRUE if succesfully added the group, EINA_FALSE if an error
+ * occurred or if a group with the same name exists.
+ */
+EAPI Eina_Bool edje_edit_group_add(Evas_Object *obj, const char *name);
+
+/** Delete the specified group from the given edje.
+ *
+ * You can only delete a currently unused group.
+ * All the parts and the programs inside the group will be deleted as well,
+ * but not image or font embedded in the edje.
+ *
+ * @param obj Object being edited.
+ * @param group_name Name of group to delete.
+ *
+ * @return EINA_TRUE if succesful, EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool edje_edit_group_del(Evas_Object *obj, const char *group_name);
+
+/** Check if a group with the given name exist in the edje.
+ *
+ * @param obj Object being edited.
+ * @param group Group name to check for.
+ *
+ * @return EINA_TRUE if group exists, EINA_FALSE if not.
+ */
+EAPI Eina_Bool edje_edit_group_exist(Evas_Object *obj, const char *group);
+
+/** Set a new name for the current open group.
+ *
+ * You can only rename a group that is currently loaded
+ * Note that the relative getter function don't exist as it doesn't make sense ;)
+ * @param obj Object being edited.
+ * @param new_name New name for the group.
+ *
+ * @return EINA_TRUE if succesful, EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool edje_edit_group_name_set(Evas_Object *obj, const char *new_name);
+
+/** Get the group minimum width.
+ *
+ * @param obj Object being edited.
+ *
+ * @return The minimum width set for the group. -1 if an error occurred.
+ */
+EAPI int edje_edit_group_min_w_get(Evas_Object *obj);
+
+/** Set the group minimum width.
+ *
+ * @param obj Object being edited.
+ * @param w New minimum width for the group.
+ */
+EAPI void edje_edit_group_min_w_set(Evas_Object *obj, int w);
+
+/** Get the group minimum height.
+ *
+ * @param obj Object being edited.
+ *
+ * @return The minimum height set for the group. -1 if an error occurred.
+ */
+EAPI int edje_edit_group_min_h_get(Evas_Object *obj);
+
+/** Set the group minimum height.
+ *
+ * @param obj Object being edited.
+ * @param h New minimum height for the group.
+ */
+EAPI void edje_edit_group_min_h_set(Evas_Object *obj, int h);
+
+/** Get the group maximum width.
+ *
+ * @param obj Object being edited.
+ *
+ * @return The maximum width set for the group. -1 if an error occurred.
+ */
+EAPI int edje_edit_group_max_w_get(Evas_Object *obj);
+
+/** Set the group maximum width.
+ *
+ * @param obj Object being edited.
+ * @param w New maximum width for the group.
+ */
+EAPI void edje_edit_group_max_w_set(Evas_Object *obj, int w);
+
+/** Get the group maximum height.
+ *
+ * @param obj Object being edited.
+ *
+ * @return The maximum height set for the group. -1 if an error occurred.
+ */
+EAPI int edje_edit_group_max_h_get(Evas_Object *obj);
+
+/** Set the group maximum height.
+ *
+ * @param obj Object being edited.
+ * @param h New maximum height for the group.
+ */
+EAPI void edje_edit_group_max_h_set(Evas_Object *obj, int h);
+
+
+//@}
+/******************************************************************************/
+/**************************   DATA API   **************************************/
+/******************************************************************************/
+/** @name Data API
+ *  Functions to deal with data embedded in the edje (see @ref edcref).
+ */ //@{
+
+/** Retrieves a list with the item names inside the data block.
+ *
+ * @param obj Object being edited.
+ *
+ * @return List of strings, each being a name entry in the global data block for the file.
+ */
+EAPI Eina_List * edje_edit_data_list_get(Evas_Object *obj);
+
+/** Create a new *global* data object in the given edje file.
+ *
+ * If another data entry with the same name exists, nothing is created and
+ * EINA_FALSE is returned.
+ *
+ * @param obj Object being edited.
+ * @param itemname Name for the new data entry.
+ * @param value Value for the new data entry.
+ *
+ * @return EINA_TRUE if succesful, EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool edje_edit_data_add(Evas_Object *obj, const char *itemname, const char *value);
+
+/** Delete the given data object from edje.
+ *
+ * @param obj Object being edited.
+ * @param itemname Data entry to remove from the global data block.
+ *
+ * @return EINA_TRUE on success, EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool edje_edit_data_del(Evas_Object *obj, const char *itemname);
+
+/** Get the data associated with the given itemname.
+ *
+ * @param obj Object being edited.
+ * @param itemname Name of the data entry to fetch the value for.
+ *
+ * @return Value of the given entry, or NULL if not found.
+ */
+EAPI const char * edje_edit_data_value_get(Evas_Object *obj, char *itemname);
+
+/** Set the data associated with the given itemname.
+ *
+ * @param obj Object being edited.
+ * @param itemname Name of data entry to change the value.
+ * @param value New value for the entry.
+ *
+ * @return EINA_TRUE on success, EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool edje_edit_data_value_set(Evas_Object *obj, const char *itemname, const char *value);
+
+/** Change the name of the given data object.
+ *
+ * @param obj Object being edited.
+ * @param itemname Data entry to rename.
+ * @param newname New name for the data entry.
+ *
+ * @return EINA_TRUE on success, EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool edje_edit_data_name_set(Evas_Object *obj, const char *itemname, const char *newname);
+
+/** Retrieves a list with the item names inside the data block at the group level.
+ *
+ * @param obj Object being edited.
+ *
+ * @return List of strings, each being a name entry in the data block for the group.
+ */
+EAPI Eina_List * edje_edit_group_data_list_get(Evas_Object *obj);
+
+/** Create a new data object in the given edje file *belonging to the current group*.
+ *
+ * If another data entry with the same name exists,
+ * nothing is created and EINA_FALSE is returned.
+ *
+ * @param obj Object being edited.
+ * @param itemname Name for the new data entry.
+ * @param value Value for the new data entry.
+ *
+ * @return EINA_TRUE if succesful, EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool edje_edit_group_data_add(Evas_Object *obj, const char *itemname, const char *value);
+
+/** Delete the given data object from the group.
+ *
+ * @param obj Object being edited.
+ * @param itemname Name of the data entry to remove.
+ *
+ * @return EINA_TRUE on success, EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool edje_edit_group_data_del(Evas_Object *obj, const char *itemname);
+
+/** Get the data associated with the given itemname.
+ *
+ * @param obj Object being edited.
+ * @param itemname Name of the data entry.
+ *
+ * @return Value of the data entry or NULL if not found.
+ */
+EAPI const char * edje_edit_group_data_value_get(Evas_Object *obj, char *itemname);
+
+/** Set the data associated with the given itemname.
+ *
+ * @param obj Object being edited.
+ * @param itemname Name of the data entry to set the value.
+ * @param value Value to set for the data entry.
+ *
+ * @return EINA_TRUE if succesful, EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool edje_edit_group_data_value_set(Evas_Object *obj, const char *itemname, const char *value);
+
+/** Change the name of the given data object.
+ *
+ * @param obj Object being edited.
+ * @param itemname Name of the data entry to rename.
+ * @param newname New name for the data entry.
+ *
+ * @return EINA_TRUE on success, EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool edje_edit_group_data_name_set(Evas_Object *obj, const char *itemname, const char *newname);
+
+
+//@}
+/******************************************************************************/
+/***********************   COLOR CLASSES API   ********************************/
+/******************************************************************************/
+/** @name Color Classes API
+ *  Functions to deal with Color Classes (see @ref edcref).
+ */ //@{
+
+/** Get the list of all the Color Classes in the given edje object.
+ *
+ * @param obj Object being edited.
+ *
+ * @return List of strings, each being one color class.
+ */
+EAPI Eina_List * edje_edit_color_classes_list_get(Evas_Object *obj);
+
+/** Create a new color class object in the given edje.
+ *
+ * If another class with the same name exists nothing is created and EINA_FALSE is returned.
+ *
+ * @param obj Object being edited.
+ * @param name Name for the new color class.
+ *
+ * @return EINA_TRUE if succesful, EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool edje_edit_color_class_add(Evas_Object *obj, const char *name);
+
+/** Delete the given class object from edje.
+ *
+ * @param obj Object being edited.
+ * @param name Color class to delete.
+ *
+ * @return EINA_TRUE if succesful, EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool edje_edit_color_class_del(Evas_Object *obj, const char *name);
+
+/** Get all the colors that compose the class.
+ *
+ * You can pass NULL to colors you are not intrested in.
+ *
+ * @param obj Object being edited.
+ * @param class_name Color class to fetch values.
+ * @param r Red component of main color.
+ * @param g Green component of main color.
+ * @param b Blue component of main color.
+ * @param a Alpha component of main color.
+ * @param r2 Red component of secondary color.
+ * @param g2 Green component of secondary color.
+ * @param b2 Blue component of secondary color.
+ * @param a2 Alpha component of secondary color.
+ * @param r3 Red component of tertiary color.
+ * @param g3 Green component of tertiary color.
+ * @param b3 Blue component of tertiary color.
+ * @param a3 Alpha component of tertiary color.
+ *
+ * @return EINA_TRUE if succesful, EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool edje_edit_color_class_colors_get(Evas_Object *obj, const char *class_name, int *r, int *g, int *b, int *a, int *r2, int *g2, int *b2, int *a2, int *r3, int *g3, int *b3, int *a3);
+
+/** Set the colors for the given color class.
+ *
+ * If you set a color to -1 it will not be touched.
+ *
+ * @param obj Object being edited.
+ * @param class_name Color class to fetch values.
+ * @param r Red component of main color.
+ * @param g Green component of main color.
+ * @param b Blue component of main color.
+ * @param a Alpha component of main color.
+ * @param r2 Red component of secondary color.
+ * @param g2 Green component of secondary color.
+ * @param b2 Blue component of secondary color.
+ * @param a2 Alpha component of secondary color.
+ * @param r3 Red component of tertiary color.
+ * @param g3 Green component of tertiary color.
+ * @param b3 Blue component of tertiary color.
+ * @param a3 Alpha component of tertiary color.
+ *
+ * @return EINA_TRUE if succesful, EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool edje_edit_color_class_colors_set(Evas_Object *obj, const char *class_name, int r, int g, int b, int a, int r2, int g2, int b2, int a2, int r3, int g3, int b3, int a3);
+
+/** Change the name of a color class.
+ *
+ * @param obj Object being edited.
+ * @param name Color class to rename.
+ * @param newname New name for the color class.
+ *
+ * @return EINA_TRUE if succesful, EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool edje_edit_color_class_name_set(Evas_Object *obj, const char *name, const char *newname);
+
+//@}
+
+/******************************************************************************/
+/**************************   TEXT STYLES *************************************/
+/******************************************************************************/
+/** @name Text styles API
+ *  Functions to deal with text styles (see @ref edcref).
+ */ //@{
+
+/** Get the list of all the text styles in the given edje object.
+ *
+ * @param obj Object being edited.
+ *
+ * @return List of strings, each being the name for a text style.
+ */
+EAPI Eina_List * edje_edit_styles_list_get(Evas_Object *obj);
+
+/** Create a new text style object in the given edje.
+ *
+ * If another style with the same name exists nothing is created and EINA_FALSE is returned.
+ *
+ * @param obj Object being edited.
+ * @param style Name for the new style.
+ *
+ * @return EINA_TRUE if succesful, EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool edje_edit_style_add(Evas_Object *obj, const char *style);
+
+/** Delete the given text style and all the child tags.
+ *
+ * @param obj Object being edited.
+ * @param style Style to delete.
+ */
+EAPI void edje_edit_style_del(Evas_Object *obj, const char *style);
+
+/** Get the list of all the tags name in the given text style.
+ *
+ * @param obj Object being edited.
+ * @param style Style to get the tags for.
+ *
+ * @return List of strings, each being one tag in the given style.
+ */
+EAPI Eina_List * edje_edit_style_tags_list_get(Evas_Object *obj, const char *style);
+
+/** Get the value of the given tag.
+ *
+ * @param obj Object being edited.
+ * @param style Style containing the tag being.
+ * @param tag Tag to get the value for.
+ *
+ * @param Value of the given tag.
+ */
+EAPI const char * edje_edit_style_tag_value_get(Evas_Object *obj, const char *style, const char *tag);
+
+/** Set the value of the given tag.
+ *
+ * @param obj Object being edited.
+ * @param style Style containing the tag to change.
+ * @param tag Name of the tag to set the value for.
+ * @param new_value Value for the tag.
+ */
+EAPI void edje_edit_style_tag_value_set(Evas_Object *obj, const char *style, const char *tag, const char *new_value);
+
+/** Set the name of the given tag.
+ *
+ * @param obj Object being edited.
+ * @param style Style containing the tag to rename.
+ * @param tag Tag to rename.
+ * @param new_name New name for the tag.
+ */
+EAPI void edje_edit_style_tag_name_set(Evas_Object *obj, const char *style, const char *tag, const char *new_name);
+
+/** Add a new tag to the given text style.
+ *
+ * If another tag with the same name exists nothing is created and EINA_FALSE is returned.
+ *
+ * @param obj Object being edited.
+ * @param style Style where to add the new tag.
+ * @param tag_name Name for the new tag.
+ *
+ * @return EINA_TRUE if succesful, EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool edje_edit_style_tag_add(Evas_Object *obj, const char *style, const char *tag_name);
+
+/** Delete the given tag.
+ *
+ * @param obj Object being edited.
+ * @param style Style from where to remove the tag.
+ * @param tag Tag to delete.
+ */
+EAPI void edje_edit_style_tag_del(Evas_Object *obj, const char *style, const char *tag);
+
+
+//@}
+/******************************************************************************/
+/************************   EXTERNALS API   ***********************************/
+/******************************************************************************/
+/** @name Externals API
+ *  Functions to deal with list of external modules (see @ref edcref).
+ */ //@{
+
+/** Get the list of all the externals requested in the given edje object.
+ *
+ * @param obj Object being edited.
+ *
+ * @return List of strings, each being an entry in the block of automatically loaded external modules.
+ */
+EAPI Eina_List * edje_edit_externals_list_get(Evas_Object *obj);
+
+/** Add an external module to be requested on edje load.
+ *
+ * @param obj Object being edited.
+ * @param external Name of the external module to add to the list of autoload.
+ *
+ * @return EINA_TRUE on success (or it was already there), EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool edje_edit_external_add(Evas_Object *obj, const char *external);
+
+/** Delete the given external from the list.
+ *
+ * @param obj Object being edited.
+ * @param external Name of the external module to remove from the autoload list.
+ *
+ * @return EINA_TRUE on success, EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool edje_edit_external_del(Evas_Object *obj, const char *external);
+
+
+//@}
+/******************************************************************************/
+/**************************   PARTS API   *************************************/
+/******************************************************************************/
+/** @name Parts API
+ *  Functions to deal with part objects (see @ref edcref).
+ */ //@{
+
+/** Get the list of all the parts in the given edje object.
+ *
+ * @param obj Object being edited.
+ *
+ * @return List of strings, each being the name for a part in the open group.
+ */
+EAPI Eina_List * edje_edit_parts_list_get(Evas_Object *obj);
+
+/** Create a new part in the given edje.
+ *
+ * If another part with the same name just exists nothing is created and EINA_FALSE is returned.
+ * Note that this function also create a default description for the part.
+ *
+ * @param obj Object being edited.
+ * @param name Name for the new part.
+ * @param type Type of the new part. See @ref edcref for more info on this.
+ *
+ * @return EINA_TRUE if succesful, EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool edje_edit_part_add(Evas_Object *obj, const char *name, Edje_Part_Type type);
+
+/** Create a new part of type EXTERNAL in the given edje.
+ *
+ * If another part with the same name just exists nothing is created and EINA_FALSE is returned.
+ * Note that this function also create a default description for the part.
+ *
+ * @param obj Object being edited.
+ * @param name Name for the new part.
+ * @param source The registered external type to use for this part.
+ *
+ * @return EINA_TRUE if succesful, EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool edje_edit_part_external_add(Evas_Object *obj, const char *name, const char *source);
+
+/** Delete the given part from the edje.
+ *
+ * All the reference to this part will be zeroed.
+ *
+ * @param obj Object being edited.
+ * @param part Name of part to delete.
+ *
+ * @return EINA_TRUE if succesful, EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool edje_edit_part_del(Evas_Object *obj, const char *part);
+
+/** Check if a part with the given name exist in the edje object.
+ *
+ * @param obj Object being edited.
+ * @param part Name of part to check for its existance.
+ *
+ * @return EINA_TRUE if the part exists, EINA_FALSE if not.
+ */
+EAPI Eina_Bool edje_edit_part_exist(Evas_Object *obj, const char *part);
+
+/** Get the name of part stacked above the one passed.
+ *
+ * @param obj Object being edited.
+ * @param part Name of part of which to check the one above.
+ *
+ * @return Name of the part above. NULL if an error occurred or if @p part is
+ * the topmost part in the group.
+ */
+EAPI const char * edje_edit_part_above_get(Evas_Object *obj, const char *part);
+
+/** Get the name of part stacked below the one passed.
+ *
+ * @param obj Object being edited.
+ * @param part Name of part of which to check the one below.
+ *
+ * @return Name of the part below. NULL if an error occurred or if @p part is
+ * the bottommost part in the group.
+ */
+EAPI const char * edje_edit_part_below_get(Evas_Object *obj, const char *part);
+
+/** Move the given part below the previous one.
+ *
+ * @param obj Object being edited.
+ * @param part Name of part to move one step below.
+ *
+ * @return EINA_TRUE if succesful, EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool edje_edit_part_restack_below(Evas_Object *obj, const char *part);
+
+/** Move the given part above the next one.
+ *
+ * @param obj Object being edited.
+ * @param part Name of part to move one step above.
+ *
+ * @return EINA_TRUE if succesful, EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool edje_edit_part_restack_above(Evas_Object *obj, const char *part);
+
+/** Set a new name for part.
+ *
+ * Note that the relative getter function don't exist as it don't make sense ;)
+ *
+ * @param obj Object being edited.
+ * @param part Name of part to rename.
+ * @param new_name New name for the given part.
+ *
+ * @return EINA_TRUE if succesful, EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool edje_edit_part_name_set(Evas_Object *obj, const char *part, const char *new_name);
+
+/**Add a new ttf font to the edje file.
+ * The newly created font will be available to all the groups in the edje, not only the current one.
+ * If font can't be load EINA_FALSE is returned.
+ */
+EAPI Eina_Bool          ///@return EINA_TRUE on success or EINA_FALSE on failure
+edje_edit_font_add(
+   Evas_Object *obj,       ///< The edje object
+   const char* path,       ///< The file path to load the ttf font from
+   const char* alias       ///< The file alias, or NULL to use filename
+);
+
+/**Remove a ttf font to the edje file.
+ * If font can't be deleted EINA_FALSE is returned.
+ */
+EAPI Eina_Bool         ///@return EINA_TRUE on success or EINA_FALSE on failure
+edje_edit_font_del(
+   Evas_Object *obj,       ///< The edje object
+   const char* alias       ///< The file alias
+);
+
+/**Get font name for a given part state. Remember to free the returned string using edje_edit_string_free().*/
+EAPI const char *          ///@return The name of the font used in the given part state
+edje_edit_state_font_get(
+   Evas_Object *obj,       ///< The edje object
+   const char *part,       ///< The name of the part
+   const char *state,      ///< The name of the 'part state' (ex. "default")
+   double value
+);
+
+/**Set font name for a given part state. */
+EAPI void
+edje_edit_state_font_set(
+   Evas_Object *obj,       ///< The edje object
+   const char *part,       ///< The name of the part
+   const char *state,      ///< The name of the 'part state' (ex. "default")
+   double value,
+   const char *font        ///< The name of the font to use in the given part state
+);
+
+/** Get the type of a part.
+ *
+ * @param obj Object being edited.
+ * @param part Name of part to get the type of.
+ *
+ * @return Type of the part. See @ref edcref for details.
+ */
+EAPI Edje_Part_Type edje_edit_part_type_get(Evas_Object *obj, const char *part);
+
+/** Get the clip_to part.
+ *
+ * @param obj Object being edited.
+ * @param part Name of the part whose clipper to get.
+ *
+ * @return Name of the part @p part is clipped to. NULL is returned on errors and if the part don't have a clip.
+ */
+EAPI const char * edje_edit_part_clip_to_get(Evas_Object *obj, const char *part);
+
+/** Set a part to clip part to.
+ *
+ * @param obj Object being edited.
+ * @param part Part to set the clipper to.
+ * @param clip_to Part to use as clipper, if NULL then the clipping value will be cancelled (unset clipping).
+ *
+ * @return EINA_TRUE if succesful, EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool edje_edit_part_clip_to_set(Evas_Object *obj, const char *part, const char *clip_to);
+
+/** Get the source of part.
+ *
+ * The meaning of this parameter varies depending on the type of the part.
+ * For GROUP parts, it's the name of another group in the Edje file which will
+ * be autoloaded and swallowed on this part.
+ * For TEXTBLOCK parts, it's the name of a group to be used for selection
+ * display under the text.
+ * For EXTERNAL parts, it's the name of the registered external widget to load
+ * and swallow on this part.
+ *
+ * @param obj Object being edited.
+ * @param part Part to get the source from.
+ *
+ * @return Content of the source parameter or NULL if nothing set or an error occurred.
+ */
+EAPI const char * edje_edit_part_source_get(Evas_Object *obj, const char *part);
+
+/** Set the source of part.
+ *
+ * @param obj Object being edited.
+ * @param part Part to set the source of.
+ * @param source Value for the source parameter.
+ *
+ * @return EINA_TRUE if succesful, EINA_FALSE otherwise.
+ *
+ * @see edje_edit_part_source_get()
+ *
+ * @note You can't change the source for EXTERNAL parts, it's akin to changing
+ * the type of the part.
+ *
+ * NOTE: This is not applied now. You must reload the edje to see the change.
+ */
+EAPI Eina_Bool edje_edit_part_source_set(Evas_Object *obj, const char *part, const char *source);
+
+/** Get the effect for a given part.
+ *
+ * Gets the effect used for parts of type TEXT. See @ref edcref for more details.
+ *
+ * @param obj Object being edited.
+ * @param part Part to get the effect of.
+ *
+ * @return The effect set for the part.
+ */
+EAPI Edje_Text_Effect edje_edit_part_effect_get(Evas_Object *obj, const char *part);
+
+/** Set the effect for a given part.
+ *
+ * @param obj Object being edited.
+ * @param part Part to set the effect to. Only makes sense on type TEXT.
+ * @param effect Effect to set for the part.
+ */
+EAPI void edje_edit_part_effect_set(Evas_Object *obj, const char *part, Edje_Text_Effect effect);
+
+/** Get the current selected state in part.
+ *
+ * @param obj Object being edited.
+ * @param part Part to get the selected state of.
+ * @param value Pointer to a double where the value of the state will be stored.
+ *
+ * @return The name of the currently selected state for the part.
+ */
+EAPI const char * edje_edit_part_selected_state_get(Evas_Object *obj, const char *part, double *value);
+
+/** Set the current state in part.
+ *
+ * @param obj Object being edited.
+ * @param part Part to set the state of.
+ * @param state Name of the state to set.
+ * @param value Value of the state.
+ *
+ * @return EINA_TRUE if succesful, EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool edje_edit_part_selected_state_set(Evas_Object *obj, const char *part, const char *state, double value);
+
+/** Get mouse_events for part.
+ *
+ * @param obj Object being edited.
+ * @param part Part to get if the mouse events is accepted.
+ *
+ * @return EINA_TRUE if succesful, EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool edje_edit_part_mouse_events_get(Evas_Object *obj, const char *part);
+
+/** Set mouse_events for part.
+ *
+ * @param obj Object being edited.
+ * @param part The part to set if the mouse events is accepted.
+ * @param mouse_events EINA_TRUE if part will accept mouse events, EINA_FALSE otherwise.
+ */
+EAPI void edje_edit_part_mouse_events_set(Evas_Object *obj, const char *part, Eina_Bool mouse_events);
+
+/** Get repeat_events for part.
+ *
+ * @param obj Object being edited.
+ * @param part Part to set if will pass all events to the other parts.
+ *
+ * @return EINA_TRUE if succesful, EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool edje_edit_part_repeat_events_get(Evas_Object *obj, const char *part);
+
+/** Set repeat_events for part.
+ *
+ * @param obj Object being edited.
+ * @param part Part to set if will repeat all the received mouse events to other parts.
+ * @param repeat_events EINA_TRUE if the events received will propagate to other parts, EINA_FALSE otherwise
+ */
+EAPI void edje_edit_part_repeat_events_set(Evas_Object *obj, const char *part, Eina_Bool repeat_events);
+
+/** Get ignore_flags for part.
+ *
+ * @param obj Object being edited.
+ * @param part Part to get which event_flags are being ignored.
+ *
+ * @return The Event flags set to the part.
+ */
+EAPI Evas_Event_Flags edje_edit_part_ignore_flags_get(Evas_Object *obj, const char *part);
+
+/** Set repeat_events for part.
+ *
+ * @param obj Object bein edited.
+ * @oaram part Part to set which event flags will be ignored
+ */
+EAPI void edje_edit_part_ignore_flags_set(Evas_Object *obj, const char *part, Evas_Event_Flags ignore_flags);
+
+/** Get horizontal dragable state for part.
+ *
+ * @param obj Object being edited.
+ * @param part Part to get if can be dragged horizontally;
+ *
+ * @return 1 (or -1) if the part can be dragged horizontally, 0 otherwise.
+ */
+EAPI int edje_edit_part_drag_x_get(Evas_Object *obj, const char *part);
+
+/** Set horizontal dragable state for part.
+ *
+ * @param obj Object being edited.
+ * @param part Part to set if should be dragged horizontally.
+ * @param drag 1 (or -1) if the part should be dragged horizontally, 0 otherwise.
+ */
+EAPI void edje_edit_part_drag_x_set(Evas_Object *obj, const char *part, int drag);
+
+/** Get vertical dragable state for part.
+ *
+ * @param obj Object being edited.
+ * @param part Part to get if can be dragged vertically.
+ *
+ * @return 1 (or - 1) if the part can be dragged vertically, 0 otherwise.
+ */
+EAPI int edje_edit_part_drag_y_get(Evas_Object *obj, const char *part);
+
+/** Set vertical dragable state for part.
+ *
+ * @param obj Object being edited.
+ * @param part Part to set if should be dragged vertically.
+ * @param drag 1 (or -1) of the part shpuld be dragged vertically, 0 otherwise.
+ */
+EAPI void edje_edit_part_drag_y_set(Evas_Object *obj, const char *part, int drag);
+
+/** Get horizontal dragable step for part.
+ *
+ * @param obj Object being edited.
+ * @param part Part to get the drag horizontal step value.
+ *
+ * @return The step value.
+ */
+EAPI int edje_edit_part_drag_step_x_get(Evas_Object *obj, const char *part);
+
+/** Set horizontal dragable state for part.
+ *
+ * @param obj Object being edited.
+ * @param part Part to set the drag horizontal step value.
+ * @param step The step the will be dragged.
+ */
+EAPI void edje_edit_part_drag_step_x_set(Evas_Object *obj, const char *part, int step);
+
+/** Get vertical dragable step for part.
+ *
+ * @param obj Object being edited.
+ * @param part Part to get the drag vertical step value.
+ *
+ * @return The step value.
+ */
+EAPI int edje_edit_part_drag_step_y_get(Evas_Object *obj, const char *part);
+
+/** Set vertical dragable state for part.
+ *
+ * @param obj Object being edited.
+ * @param part Part to set the drag vertical step value.
+ * @param step The step the will be dragged.
+ */
+EAPI void edje_edit_part_drag_step_y_set(Evas_Object *obj, const char *part, int step);
+
+/** Get horizontal dragable count for part.
+ *
+ * @param obj Object being edited.
+ * @param part Part to get the drag horizontal count value.
+ */
+EAPI int edje_edit_part_drag_count_x_get(Evas_Object *obj, const char *part);
+
+/** Set horizontal dragable count for part.
+ *
+ * @param obj Object being edited.
+ * @param part Part to set the drag horizontal count value.
+ * @aparam count The count value.
+ */
+EAPI void edje_edit_part_drag_count_x_set(Evas_Object *obj, const char *part, int count);
+
+/** Get vertical dragable count for part.
+ *
+ * @param obj Object being edited.
+ * @param part Part to get the drag vertical count value.
+ */
+EAPI int edje_edit_part_drag_count_y_get(Evas_Object *obj, const char *part);
+
+/** Set vertical dragable count for part.
+ *
+ * @param obj Object being edited.
+ * @param part Part to set the drag vertical count value.
+ * @aparam count The count value.
+ */
+EAPI void edje_edit_part_drag_count_y_set(Evas_Object *obj, const char *part, int count);
+
+/** Get the name of the part that is used as 'confine' for the given draggies.
+ *
+ * @param obj Object being edited.
+ * @param part Part to get the name that is used as 'confine' for the given draggies.
+ *
+ * @return The name of the confine part or NULL (if unset).
+ */
+EAPI const char * edje_edit_part_drag_confine_get(Evas_Object *obj, const char *part);
+
+/** Set the name of the part that is used as 'confine' for the given draggies.
+ *
+ * @param obj Object being edited.
+ * @param part Part to set the name that is used as 'confine' for the given draggies.
+ * @param confine The name of the confine part or NULL to unset confine.
+ */
+EAPI void edje_edit_part_drag_confine_set(Evas_Object *obj, const char *part, const char *confine);
+
+/** Get the name of the part that is used as the receiver of the drag event.
+ *
+ * @param obj Object being edited.
+ * @param part Part to get the name that is used as the receiver of the drag event.
+ *
+ * @return The name of the part that will receive events, or NULL (if unset).
+ */
+EAPI const char * edje_edit_part_drag_event_get(Evas_Object *obj, const char *part);
+
+/** Set the name of the part that will receive events from the given draggies.
+ *
+ * @param obj Object being edited.
+ * @param part Part to set the name that will receive events from the given draggies.
+ * @param event The name of the part that will receive events, or NULL to unset.
+ */
+EAPI void edje_edit_part_drag_event_set(Evas_Object *obj, const char *part, const char *event);
+
+
+//@}
+/******************************************************************************/
+/**************************   STATES API   ************************************/
+/******************************************************************************/
+/** @name States API
+ *  Functions to deal with part states (see @ref edcref).
+ */ //@{
+
+/** Get the list of all the states in the given part.
+ *
+ * @param obj Object being edited.
+ * @param part Part to get the states names list.
+ *
+ * @return An Eina_List* of string (char *)containing all the states names found
+ * in part, including the float value (ex: "default 0.00").
+ *
+ * Use edje_edit_string_list_free() when you don't need it anymore.
+ */
+EAPI Eina_List * edje_edit_part_states_list_get(Evas_Object *obj, const char *part);
+
+/** Set a new name for the given state in the given part.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @oaram state Name of the state to rename.
+ * @param value Value of the state to rename.
+ * @param new_name The new name for the state.
+ * @param new_value The new value for the state.
+ *
+ * @return EINA_TRUE if succesful, EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool edje_edit_state_name_set(Evas_Object *obj, const char *part, const char *state, double value, const char *new_name, double new_value);
+
+/** Create a new state to the give part.
+ *
+ * @param obj Object being edited.
+ * @param part Part to set the name of the new state.
+ * @param name Name for the new state (not including the state value).
+ * @param value The state value.
+ */
+EAPI void edje_edit_state_add(Evas_Object *obj, const char *part, const char *name, double value);
+
+/** Delete the given part state from the edje.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The current name of the state (not including the state value).
+ * @param value The state value.
+ */
+EAPI void edje_edit_state_del(Evas_Object *obj, const char *part, const char *state, double value);
+
+/** Check if a part state with the given name exist.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to check (not including the state value).
+ * @param value The state value.
+ *
+ * @return EINA_TRUE if the part state exist, EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool edje_edit_state_exist(Evas_Object *obj, const char *part, const char *state, double value);
+
+/** Copies the state @p from into @p to. If @p to doesn't exist it will be created.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param from State to copy from (not including state value).
+ * @param val_from The value of the state to copy from.
+ * @param to State to copy into (not including state value).
+ * @param val_to The value of the state to copy into.
+ *
+ * @return EINA_TRUE if succesful, EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool edje_edit_state_copy(Evas_Object *obj, const char *part, const char *from, double val_from, const char *to, double val_to);
+
+/** Get the 'rel1 relative X' value of state.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to get 'rel1 relative X' (not including the state value).
+ * @param value The state value.
+ *
+ * @return The 'rel1 relative X' value of the part state.
+ */
+EAPI double edje_edit_state_rel1_relative_x_get(Evas_Object *obj, const char *part, const char *state, double value);
+
+/** Get the 'rel1 relative Y' value of state.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to get 'rel1 relative Y' (not including the state value).
+ * @param value The state value.
+ *
+ * @return The 'rel1 relative Y' value of the part state.
+ */
+EAPI double edje_edit_state_rel1_relative_y_get(Evas_Object *obj, const char *part, const char *state, double value);
+
+/** Get the 'rel2 relative X' value of state.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to get 'rel2 relative X' (not including the state value).
+ * @param value The state value.
+ *
+ * @return The 'rel2 relative X' value of the part state.
+ */
+EAPI double edje_edit_state_rel2_relative_x_get(Evas_Object *obj, const char *part, const char *state, double value);
+
+/** Get the 'rel2 relative Y' value of state.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to get 'rel2 relative Y' (not including the state value).
+ * @param value The state value.
+ *
+ * @return The 'rel2 relative Y' value of the part state.
+ */
+EAPI double edje_edit_state_rel2_relative_y_get(Evas_Object *obj, const char *part, const char *state, double value);
+
+/** Set the 'rel1 relative X' value of state.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to set 'rel1 relative X' (not including the state value).
+ * @param value The state value.
+ * @param x The new 'rel1 relative X' value to set'.
+ */
+EAPI void edje_edit_state_rel1_relative_x_set(Evas_Object *obj, const char *part, const char *state, double value, double x);
+
+/** Set the 'rel1 relative Y' value of state.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to set 'rel1 relative Y' (not including the state value).
+ * @param value The state value.
+ * @param x The new 'rel1 relative Y' value to set'.
+ */
+EAPI void edje_edit_state_rel1_relative_y_set(Evas_Object *obj, const char *part, const char *state, double value, double y);
+
+/** Set the 'rel2 relative X' value of state.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to set 'rel2 relative X' (not including the state value).
+ * @param value The state value.
+ * @param x The new 'rel2 relative X' value to set'.
+ */
+EAPI void edje_edit_state_rel2_relative_x_set(Evas_Object *obj, const char *part, const char *state, double value, double x);
+
+/** Set the 'rel2 relative Y' value of state.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to set 'rel2 relative Y' (not including the state value).
+ * @param value The state value.
+ * @param x The new 'rel2 relative Y' value to set'.
+ */
+EAPI void edje_edit_state_rel2_relative_y_set(Evas_Object *obj, const char *part, const char *state, double value, double y);
+
+/** Get the 'rel1 offset X' value of state.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to get 'rel1 offset X' (not including the state value).
+ * @param value The state value.
+ *
+ * @return The 'rel1 offset X' value of the part state.
+ */
+EAPI int edje_edit_state_rel1_offset_x_get(Evas_Object *obj, const char *part, const char *state, double value);
+
+/** Get the 'rel1 offset Y' value of state.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to get 'rel1 offset Y' (not including the state value).
+ * @param value The state value.
+ *
+ * @return The 'rel1 offset Y' value of the part state.
+ */
+EAPI int edje_edit_state_rel1_offset_y_get(Evas_Object *obj, const char *part, const char *state, double value);
+
+/** Get the 'rel2 offset X' value of state.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to get 'rel2 offset X' (not including the state value).
+ * @param value The state value.
+ *
+ * @return The 'rel2 offset X' value of the part state.
+ */
+EAPI int edje_edit_state_rel2_offset_x_get(Evas_Object *obj, const char *part, const char *state, double value);
+
+/** Get the 'rel2 offset Y' value of state.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to get 'rel2 offset Y' (not including the state value).
+ * @param value The state value.
+ *
+ * @return The 'rel2 offset Y' value of the part state.
+ */
+EAPI int edje_edit_state_rel2_offset_y_get(Evas_Object *obj, const char *part, const char *state, double value);
+
+/** Set the 'rel1 offset X' value of state.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to set 'rel1 offset X' (not including the state value).
+ * @param value The state value.
+ * @param x The new 'rel1 offset X' value to set'.
+ */
+EAPI void edje_edit_state_rel1_offset_x_set(Evas_Object *obj, const char *part, const char *state, double value, double x);
+
+/** Set the 'rel1 offset Y' value of state.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to set 'rel1 offset Y' (not including the state value).
+ * @param value The state value.
+ * @param x The new 'rel1 offset Y' value to set'.
+ */
+EAPI void edje_edit_state_rel1_offset_y_set(Evas_Object *obj, const char *part, const char *state, double value, double y);
+
+/** Set the 'rel2 offset X' value of state.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to set 'rel2 offset X' (not including the state value).
+ * @param value The state value.
+ * @param x The new 'rel2 offset X' value to set'.
+ */
+EAPI void edje_edit_state_rel2_offset_x_set(Evas_Object *obj, const char *part, const char *state, double value, double x);
+
+/** Set the 'rel2 offset Y' value of state.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to set 'rel2 offset Y' (not including the state value).
+ * @param value The state value.
+ * @param x The new 'rel2 offset Y' value to set'.
+ */
+EAPI void edje_edit_state_rel2_offset_y_set(Evas_Object *obj, const char *part, const char *state, double value, double y);
+
+/** Get the part name rel1x is relative to.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The state that contain which the part name rel1x is relative to (not including the state value).
+ * @param value The state value.
+ *
+ * @return The part name rel1x is relative to or NULL if the part is relative to the whole interface.
+ */
+EAPI const char * edje_edit_state_rel1_to_x_get(Evas_Object *obj, const char *part, const char *state, double value);
+
+/** Get the part name rel1y is relative to.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The state that contain which the part name rel1y is relative to (not including the state value).
+ * @param value The state value.
+ *
+ * @return The part name rel1y is relative to or NULL if the part is relative to the whole interface.
+ */
+EAPI const char * edje_edit_state_rel1_to_y_get(Evas_Object *obj, const char *part, const char *state, double value);
+
+/** Get the part name rel2x is relative to.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The state that contain which the part name rel2x is relative to (not including the state value).
+ * @param value The state value.
+ *
+ * @return The part name rel2x is relative to or NULL if the part is relative to the whole interface.
+ */
+EAPI const char * edje_edit_state_rel2_to_x_get(Evas_Object *obj, const char *part, const char *state, double value);
+
+/** Get the part name rel2y is relative to.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The state that contain which the part name rel2y is relative to (not including the state value).
+ * @param value The state value.
+ *
+ * @return The part name rel2y is relative to or NULL if the part is relative to the whole interface.
+ */
+EAPI const char * edje_edit_state_rel2_to_y_get(Evas_Object *obj, const char *part, const char *state, double value);
+
+/** Set the part rel1x is relative to.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to set rel1x is relative to (not including the state value).
+ * @param value The state value.
+ * @param rel_to The name of the part that is used as container/parent (NULL make the part relative to the whole interface).
+ *
+ * @return The part name rel1x is relative to or NULL if the part is relative to the whole interface.
+ */
+EAPI void edje_edit_state_rel1_to_x_set(Evas_Object *obj, const char *part, const char *state, double value, const char *rel_to);
+
+/** Set the part rel1y is relative to.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to set rel1y is relative to (not including the state value).
+ * @param value The state value.
+ * @param rel_to The name of the part that is used as container/parent (NULL make the part relative to the whole interface).
+ *
+ * @return The part name rel1y is relative to or NULL if the part is relative to the whole interface.
+ */
+EAPI void edje_edit_state_rel1_to_y_set(Evas_Object *obj, const char *part, const char *state, double value, const char *rel_to);
+
+/** Set the part rel2x is relative to.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to set rel2x is relative to (not including the state value).
+ * @param value The state value.
+ * @param rel_to The name of the part that is used as container/parent (NULL make the part relative to the whole interface).
+ *
+ * @return The part name rel2x is relative to or NULL if the part is relative to the whole interface.
+ */
+EAPI void edje_edit_state_rel2_to_x_set(Evas_Object *obj, const char *part, const char *state, double value, const char *rel_to);
+
+/** Set the part rel2y is relative to.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to set rel2y is relative to (not including the state value).
+ * @param value The state value.
+ * @param rel_to The name of the part that is used as container/parent (NULL make the part relative to the whole interface).
+ *
+ * @return The part name rel2y is relative to or NULL if the part is relative to the whole interface.
+ */
+EAPI void edje_edit_state_rel2_to_y_set(Evas_Object *obj, const char *part, const char *state, double value, const char *rel_to);
+
+/** Get the color of a part state.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to get color (not including the state value).
+ * @param value The state value.
+ * @param r A pointer to store the red value.
+ * @param g A pointer to store the green value.
+ * @param b A pointer to store the blue value.
+ * @param a A pointer to store the alpha value.
+ */
+EAPI void edje_edit_state_color_get(Evas_Object *obj, const char *part, const char *state, double value, int *r, int *g, int *b, int *a);
+
+/** Get the color2 of a part state.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to get color (not including the state value).
+ * @param value The state value.
+ * @param r A pointer to store the red value.
+ * @param g A pointer to store the green value.
+ * @param b A pointer to store the blue value.
+ * @param a A pointer to store the alpha value.
+ */
+EAPI void edje_edit_state_color2_get(Evas_Object *obj, const char *part, const char *state, double value, int *r, int *g, int *b, int *a);
+
+/** Get the color3 of a part state.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to get color (not including the state value).
+ * @param value The state value.
+ * @param r A pointer to store the red value.
+ * @param g A pointer to store the green value.
+ * @param b A pointer to store the blue value.
+ * @param a A pointer to store the alpha value.
+ */
+EAPI void edje_edit_state_color3_get(Evas_Object *obj, const char *part, const char *state, double value, int *r, int *g, int *b, int *a);
+
+/** Set the color of a part state.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to set color (not including the state value).
+ * @param value The state value.
+ * @param r The red value of the color.
+ * @param g The green value of the color.
+ * @param b The blue value of the color.
+ * @param a The alpha value of the color.
+ */
+EAPI void edje_edit_state_color_set(Evas_Object *obj, const char *part, const char *state, double value, int r, int g, int b, int a);
+
+/** Set the color2 of a part state.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to set color (not including the state value).
+ * @param value The state value.
+ * @param r The red value of the color.
+ * @param g The green value of the color.
+ * @param b The blue value of the color.
+ * @param a The alpha value of the color.
+ */
+EAPI void edje_edit_state_color2_set(Evas_Object *obj, const char *part, const char *state, double value, int r, int g, int b, int a);
+
+/** Set the color3 of a part state.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to set color (not including the state value).
+ * @param value The state value.
+ * @param r The red value of the color.
+ * @param g The green value of the color.
+ * @param b The blue value of the color.
+ * @param a The alpha value of the color.
+ */
+EAPI void edje_edit_state_color3_set(Evas_Object *obj, const char *part, const char *state, double value, int r, int g, int b, int a);
+
+/** Get the horizontal align value of a part state.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to get horizontal align (not including the state value).
+ * @param value The state value.
+ *
+ * @return The horizontal align value for the given state
+ */
+EAPI double edje_edit_state_align_x_get(Evas_Object *obj, const char *part, const char *state, double value);
+
+/** Get the vertical align value of a part state.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to get horizontal align (not including the state value).
+ * @param value The state value.
+ *
+ * @return The vertical align value for the given state
+ */
+EAPI double edje_edit_state_align_y_get(Evas_Object *obj, const char *part, const char *state, double value);
+
+/** Set the horizontal align value of a part state.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to get horizontal align (not including the state value).
+ * @param value The state value.
+ * @param The new vertical align value.
+ */
+EAPI void edje_edit_state_align_x_set(Evas_Object *obj, const char *part, const char *state, double value,  double align);
+
+/** Set the vertical align value of a part state.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to get vertical align (not including the state value).
+ * @param value The state value.
+ * @param The new vertical align value.
+ */
+EAPI void edje_edit_state_align_y_set(Evas_Object *obj, const char *part, const char *state, double value,  double align);
+
+/** Get the minimum width value of a part state.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to get minimum width (not including the state value).
+ * @param value The state value.
+ *
+ * @return The minimum width value.
+ */
+EAPI int edje_edit_state_min_w_get(Evas_Object *obj, const char *part, const char *state, double value);
+
+/** Set the minimum width value of a part state.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to set minimum width (not including the state value).
+ * @param value The state value.
+ * @param min_w Minimum width value.
+ */
+EAPI void edje_edit_state_min_w_set(Evas_Object *obj, const char *part, const char *state, double value, int min_w);
+
+/** Get the minimum height value of a part state.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to get minimum height (not including the state value).
+ * @param value The state value.
+ *
+ * @return The minimum height value.
+ */
+EAPI int edje_edit_state_min_h_get(Evas_Object *obj, const char *part, const char *state, double value);
+
+/** Set the minimum height value of a part state.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to set minimum height (not including the state value).
+ * @param value The state value.
+ * @param min_h Minimum height value.
+ */
+EAPI void edje_edit_state_min_h_set(Evas_Object *obj, const char *part, const char *state, double value, int min_h);
+
+/** Get the maximum width value of a part state.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to get maximum width (not including the state value).
+ * @param value The state value.
+ *
+ * @return The maximum width value.
+ */
+EAPI int edje_edit_state_max_w_get(Evas_Object *obj, const char *part, const char *state, double value);
+
+/** Set the maximum width value of a part state.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to set maximum width (not including the state value).
+ * @param value The state value.
+ * @param max_w Maximum width value.
+ */
+EAPI void edje_edit_state_max_w_set(Evas_Object *obj, const char *part, const char *state, double value, int max_w);
+
+/** Get the maximum height value of a part state.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to get maximum height (not including the state value).
+ * @param value The state value.
+ *
+ * @return The maximum height value.
+ */
+EAPI int edje_edit_state_max_h_get(Evas_Object *obj, const char *part, const char *state, double value);
+
+/** Set the maximum height value of a part state.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to set maximum height (not including the state value).
+ * @param value The state value.
+ * @param max_h Maximum height value.
+ */
+EAPI void edje_edit_state_max_h_set(Evas_Object *obj, const char *part, const char *state, double value, int max_h);
+
+/** Get the minimum aspect value of a part state.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to get minimum aspect (not including the state value).
+ * @param value The state value.
+ *
+ * @return The minimum aspect
+ */
+EAPI double edje_edit_state_aspect_min_get(Evas_Object *obj, const char *part, const char *state, double value);
+
+/** Get the maximum aspect value of a part state.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to get maximum aspect (not including the state value).
+ * @param value The state value.
+ *
+ * @return The maximum aspect
+ */
+EAPI double edje_edit_state_aspect_max_get(Evas_Object *obj, const char *part, const char *state, double value);
+
+/** Set the minimum aspect value of a part state.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to set minimum aspect (not including the state value).
+ * @param value The state value.
+ * @param max_h Minimum aspect value.
+ */
+EAPI void edje_edit_state_aspect_min_set(Evas_Object *obj, const char *part, const char *state, double value, double aspect);
+
+/** Set the maximum aspect value of a part state.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to set maximum aspect (not including the state value).
+ * @param value The state value.
+ * @param max_h Maximum aspect value.
+ */
+EAPI void edje_edit_state_aspect_max_set(Evas_Object *obj, const char *part, const char *state, double value, double aspect);
+
+/** Get the aspect preference of a part state.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to get aspect preference (not including the state value).
+ * @param value The state value.
+ *
+ * @return The aspect preference (0 = None, 1 = Vertical, 2 = Horizontal, 3 = Both)
+ */
+EAPI unsigned char edje_edit_state_aspect_pref_get(Evas_Object *obj, const char *part, const char *state, double value);
+
+/** Set the aspect preference of a part state.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to set aspect preference (not including the state value).
+ * @param value The state value.
+ * @param The aspect preference to set (0 = None, 1 = Vertical, 2 = Horizontal, 3 = Both)
+ */
+EAPI void edje_edit_state_aspect_pref_set(Evas_Object *obj, const char *part, const char *state, double value, unsigned char pref);
+
+/** Get the fill horizontal origin relative value of a part state.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to get the fill horizontal origin relative to area (not including the state value).
+ * @param value The state value.
+ *
+ * @return The fill horizontal origin relative to area.
+ */
+EAPI double edje_edit_state_fill_origin_relative_x_get(Evas_Object *obj, const char *part, const char *state, double value);
+
+/** Get the fill vertical origin relative value of a part state.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to get fill vertical origin relative to area (not including the state value).
+ * @param value The state value.
+ *
+ * @return The fill vertical origin relative to area.
+ */
+EAPI double edje_edit_state_fill_origin_relative_y_get(Evas_Object *obj, const char *part, const char *state, double value);
+
+/** Get the fill horizontal origin offset value of a part state.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to get fill horizontal origin offset relative to area (not including the state value).
+ * @param value The state value.
+ *
+ * @return The fill horizontal origin offset relative to area.
+ */
+EAPI int edje_edit_state_fill_origin_offset_x_get(Evas_Object *obj, const char *part, const char *state, double value);
+
+/** Get the fill vertical origin offset value of a part state.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to get fill vertical origin offset relative to area (not including the state value).
+ * @param value The state value.
+ *
+ * @return The fill vertical origin offset value.
+ */
+EAPI int edje_edit_state_fill_origin_offset_y_get(Evas_Object *obj, const char *part, const char *state, double value);
+
+/** Set the fill horizontal origin relative value of a part state.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to set fill horizontal origin relative to area (not including the state value).
+ * @param value The state value.
+ * @param x The fill horizontal origin value.
+ */
+EAPI void edje_edit_state_fill_origin_relative_x_set(Evas_Object *obj, const char *part, const char *state, double value, double x);
+
+/** Set the fill horizontal origin relative value of a part state.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to set fill vertical origin relative to area (not including the state value).
+ * @param value The state value.
+ * @param y The fill vertical origin value.
+ */
+EAPI void edje_edit_state_fill_origin_relative_y_set(Evas_Object *obj, const char *part, const char *state, double value, double y);
+
+/** Set the fill horizontal origin offset value of a part state.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to set fill horizontal origin offset relative to area (not including the state value).
+ * @param value The state value.
+ * @param x The fill horizontal origin offset value.
+ */
+EAPI void edje_edit_state_fill_origin_offset_x_set(Evas_Object *obj, const char *part, const char *state, double value, double x);
+
+/** Set the fill vertical origin offset value of a part state.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to set fill vertical origin offset relative to area (not including the state value).
+ * @param value The state value.
+ * @param y The fill vertical origin offset value.
+ */
+EAPI void edje_edit_state_fill_origin_offset_y_set(Evas_Object *obj, const char *part, const char *state, double value, double y);
+
+/** Get the fill horizontal size relative value of a part state.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to get fill horizontal size relative to area (not including the state value).
+ * @param value The state value.
+ *
+ * @return The fill horizontal size relative to area.
+ */
+EAPI double edje_edit_state_fill_size_relative_x_get(Evas_Object *obj, const char *part, const char *state, double value);
+
+/** Get the fill vertical size relative value of a part state.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to get fill vertical size relative to area (not including the state value).
+ * @param value The state value.
+ *
+ * @return The fill vertical size relative to area.
+ */
+EAPI double edje_edit_state_fill_size_relative_y_get(Evas_Object *obj, const char *part, const char *state, double value);
+
+/** Get the fill horizontal size offset value of a part state.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to get fill horizontal size offset relative to area (not including the state value).
+ * @param value The state value.
+ *
+ * @return The fill horizontal size offset relative to area.
+ */
+EAPI int edje_edit_state_fill_size_offset_x_get(Evas_Object *obj, const char *part, const char *state, double value);
+
+/** Get the fill vertical size offset value of a part state.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to get fill vertical size offset relative to area (not including the state value).
+ * @param value The state value.
+ *
+ * @return The fill vertical size offset relative to area.
+ */
+EAPI int edje_edit_state_fill_size_offset_y_get(Evas_Object *obj, const char *part, const char *state, double value);
+
+/** Set the fill horizontal size relative value of a part state.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to set fill horizontal size relative value (not including the state value).
+ * @param value The state value.
+ * @param x The horizontal size relative value.
+ */
+EAPI void edje_edit_state_fill_size_relative_x_set(Evas_Object *obj, const char *part, const char *state, double value, double x);
+
+/** Set the fill vertical size relative value of a part state.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to set fill vertical size relative value (not including the state value).
+ * @param value The state value.
+ * @param y The vertical size relative value.
+ */
+EAPI void edje_edit_state_fill_size_relative_y_set(Evas_Object *obj, const char *part, const char *state, double value, double x);
+
+/** Set the fill horizontal size offset value of a part state.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to set fill horizontal size offset relative value (not including the state value).
+ * @param value The state value.
+ * @param x The horizontal size offset value.
+ */
+EAPI void edje_edit_state_fill_size_offset_x_set(Evas_Object *obj, const char *part, const char *state, double value, double x);
+
+/** Set the fill vertical size offset value of a part state.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to set fill vertical size offset relative value (not including the state value).
+ * @param value The state value.
+ * @param y The vertical size offset value.
+ */
+EAPI void edje_edit_state_fill_size_offset_y_set(Evas_Object *obj, const char *part, const char *state, double value, double y);
+
+/** Get the visibility of a part state.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to get visibility (not including the state value).
+ * @param value The state value.
+ *
+ * @return EINA_TRUE if the state is visible, EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool edje_edit_state_visible_get(Evas_Object *obj, const char *part, const char *state, double value);
+
+/** Set the visibility of a part state.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to set visibility (not including the state value).
+ * @param value The state value.
+ * @param visible To set state visible (EINA_TRUE if the state is visible, EINA_FALSE otherwise)
+ */
+EAPI void edje_edit_state_visible_set(Evas_Object *obj, const char *part, const char *state, double value, Eina_Bool visible);
+
+/** Get the color class of the given part state.
+ *
+ * Remember to free the string with edje_edit_string_free()
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to get color class (not including the state value).
+ * @param value The state value.
+ *
+ * @return The current color class.
+ */
+EAPI const char *edje_edit_state_color_class_get(Evas_Object *obj, const char *part, const char *state, double value);
+
+/** Set the color class of the given part state.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to set color class (not including the state value).
+ * @param value The state value.
+ * @param color_class The color class to assign.
+ */
+EAPI void edje_edit_state_color_class_set(Evas_Object *obj, const char *part, const char *state, double value, const char *color_class);
+
+/** Get the list of parameters for an external part.
+ *
+ * DO NOT FREE THE LIST!
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to get list of Edje_External_Param (not including the state value).
+ * @param value The state value.
+ *
+ * @return The list of Edje_External_Param.
+ */
+EAPI const Eina_List * edje_edit_state_external_params_list_get(Evas_Object *obj, const char *part, const char *state, double value);
+
+/** Get the external parameter type and value.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to get external parameter (not including the state value).
+ * @param value The state value.
+ * @param param The name of the paramter to look for.
+ * @param type The type of the parameter will be stored here.
+ * @param val Pointer to value will be stored here - DO NOT FREE IT!
+ *
+ * @return EINA_TRUE if the parameter was found, EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool edje_edit_state_external_param_get(Evas_Object *obj, const char *part, const char *state, double value, const char *param, Edje_External_Param_Type *type, void **val);
+
+/** Get external parameter of type INT.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to get external parameter of type INT (not including the state value).
+ * @param value The state value.
+ * @param param The name of the paramter.
+ * @param val The value of the parameter.
+ *
+ * @return EINA_TRUE if sucessful. EINA_FALSE if not found or is of different type.
+ */
+EAPI Eina_Bool edje_edit_state_external_param_int_get(Evas_Object *obj, const char *part, const char *state, double value, const char *param, int *val);
+
+/** Get external parameter of type BOOL.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to get external parameter of type BOOL (not including the state value).
+ * @param value The state value.
+ * @param param The name of the paramter.
+ * @param val The value of the parameter.
+ *
+ * @return EINA_TRUE if sucessful. EINA_FALSE if not found or is of different type.
+ */
+EAPI Eina_Bool edje_edit_state_external_param_bool_get(Evas_Object *obj, const char *part, const char *state, double value, const char *param, Eina_Bool *val);
+
+/** Get external parameter of type DOUBLE.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to get external parameter of type DOUBLE (not including the state value).
+ * @param value The state value.
+ * @param param The name of the paramter.
+ * @param val The value of the parameter.
+ *
+ * @return EINA_TRUE if sucessful. EINA_FALSE if not found or is of different type.
+ */
+EAPI Eina_Bool edje_edit_state_external_param_double_get(Evas_Object *obj, const char *part, const char *state, double value, const char *param, double *val);
+
+/** Get external parameter of type STRING.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to get external parameter of type STRING (not including the state value).
+ * @param value The state value.
+ * @param param The name of the paramter.
+ * @param val The value of the parameter.
+ *
+ * @return EINA_TRUE if sucessful. EINA_FALSE if not found or is of different type.
+ */
+EAPI Eina_Bool edje_edit_state_external_param_string_get(Evas_Object *obj, const char *part, const char *state, double value, const char *param, const char **val);
+
+/** Get external parameter of type CHOICE.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to get external parameter of type CHOICE (not including the state value).
+ * @param value The state value.
+ * @param param The name of the paramter.
+ * @param val The value of the parameter.
+ *
+ * @return EINA_TRUE if sucessful. EINA_FALSE if not found or is of different type.
+ */
+EAPI Eina_Bool edje_edit_state_external_param_choice_get(Evas_Object *obj, const char *part, const char *state, double value, const char *param, const char **val);
+
+/** Set the external parameter type and value, adding it if it didn't exist before.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to get external parameter (not including the state value).
+ * @param value The state value.
+ * @param param The name of the paramter set.
+ * @param type The type of the parameter.
+ * @param val Value according to type.
+ *
+ * @return EINA_TRUE if it was set, EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool edje_edit_state_external_param_set(Evas_Object *obj, const char *part, const char *state, double value, const char *param, Edje_External_Param_Type type, ...);
+
+/** Set external parameter of type INT.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to get external parameter of type INT (not including the state value).
+ * @param value The state value.
+ * @param param The name of the paramter.
+ * @param val Value will be stored here.
+ *
+ * @return EINA_TRUE if it was set, EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool edje_edit_state_external_param_int_set(Evas_Object *obj, const char *part, const char *state, double value, const char *param, int val);
+
+/** Set external parameter of type BOOL.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to get external parameter of type BOOL (not including the state value).
+ * @param value The state value.
+ * @param param The name of the paramter.
+ * @param val Value will be stored here.
+ *
+ * @return EINA_TRUE if it was set, EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool edje_edit_state_external_param_bool_set(Evas_Object *obj, const char *part, const char *state, double value, const char *param, Eina_Bool val);
+
+/** Set external parameter of type DOUBLE.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to get external parameter of type DOUBLE (not including the state value).
+ * @param value The state value.
+ * @param param The name of the paramter.
+ * @param val Value will be stored here.
+ *
+ * @return EINA_TRUE if it was set, EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool edje_edit_state_external_param_double_set(Evas_Object *obj, const char *part, const char *state, double value, const char *param, double val);
+
+/** Set external parameter of type STRING.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to get external parameter of type STRING (not including the state value).
+ * @param value The state value.
+ * @param param The name of the paramter.
+ * @param val Value will be stored here.
+ *
+ * @return EINA_TRUE if it was set, EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool edje_edit_state_external_param_string_set(Evas_Object *obj, const char *part, const char *state, double value, const char *param, const char *val);
+
+/** Set external parameter of type CHOICE.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to get external parameter of type CHOICE (not including the state value).
+ * @param value The state value.
+ * @param param The name of the paramter.
+ * @param val Value will be stored here.
+ *
+ * @return EINA_TRUE if it was set, EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool edje_edit_state_external_param_choice_set(Evas_Object *obj, const char *part, const char *state, double value, const char *param, const char *val);
+
+
+//@}
+/******************************************************************************/
+/**************************   TEXT API   ************************************/
+/******************************************************************************/
+/** @name Text API
+ *  Functions to deal with text objects (see @ref edcref).
+ */ //@{
+
+/** Get the text of a part state.
+ *
+ * Remember to free the returned string with edje_edit_string_free().
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to get text (not including the state value).
+ * @param value The state value.
+ *
+ * @return A newly allocated string containing the text for the given state.
+ */
+EAPI const char * edje_edit_state_text_get(Evas_Object *obj, const char *part, const char *state, double value);
+
+/** Set the text of a part state.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to set text (not including the state value).
+ * @param value The state value.
+ * @param text The new text to assign.
+ */
+EAPI void edje_edit_state_text_set(Evas_Object *obj, const char *part, const char *state, double value,const char *text);
+
+/** Get the text size of a part state
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to get text size (not including the state value).
+ * @param value The state value.
+ *
+ * @return The text size or -1 on errors.
+ */
+EAPI int edje_edit_state_text_size_get(Evas_Object *obj, const char *part, const char *state, double value);
+
+/** Set the text size of a part state.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to set text size (not including the state value).
+ * @param value The state value.
+ * @param size The new font size to set (in pixel)
+ */
+EAPI void edje_edit_state_text_size_set(Evas_Object *obj, const char *part, const char *state, double value, int size);
+
+/** Get the text horizontal align of a part state.
+ *
+ * The value range is from 0.0(right) to 1.0(left)
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to get the text horizontal align (not including the state value).
+ * @param value The state value.
+ *
+ * @return The text horizont align value
+ */
+EAPI double edje_edit_state_text_align_x_get(Evas_Object *obj, const char *part, const char *state, double value);
+
+/** Get the text vertical align of a part state.
+ *
+ * The value range is from 0.0(top) to 1.0(bottom)
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to get the text vertical align (not including the state value).
+ * @param value The state value.
+ *
+ * @return The text horizont align value
+ */
+EAPI double edje_edit_state_text_align_y_get(Evas_Object *obj, const char *part, const char *state, double value);
+
+/** Set the text horizontal align of a part state.
+ *
+ * The value range is from 0.0(right) to 1.0(left)
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to set the text horizontal align (not including the state value).
+ * @param value The state value.
+ * @param align The new text horizontal align value
+ */
+EAPI void edje_edit_state_text_align_x_set(Evas_Object *obj, const char *part, const char *state, double value, double align);
+
+/** Set the text vertical align of a part state.
+ *
+ * The value range is from 0.0(top) to 1.0(bottom)
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to set the text vertical align (not including the state value).
+ * @param value The state value.
+ * @param align The new text vertical align value
+ */
+EAPI void edje_edit_state_text_align_y_set(Evas_Object *obj, const char *part, const char *state, double value, double align);
+
+/** Get the text elipsis of a part state.
+ *
+ * The value range is from 0.0(right) to 1.0(left)
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to get the text elipses value (not including the state value).
+ * @param value The state value.
+ *
+ * @return The text elipsis value
+ */
+EAPI double edje_edit_state_text_elipsis_get(Evas_Object *obj, const char *part, const char *state, double value);
+
+/** Set the text vertical align of a part state.
+ *
+ * The value range is from 0.0(right) to 1.0(left)
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to set the text elipses value (not including the state value).
+ * @param value The state value.
+ * @param balance The position where to cut the string
+ */
+EAPI void edje_edit_state_text_elipsis_set(Evas_Object *obj, const char *part, const char *state, double value, double balance);
+
+/** Get if the text part fit it's container horizontally
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to get the if the text part fit it's container horizontally (not including the state value).
+ * @param value The state value.
+ *
+ * @return EINA_TRUE If the part fit it's container horizontally, EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool edje_edit_state_text_fit_x_get(Evas_Object *obj, const char *part, const char *state, double value);
+
+/** Set if the text part should fit it's container horizontally
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to set the if the text part fit it's container horizontally (not including the state value).
+ * @param value The state value.
+ * @param fit EINA_TRUE to make the text fit it's container horizontally, EINA_FALSE otherwise.
+ */
+EAPI void edje_edit_state_text_fit_x_set(Evas_Object *obj, const char *part, const char *state, double value, Eina_Bool fit);
+
+/** Get if the text part fit it's container vertically
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to get the if the text part fit it's container vertically (not including the state value).
+ * @param value The state value.
+ *
+ * @return EINA_TRUE If the part fit it's container vertically, EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool edje_edit_state_text_fit_y_get(Evas_Object *obj, const char *part, const char *state, double value);
+
+/** Set if the text part should fit it's container vertically
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to set the if the text part fit it's container vertically (not including the state value).
+ * @param value The state value.
+ * @param fit EINA_TRUE to make the text fit it's container vertically, EINA_FALSE otherwise.
+ */
+EAPI void edje_edit_state_text_fit_y_set(Evas_Object *obj, const char *part, const char *state, double value, Eina_Bool fit);
+
+/** Get the list of all the fonts in the given edje.
+ *
+ * Use edje_edit_string_list_free() when you don't need the list anymore.
+ *
+ * @param obj Object being edited.
+ *
+ * @return A list containing all the fonts names found in the edje file.
+ */
+EAPI Eina_List * edje_edit_fonts_list_get(Evas_Object *obj);
+
+/** Add a new font to the edje file.
+ *
+ * The newly created font will be available to all the groups in the edje, not only the current one.
+ *
+ * @param obj Object being edited.
+ * @param path The file path to load the font from.
+ * @param alias The alias for file, or NULL to use filename
+ *
+ * @return EINA_TRUE if font cat be loaded, EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool edje_edit_font_add(Evas_Object *obj, const char *path, const char* alias);
+
+/** Delete font from the edje file.
+ *
+ * The font will be removed from all the groups in the edje, not only the current one.
+ *
+ * @param obj Object being edited.
+ * @param alias The font alias
+ *
+ * @return EINA_TRUE if font deleted, EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool edje_edit_font_del(Evas_Object *obj, const char* alias);
+
+/** Get font name for a given part state.
+ *
+ * Remember to free the returned string using edje_edit_string_free().
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to get the name of the font used (not including the state value).
+ * @param value The state value.
+ *
+ * @return The name of the font used in the given part state.
+ */
+EAPI const char * edje_edit_state_font_get(Evas_Object *obj, const char *part, const char *state, double value);
+
+/** Set font name for a given part state.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to set the name of the font that will be used (not including the state value).
+ * @param value The state value.
+ * @param font The name of the font to use in the given part state.
+ */
+EAPI void edje_edit_state_font_set(Evas_Object *obj, const char *part, const char *state, double value, const char *font);
+
+
+//@}
+/******************************************************************************/
+/**************************   IMAGES API   ************************************/
+/******************************************************************************/
+/** @name Images API
+ *  Functions to deal with image objects (see @ref edcref).
+ */ //@{
+
+/** Get the list of all the images in the given edje.
+ * Use edje_edit_string_list_free() when you don't need the list anymore.
+ *
+ * @param obj Object being edited.
+ *
+ * @return A List containing all images names found in the edje file.
+ */
+EAPI Eina_List * edje_edit_images_list_get(Evas_Object *obj);
+
+/** Add an new image to the image collection
+ *
+ * This function add the given image inside the edje. Don't add a new image part
+ * but only put the image inside the edje file. It actually write directly to
+ * the file so you don't have to save.
+ * After you have to create a new image_part that use this image. Note that all
+ * the parts in the edje share the same image collection, thus you can/must use
+ * the same image for different part.
+ *
+ * The format of the image files that can be loaded depend on the evas engine on your system
+ *
+ * @param obj Object being edited.
+ * @param path The name of the image file to include in the edje.
+ *
+ * @return EINA_TRUE if succesful, EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool edje_edit_image_add(Evas_Object *obj, const char *path);
+
+/** Delete an image from the image collection
+ *
+ * It actually write directly to the file so you don't have to save.
+ *
+ * @param obj Object being edited.
+ * @param name The name of the image file to include in the edje.
+ *
+ * @return EINA_TRUE if succesful, EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool edje_edit_image_del(Evas_Object *obj, const char *name);
+
+/** Add an image entry to the image collection
+ *
+ * This function adds the given image entry to the edje image collection. The
+ * image needs to be inside the eet already, with key name "images/id". After
+ * you have to create a new image_part that use this image, referring to it as
+ * "name". Note that all the parts in the edje share the same image collection,
+ * thus you can/must use the same image for different part.
+ *
+ * @param obj Object being edited.
+ * @param name The image entry name.
+ * @param id The image id.
+ *
+ * @return EINA_TRUE if succesful, EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool edje_edit_image_data_add(Evas_Object *obj, const char *name, int id);
+
+/** Get normal image name for a given part state.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to get the name that is being used (not including the state value).
+ * @param value The state value.
+ *
+ * @return The name of the image used by state.
+ */
+EAPI const char * edje_edit_state_image_get(Evas_Object *obj, const char *part, const char *state, double value);
+
+/** Set normal image for a given part state.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to set the image that will be used (not including the state value).
+ * @param value The state value.
+ * @param image The name of the image (must be an image contained in the edje file).
+ */
+EAPI void edje_edit_state_image_set(Evas_Object *obj, const char *part, const char *state, double value, const char *image);
+
+/** Get image id for a given image name.
+ *
+ * @param obj Object being edited.
+ * @param image_name The image name.
+ *
+ * @return The id of the given image name.
+ */
+EAPI int edje_edit_image_id_get(Evas_Object *obj, const char *image_name);
+
+/** Get compression type for the given image.
+ *
+ * @param obj Object being edited.
+ * @param image The name of the image.
+ *
+ * @return One of Image Compression types.
+ * (EDJE_EDIT_IMAGE_COMP_RAW, EDJE_EDIT_IMAGE_COMP_USER, EDJE_EDIT_IMAGE_COMP_COMP, EDJE_EDIT_IMAGE_COMP_LOSSY).
+ */
+EAPI Edje_Edit_Image_Comp edje_edit_image_compression_type_get(Evas_Object *obj, const char *image);
+
+/** Get compression rate for the given image.
+ *
+ * @param obj Object being edited.
+ * @param name The name of the image.
+ *
+ * @return The compression rate (if the imnage is EDJE_EDIT_IMAGE_COMP_LOSSY). Or < 0 on errors.
+ */
+EAPI int edje_edit_image_compression_rate_get(Evas_Object *obj, const char *image);
+
+/** Get the image border of a part state.
+ *
+ * Pass NULL to any of [r,g,b,a] to get only the others.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to get the image border (not including the state value).
+ * @param value The state value.
+ * @param l A pointer to store the left value
+ * @param r A pointer to store the right value
+ * @param t A pointer to store the top value
+ * @param r A pointer to store the bottom value
+ */
+EAPI void edje_edit_state_image_border_get(Evas_Object *obj, const char *part, const char *state, double value, int *l, int *r, int *t, int *b);
+
+/** Set the image border of a part state.
+ *
+ * Pass -1 to any of [l,r,t,b] to leave the value untouched.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to set the image border (not including the state value).
+ * @param value The state value.
+ * @param l Left border value (or -1).
+ * @param r Right border value (or -1).
+ * @param t Top border value (or -1).
+ * @param r Bottom border value (or -1).
+ */
+EAPI void edje_edit_state_image_border_set(Evas_Object *obj, const char *part, const char *state, double value, int l, int r, int t, int b);
+
+/** Get if the image center should be draw.
+ *
+ * 1 means to draw the center, 0 to don't draw it.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to get the image border fill (not including the state value).
+ * @param value The state value.
+ *
+ * @return 1 if the center of the bordered image is draw, 0 otherwise.
+ */
+EAPI unsigned char edje_edit_state_image_border_fill_get(Evas_Object *obj, const char *part, const char *state, double value);
+
+/** Set if the image center should be draw.
+ *
+ * 1 means to draw the center, 0 to don't draw it.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to set the image border fill (not including the state value).
+ * @param value The state value.
+ * @param fill Fill to be se. 1 if the center of the bordered image is draw, 0 otherwise.
+ */
+EAPI void edje_edit_state_image_border_fill_set(Evas_Object *obj, const char *part, const char *state, double value, unsigned char fill);
+
+/** Get the list of all the tweens images in the given part state.
+ *
+ * Use edje_edit_string_list_free() when you don't need it anymore.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to get the list of all the tweens images (not including the state value).
+ * @param value The state value.
+ *
+ * @return A string list containing all the image name that form a tween animation in the given part state.
+ */
+EAPI Eina_List * edje_edit_state_tweens_list_get(Evas_Object *obj, const char *part, const char *state, double value);
+
+/** Add a new tween frame to the given part state.
+ *
+ * The tween param must be the name of an existing image.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to add a new tween frame (not including the state value).
+ * @param value The state value.
+ * @param tween The name of the image to add.
+ *
+ * @return EINA_TRUE if succesful, EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool edje_edit_state_tween_add(Evas_Object *obj, const char *part, const char *state, double value, const char *tween);
+
+/** Remove the first tween with the given name.
+ *
+ * The image is not removed from the edje.
+ *
+ * @param obj Object being edited.
+ * @param part Part that contain state.
+ * @param state The name of the state to del the tween (not including the state value).
+ * @param value The state value.
+ * @param tween The name of the image to del.
+ *
+ * @return EINA_TRUE if succesful, EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool edje_edit_state_tween_del(Evas_Object *obj, const char *part, const char *state, double value, const char *tween);
+
+
+//@}
+/******************************************************************************/
+/*************************   SPECTRUM API   ***********************************/
+/******************************************************************************/
+/** @name Spectrum API
+ *  Functions to manage spectrum (see @ref edcref).
+ */ //@{
+
+/** Get the list of all the spectrum in the given edje object.
+ *
+ * Use edje_edit_string_list_free() when you don't need it anymore.
+ *
+ * @param obj Object being edited.
+ *
+ * @return A list containing all the spectra names.
+ */
+EAPI Eina_List * edje_edit_spectrum_list_get(Evas_Object *obj);
+
+/** Add a new spectra in the given edje object.
+ *
+ * @param obj Object being edited.
+ * @param spectra The name of the spectra to include in the edje.
+ *
+ * @return EINA_TRUE if succesful, EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool edje_edit_spectra_add(Evas_Object *obj, const char *name);
+
+/** Delete the given spectra from the edje object.
+ *
+ * @param obj Object being edited.
+ * @param spectra The name of the spectra to delete.
+ *
+ * @return EINA_TRUE if succesful, EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool edje_edit_spectra_del(Evas_Object *obj, const char *spectra);
+
+/** Change the name of the given spectra.
+ *
+ * @param obj Object being edited.
+ * @param spectra The name of the current spectra.
+ * @param name The new name to assign.
+ *
+ * @return EINA_TRUE if succesful, EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool edje_edit_spectra_name_set(Evas_Object *obj, const char *spectra, const char *name);
+
+/** Get the number of stops in the given spectra.
+ *
+ * @param obj Object being edited.
+ * @param spectra The name of the spectra.
+ *
+ * @return The number of stops (or 0 on errors).
+ */
+EAPI int edje_edit_spectra_stop_num_get(Evas_Object *obj, const char *spectra);
+
+/** Set the number of stops in the given spectra.
+ *
+ * @param obj Object being edited.
+ * @param spectra The name of the spectra.
+ * @param num The number of stops you want
+ *
+ * @return EINA_TRUE if succesful, EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool edje_edit_spectra_stop_num_set(Evas_Object *obj, const char *spectra, int num);
+
+/** Get the colors of the given stop.
+ *
+ * @param obj Object being edited.
+ * @param spectra The name of the spectra.
+ * @param stop_number The number of the stop,
+ * @param r Where to store the red color value,
+ * @param g Where to store the green color value,
+ * @param b Where to store the blue color value,
+ * @param a Where to store the alpha color value,
+ * @param d Where to store the delta stop value,
+ *
+ * @return EINA_TRUE if succesful, EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool edje_edit_spectra_stop_color_get(Evas_Object *obj, const char *spectra, int stop_number, int *r, int *g, int *b, int *a, int *d);
+
+/** Set the colors of the given stop.
+ *
+ * @param obj Object being edited.
+ * @param spectra The name of the spectra.
+ * @param stop_number The number of the stops,
+ * @param r The red color value to set,
+ * @param g The green color value to set,
+ * @param b The blue color value to set,
+ * @param a The alpha color value to set,
+ * @param d The delta stop value to set,
+ */
+EAPI Eina_Bool edje_edit_spectra_stop_color_set(Evas_Object *obj, const char *spectra, int stop_number, int r, int g, int b, int a, int d);
+
+
+//@}
+/******************************************************************************/
+/*************************   GRADIENT API   ***********************************/
+/******************************************************************************/
+/** @name Gradient API
+ *  Functions to deal with gradient objects (see @ref edcref).
+ */ //@{
+
+/** Get the type of gradient.
+ *
+ * Remember to free the string with edje_edit_string_free().
+ *
+ * @param obj Object being edited.
+ * @param part The part that contain state.
+ * @param state The name of the state to get the gradient type (not including the state value).
+ * @param value The state value.
+ *
+ * @return The type of gradient used in state.
+ * (linear, linear.diag, linear.codiag, radial, rectangular, angular, sinosoidal)
+ */
+EAPI const char * edje_edit_state_gradient_type_get(Evas_Object *obj, const char *part, const char *state, double value);
+
+/** Set the type of gradient.
+ *
+ * Gradient type can be on of the following: linear, linear.diag, linear.codiag, radial, rectangular, angular, sinusoidal
+ *
+ * @param obj Object being edited.
+ * @param part The part that contain state.
+ * @param state The name of the state to set the gradient type (not including the state value).
+ * @param value The state value.
+ * @param type The type of gradient to use.
+ *
+ * @return EINA_TRUE if succesful, EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool edje_edit_state_gradient_type_set(Evas_Object *obj, const char *part, const char *state, double value, const char *type);
+
+/** Get if the current gradient use the fill properties or the gradient_rel as params.
+ *
+ * @param obj Object being edited.
+ * @param part The part that contain state.
+ * @param state The name of the state to set the gradient type (not including the state value).
+ * @param value The state value.
+ *
+ * @return EINA_TRUE if gradient use the fill properties, EINA_FALSE otherwise.
+ * */
+EAPI Eina_Bool edje_edit_state_gradient_use_fill_get(Evas_Object *obj, const char *part, const char *state, double value);
+
+/** Get the spectra used by part state.
+ *
+ * Remember to free the string with edje_edit_string_free().
+ *
+ * @param obj Object being edited.
+ * @param part The part that contain state.
+ * @param state The name of the state to get the spectra name used (not including the state value).
+ * @param value The state value.
+ *
+ * @return The spectra name used in state.
+ */
+EAPI const char * edje_edit_state_gradient_spectra_get(Evas_Object *obj, const char *part, const char *state, double value);
+
+/** Set the spectra used by part state.
+ *
+ * @param obj Object being edited.
+ * @param part The part that contain state.
+ * @param state The name of the state to set the spectra (not including the state value).
+ * @param value The state value.
+ * @param spectra The spectra name to assign
+ *
+ * @return EINA_TRUE if succesful, EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool edje_edit_state_gradient_spectra_set(Evas_Object *obj, const char *part, const char *state, double value, const char *spectra);
+
+/** Get the angle of the gradient.
+ *
+ * @param obj Object being edited.
+ * @param part The part that contain state.
+ * @param state The name of the state to get the angle (not including the state value).
+ * @param value The state value.
+ *
+ * @return The angle of the gradient.
+ */
+EAPI int edje_edit_state_gradient_angle_get(Evas_Object *obj, const char *part, const char *state, double value);
+
+/** Set the angle of the gradient.
+ *
+ * @param obj Object being edited.
+ * @param part The part that contain state.
+ * @param state The name of the state to set the angle (not including the state value).
+ * @param value The state value.
+ * @param angle The angle to set.
+ */
+EAPI void edje_edit_state_gradient_angle_set(Evas_Object *obj, const char *part, const char *state, double value, int angle);
+
+/** Get the gradient rel1 horizontal relative value
+ *
+ * @param obj Object being edited.
+ * @param part The part that contain state.
+ * @param state The name of the state to get rel1 relative x value (not including the state value).
+ * @param value The state value.
+ *
+ * @return The gradient rel1 horizontal relative value.
+ */
+EAPI double edje_edit_state_gradient_rel1_relative_x_get(Evas_Object *obj, const char *part, const char *state, double value);
+
+/** Get the gradient rel1 vertical relative value
+ *
+ * @param obj Object being edited.
+ * @param part The part that contain state.
+ * @param state The name of the state to get rel1 relative y value (not including the state value).
+ * @param value The state value.
+ *
+ * @return The gradient rel1 vertical relative value.
+ */
+EAPI double edje_edit_state_gradient_rel1_relative_y_get(Evas_Object *obj, const char *part, const char *state, double value);
+
+/** Get the gradient rel2 horizontal relative value
+ *
+ * @param obj Object being edited.
+ * @param part The part that contain state.
+ * @param state The name of the state to get rel2 relative x value (not including the state value).
+ * @param value The state value.
+ *
+ * @return The gradient rel2 horizontal relative value.
+ */
+EAPI double edje_edit_state_gradient_rel2_relative_x_get(Evas_Object *obj, const char *part, const char *state, double value);
+
+/** Get the gradient rel2 vertical relative value
+ *
+ * @param obj Object being edited.
+ * @param part The part that contain state.
+ * @param state The name of the state to get rel2 relative y value (not including the state value).
+ * @param value The state value.
+ *
+ * @return The gradient rel2 vertical relative value.
+ */
+EAPI double edje_edit_state_gradient_rel2_relative_y_get(Evas_Object *obj, const char *part, const char *state, double value);
+
+
+/** Set the gradient rel1 horizontal relative value
+ *
+ * @param obj Object being edited.
+ * @param part The part that contain state.
+ * @param state The name of the state to set rel1 relative x value (not including the state value).
+ * @param value The state value.
+ * @param val The rel1 relative x to be set,
+ *
+ * @return EINA_TRUE if succesful, EINA_FALSE otherwise..
+ */
+EAPI Eina_Bool edje_edit_state_gradient_rel1_relative_x_set(Evas_Object *obj, const char *part, const char *state, double value, double val);
+
+
+/** Set the gradient rel1 vertical relative value
+ *
+ * @param obj Object being edited.
+ * @param part The part that contain state.
+ * @param state The name of the state to set rel1 relative y value (not including the state value).
+ * @param value The state value.
+ * @param val The rel1 relative y to be set,
+ *
+ * @return EINA_TRUE if succesful, EINA_FALSE otherwise..
+ */
+EAPI Eina_Bool edje_edit_state_gradient_rel1_relative_y_set(Evas_Object *obj, const char *part, const char *state, double value, double val);
+
+/** Set the gradient rel2 horizontal relative value
+ *
+ * @param obj Object being edited.
+ * @param part The part that contain state.
+ * @param state The name of the state to set rel2 relative x value (not including the state value).
+ * @param value The state value.
+ * @param val The rel2 relative x to be set,
+ *
+ * @return EINA_TRUE if succesful, EINA_FALSE otherwise..
+ */
+EAPI Eina_Bool edje_edit_state_gradient_rel2_relative_x_set(Evas_Object *obj, const char *part, const char *state, double value, double val);
+
+/** Set the gradient rel2 vertical relative value
+ *
+ * @param obj Object being edited.
+ * @param part The part that contain state.
+ * @param state The name of the state to set rel2 relative y value (not including the state value).
+ * @param value The state value.
+ * @param val The rel2 relative y to be set,
+ *
+ * @return EINA_TRUE if succesful, EINA_FALSE otherwise..
+ */
+EAPI Eina_Bool edje_edit_state_gradient_rel2_relative_y_set(Evas_Object *obj, const char *part, const char *state, double value, double val);
+
+/** Get the gradient rel1 horizontal offset value
+ *
+ * @param obj Object being edited.
+ * @param part The part that contain state.
+ * @param state The name of the state to get rel1 offset x value (not including the state value).
+ * @param value The state value.
+ *
+ * @return The gradient rel1 horizontal offset value.
+ */
+EAPI int edje_edit_state_gradient_rel1_offset_x_get(Evas_Object *obj, const char *part, const char *state, double value);
+
+/** Get the gradient rel1 vertical offset value
+ *
+ * @param obj Object being edited.
+ * @param part The part that contain state.
+ * @param state The name of the state to get rel1 offset y value (not including the state value).
+ * @param value The state value.
+ *
+ * @return The gradient rel1 vertical offset value.
+ */
+EAPI int edje_edit_state_gradient_rel1_offset_y_get(Evas_Object *obj, const char *part, const char *state, double value);
+
+/** Get the gradient rel2 horizontal offset value
+ *
+ * @param obj Object being edited.
+ * @param part The part that contain state.
+ * @param state The name of the state to get rel2 offset x value (not including the state value).
+ * @param value The state value.
+ *
+ * @return The gradient rel2 horizontal offset value.
+ */
+EAPI int edje_edit_state_gradient_rel2_offset_x_get(Evas_Object *obj, const char *part, const char *state, double value);
+
+/** Get the gradient rel2 vertical offset value
+ *
+ * @param obj Object being edited.
+ * @param part The part that contain state.
+ * @param state The name of the state to get rel2 offset y value (not including the state value).
+ * @param value The state value.
+ *
+ * @return The gradient rel2 vertical offset value.
+ */
+EAPI int edje_edit_state_gradient_rel2_offset_y_get(Evas_Object *obj, const char *part, const char *state, double value);
+
+/** Set the gradient rel1 horizontal offset value
+ *
+ * @param obj Object being edited.
+ * @param part The part that contain state.
+ * @param state The name of the state to set rel1 offset x value (not including the state value).
+ * @param value The state value.
+ * @param val The rel1 offset x value.
+ *
+ * @return EINA_TRUE if succesful, EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool edje_edit_state_gradient_rel1_offset_x_set(Evas_Object *obj, const char *part, const char *state, double value, int val);
+
+/** Set the gradient rel1 vertical offset value
+ *
+ * @param obj Object being edited.
+ * @param part The part that contain state.
+ * @param state The name of the state to set rel1 offset y value (not including the state value).
+ * @param value The state value.
+ * @param val The rel1 offset y value.
+ *
+ * @return EINA_TRUE if succesful, EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool edje_edit_state_gradient_rel1_offset_y_set(Evas_Object *obj, const char *part, const char *state, double value, int val);
+
+/** Set the gradient rel2 horizontal offset value
+ *
+ * @param obj Object being edited.
+ * @param part The part that contain state.
+ * @param state The name of the state to set rel2 offset x value (not including the state value).
+ * @param value The state value.
+ * @param val The rel2 offset x value.
+ *
+ * @return EINA_TRUE if succesful, EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool edje_edit_state_gradient_rel2_offset_x_set(Evas_Object *obj, const char *part, const char *state, double value, int val);
+
+/** Set the gradient rel2 vertical offset value
+ *
+ * @param obj Object being edited.
+ * @param part The part that contain state.
+ * @param state The name of the state to set rel2 offset y value (not including the state value).
+ * @param value The state value.
+ * @param val The rel2 offset y value.
+ *
+ * @return EINA_TRUE if succesful, EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool edje_edit_state_gradient_rel2_offset_y_set(Evas_Object *obj, const char *part, const char *state, double value, int val);
+
+
+//@}
+/******************************************************************************/
+/*************************   PROGRAMS API   ***********************************/
+/******************************************************************************/
+/** @name Programs API
+ *  Functions to deal with programs (see @ref edcref).
+ */ //@{
+
+/** Get the list of all the programs in the given edje object.
+ *
+ * Use edje_edit_string_list_free() when you don't need it anymore.
+ *
+ * @param obj Object being edited.
+ *
+ * @return A list containing all the program names.
+ */
+EAPI Eina_List * edje_edit_programs_list_get(Evas_Object *obj);
+
+/** Add a new program to the edje file
+ *
+ * If a program with the same name just exist the function will fail.
+ *
+ * @param obj Object being edited.
+ * @param name The name of the new program.
+ *
+ * @return EINA_TRUE if succesful, EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool edje_edit_program_add(Evas_Object *obj, const char *name);
+
+/** Remove the given program from the edje file.
+ *
+ * @param obj Object being edited.
+ * @param prog The name of the program to remove.
+ *
+ * @return EINA_TRUE if succesful, EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool edje_edit_program_del(Evas_Object *obj, const char *prog);
+
+/** Check if a program with the given name exist in the edje object.
+ *
+ * @param obj Object being edited.
+ * @param The name of the program that will be searched,
+ *
+ * @return EINA_TRUE if the program exist, EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool edje_edit_program_exist(Evas_Object *obj, const char *prog);
+
+/** Run the given program.
+ *
+ * @param obj Object being edited.
+ * @param prog The name of the program to execute.
+ *
+ * @return EINA_TRUE if succesful, EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool edje_edit_program_run(Evas_Object *obj, const char *prog);
+
+/** Set a new name for the given program
+ *
+ * @param obj Object being edited.
+ * @param prog The current program name.
+ * @param new_name The new name to assign.
+ *
+ * @return EINA_TRUE if succesful, EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool edje_edit_program_name_set(Evas_Object *obj, const char *prog, const char *new_name);
+
+/** Get source of a given program.
+ *
+ * Remember to free the returned string using edje_edit_string_free().
+ *
+ * @param obj Object being edited.
+ * @param prog The name of the program to get source.
+ *
+ * @return The source value por program.
+ */
+EAPI const char * edje_edit_program_source_get(Evas_Object *obj, const char *prog);
+
+/** Set source of the given program.
+ *
+ * @param obj Object being edited.
+ * @param program The name of the program to set source.
+ * @param source The new source value.
+ *
+ * @return EINA_TRUE if succesful, EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool edje_edit_program_source_set(Evas_Object *obj, const char *prog, const char *source);
+
+/** Get signal of a given program.
+ *
+ * Remember to free the returned string using edje_edit_string_free().
+ *
+ * @param obj Object being edited.
+ * @param prog The name of the program to get the signal.
+ *
+ * @return The signal value for program.
+ */
+EAPI const char * edje_edit_program_signal_get(Evas_Object *obj, const char *prog);
+
+/** Set signal of the given program.
+ *
+ * @param obj Object being edited.
+ * @param prog The name of the program to set the signal.
+ * @param signal The new signal value.
+ *
+ * @return EINA_TRUE if succesful, EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool edje_edit_program_signal_set(Evas_Object *obj, const char *prog, const char *signal);
+
+/** Get in.from of a given program.
+ *
+ * @param obj Object being edited.
+ * @param prog The name of the program to get the delay.
+ *
+ * @return The delay.
+ */
+EAPI double edje_edit_program_in_from_get(Evas_Object *obj, const char *prog);
+
+/** Set in.from of a given program.
+ *
+ * @param obj Object being edited.
+ * @param prog The name of the program to set the delay.
+ * @param seconds Number of seconds to delay the program execution
+ *
+ * */
+EAPI Eina_Bool edje_edit_program_in_from_set(Evas_Object *obj, const char *prog, double seconds);
+
+/** Get in.range of a given program.
+ *
+ * @param obj Object being edited.
+ * @param prog The name of the program to get random delay.
+ *
+ * @return The delay random.
+ */
+EAPI double edje_edit_program_in_range_get(Evas_Object *obj, const char *prog);
+
+/** Set in.range of a given program.
+ *
+ * @param obj Object being edited.
+ * @param prog The name of the program to set random delay.
+ * @param seconds Max random number of seconds to delay.
+ *
+ * @returen EINA_TRUE if succesful, EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool edje_edit_program_in_range_set(Evas_Object *obj, const char *prog, double seconds);
+
+/** Get the action of a given program.
+ *
+ * @param obj Object being edited.
+ * @param prog The name of the program to get the action.
+ *
+ * @return The action type, or -1 on errors.
+ * Action can be one of EDJE_ACTION_TYPE_NONE, _STATE_SET, ACTION_STOP, SIGNAL_EMIT, DRAG_VAL_SET, _DRAG_VAL_STEP, _DRAG_VAL_PAGE, _SCRIPT
+ */
+EAPI Edje_Action_Type edje_edit_program_action_get(Evas_Object *obj, const char *prog);
+
+/** Set the action of a given program.
+ *
+ * Action can be one of EDJE_ACTION_TYPE_NONE, _STATE_SET, ACTION_STOP, SIGNAL_EMIT, DRAG_VAL_SET, _DRAG_VAL_STEP, _DRAG_VAL_PAGE, _SCRIPT
+ *
+ * @param obj Object being edited.
+ * @param prog The name of the program to set the action.
+ * @param action The new action type.
+ *
+ * @return EINA_TRUE if succesful, EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool edje_edit_program_action_set(Evas_Object *obj, const char *prog, Edje_Action_Type action);
+
+/** Get the list of the targets for the given program.
+ *
+ * Use edje_edit_string_list_free() when you don't need it anymore.
+ *
+ * @param obj Object being edited.
+ * @param prog The name of the progrem to get the list of the targets.
+ *
+ * @return A list with all the targets names, or NULL on error.
+ */
+EAPI Eina_List * edje_edit_program_targets_get(Evas_Object *obj, const char *prog);
+
+/** Add a new target name to the list of 'targets' in the given program.
+ *
+ * If program action is EDJE_ACTION_TYPE_ACTION_STOP then 'target' must be an existing program name.
+ * If action is EDJE_ACTION_TYPE_STATE_SET then 'target' must be an existing part name.
+ *
+ * @param obj Object being edited.
+ * @param program The name of the program to add a new target.
+ *
+ * @return EINA_TRUE if succesful, EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool edje_edit_program_target_add(Evas_Object *obj, const char *prog, const char *target);
+
+/** Deletes a target from the list of 'targets' in the given program.
+ *
+ * If program action is EDJE_ACTION_TYPE_ACTION_STOP then 'target' must be an existing program name.
+ * If action is EDJE_ACTION_TYPE_STATE_SET then 'target' must be an existing part name.
+ *
+ * @param obj Object being edited.
+ * @param prog The name of the program to del a target from the list of targets.
+ * @param target The name of another program or another part.
+ *
+ * @return EINA_TRUE if succesful, EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool edje_edit_program_target_del(Evas_Object *obj, const char *prog, const char *target);
+
+/** Clear the 'targets' list of the given program
+ *
+ * @param obj Object being edited.
+ * @param prog The name of the program to cleaar the 'targets' list.
+ *
+ * @return EINA_TRUE if succesful, EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool edje_edit_program_targets_clear(Evas_Object *obj, const char *prog);
+
+/** Get the list of action that will be run after the give program
+ *
+ * Use edje_edit_string_list_free() when you don't need it anymore.
+ *
+ * @param obj Object being edited.
+ * @param prog The name of the program to get the list of actions
+ *
+ * @return A list with all program names. or NULL on error.
+ */
+EAPI Eina_List * edje_edit_program_afters_get(Evas_Object *obj, const char *prog);
+
+/** Add a new program name to the list of 'afters' in the given program.
+ *
+ * All the programs listed in 'afters' will be executed after program execution.
+ *
+ * @param obj Object being edited.
+ * @param prog The name of the program that contains the list of afters
+ * @param after The name of another program to add to the afters list
+ *
+ * @return EINA_TRUE if succesful, EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool edje_edit_program_after_add(Evas_Object *obj, const char *prog, const char *after);
+
+/** Delete the given program from the list of 'afters' of the program.
+ *
+ * @param obj Object being edited.
+ * @param prog The name of the program from where to remove the after.
+ * @param after The name of the program to remove from the list of afters.
+ *
+ * @return EINA_TRUE is succesful or not in the list, EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool edje_edit_program_after_del(Evas_Object *obj, const char *prog, const char *after);
+
+/** Clear the 'afters' list of the given program.
+ *
+ * @param obj Object being edited.
+ * @param prog The name of the program to clear the 'afters' list.
+ *
+ * @return EINA_TRUE if succesful, EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool edje_edit_program_afters_clear(Evas_Object *obj, const char *prog);
+
+/** Get the state for the given program
+ *
+ * In a STATE_SET action this is the name of state to set.
+ * In a SIGNAL_EMIT action is the name of the signal to emit.
+ *
+ * @param obj Object being edited.
+ * @param prog The name of the program to get the state.
+ *
+ * @return The name of the state.
+ */
+EAPI const char * edje_edit_program_state_get(Evas_Object *obj, const char *prog);
+
+/** Set the state for the given program
+ *
+ * In a STATE_SET action this is the name of state to set.
+ * In a SIGNAL_EMIT action is the name of the signal to emit.
+ *
+ * @param obj Object being edited.
+ * @param prog The name of the program to set a state.
+ * @param state The nameo of the state to set (not including the state value)
+ *
+ * @return EINA_TRUE if succesful, EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool edje_edit_program_state_set(Evas_Object *obj, const char *prog, const char *state);
+
+/** Get the value of state for the given program.
+ *
+ * In a STATE_SET action this is the value of state to set.
+ * Not used on SIGNAL_EMIT action.
+ *
+ * @param obj Object being edited.
+ * @param prog The name of the program to get the value of state.
+ *
+ * @return The value of state for the program.
+ */
+EAPI double edje_edit_program_value_get(Evas_Object *obj, const char *prog);
+
+/** Set the value of state for the given program.
+ *
+ * In a STATE_SET action this is the value of state to set.
+ * Not used on SIGNAL_EMIT action.
+ *
+ * @param obj Object being edited.
+ * @param prog The name of the program to set the value of state.
+ * @param value The vale to set.
+ *
+ * @return EINA_TRUE if succesful, EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool edje_edit_program_value_set(Evas_Object *obj, const char *prog, double value);
+
+/** Get the state2 for the given program
+ *
+ * In a STATE_SET action is not used
+ * In a SIGNAL_EMIT action is the source of the emitted signal.
+ *
+ * @param obj Object being edited.
+ * @param prog The name of the program to get the state2.
+ *
+ * @return The source to emit for the program.
+ */
+EAPI const char * edje_edit_program_state2_get(Evas_Object *obj, const char *prog);
+
+/** Set the state2 for the given program
+ *
+ * In a STATE_SET action is not used
+ * In a SIGNAL_EMIT action is the source of the emitted signal.
+ *
+ * @param obj Object being edited.
+ * @param prog The name of the program to set the state2.
+ * @param state2 The name of the state to set.
+ *
+ * @return EINA_TRUE if succesful, EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool edje_edit_program_state2_set(Evas_Object *obj, const char *prog, const char *state2);
+
+/** Get the value of state2 for the given program.
+ *
+ * @param obj Object being edited.
+ * @param prog The name of the program to get the state2 value.
+ *
+ * @return The vale of the state2 for the program.
+ */
+EAPI double edje_edit_program_value2_get(Evas_Object *obj, const char *prog);
+
+/** Set the value2 of state for the given program.
+ *
+ * This is used in DRAG_ACTION
+ *
+ * @param obj Object being edited.
+ * @param prog The name of the program to set the state2 value.
+ * @param value The value of the state2 to set.
+ */
+EAPI Eina_Bool edje_edit_program_value2_set(Evas_Object *obj, const char *prog, double value);
+
+/** Get the type of transition to use when apply animations.
+ *
+ * Can be one of: EDJE_TWEEN_MODE_NONE, EDJE_TWEEN_MODE_LINEAR, EDJE_TWEEN_MODE_SINUSOIDAL, EDJE_TWEEN_MODE_ACCELERATE or EDJE_TWEEN_MODE_DECELERATE.
+ *
+ * @param obj Object being edited.
+ * @param prog The name of the program to get the transition.
+ *
+ * @return The type of transition used by program.
+ */
+EAPI Edje_Tween_Mode edje_edit_program_transition_get(Evas_Object *obj, const char *prog);
+
+/** Set the type of transition to use when apply animations.
+ *
+ * Can be one of: EDJE_TWEEN_MODE_NONE, EDJE_TWEEN_MODE_LINEAR, EDJE_TWEEN_MODE_SINUSOIDAL, EDJE_TWEEN_MODE_ACCELERATE or EDJE_TWEEN_MODE_DECELERATE.
+ *
+ * @param obj Object being edited.
+ * @param prog The name of the program to set the transition.
+ * @param transition The transition type to set
+ *
+ * @return EINA_TRUE if succesful, EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool edje_edit_program_transition_set(Evas_Object *obj, const char *prog, Edje_Tween_Mode transition);
+
+/** Get the duration of the transition in seconds.
+ *
+ * @param obj Object being edited.
+ * @param prog The name of the program to get the transition time.
+ *
+ * @return The duration of the transition.
+ */
+EAPI double edje_edit_program_transition_time_get(Evas_Object *obj, const char *prog);
+
+/** Set the duration of the transition in seconds.
+ *
+ * @param obj Object being edited.
+ * @param prog The name of the program to set the transition time.
+ * @param seconds The duration of the transition (in seconds).
+ *
+ * @return EINA_TRUE if succesful, EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool edje_edit_program_transition_time_set(Evas_Object *obj, const char *prog, double seconds);
+
+
+//@}
+/******************************************************************************/
+/**************************   SCRIPTS API   ***********************************/
+/******************************************************************************/
+/** @name Scripts API
+ *  Functions to deal with embryo scripts (see @ref edcref).
+ */ //@{
+
+/**
+ * Get the script for the given object,
+ *
+ * @param obj Object being edited.
+ *
+ * @return The script name.
+ */
+EAPI const char * edje_edit_script_get(Evas_Object *obj);
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am
new file mode 100644 (file)
index 0000000..bec0f28
--- /dev/null
@@ -0,0 +1,134 @@
+
+MAINTAINERCLEANFILES = Makefile.in
+
+AM_CPPFLAGS = \
+-I. \
+-I$(top_srcdir) \
+-I$(top_srcdir)/src/bin \
+-I$(top_srcdir)/src/lib \
+-DPACKAGE_BIN_DIR=\"$(bindir)\" \
+-DPACKAGE_LIB_DIR=\"$(libdir)\" \
+-DPACKAGE_DATA_DIR=\"$(datadir)/$(PACKAGE)\" \
+@EVIL_CFLAGS@ \
+@EDJE_CFLAGS@ \
+@ECORE_IMF_CFLAGS@ \
+@EFL_EDJE_BUILD@
+
+lib_LTLIBRARIES = libedje.la
+
+include_HEADERS = Edje.h Edje_Edit.h
+
+base_sources = \
+edje_calc.c \
+edje_callbacks.c \
+edje_data.c \
+edje_embryo.c \
+edje_lua.c \
+edje_lua2.c \
+edje_load.c \
+edje_main.c \
+edje_misc.c \
+edje_program.c \
+edje_smart.c \
+edje_text.c \
+edje_util.c \
+edje_var.c \
+edje_container.c \
+edje_message_queue.c \
+edje_cache.c \
+edje_match.c \
+edje_textblock_styles.c \
+edje_edit.c \
+edje_script_only.c \
+edje_lua_script_only.c \
+edje_entry.c \
+edje_external.c \
+edje_module.c
+
+if EDJE_AMALGAMATION
+nodist_libedje_la_SOURCES = edje_amalgamation.c
+
+edje_amalgamation.c: $(base_sources) Makefile
+       -rm -f edje_amalgamation.c
+
+       @echo "#ifdef HAVE_CONFIG_H" >> edje_amalgamation.c
+       @echo "# include \"config.h\"" >> edje_amalgamation.c
+       @echo "#endif" >> edje_amalgamation.c
+
+       @echo "#ifndef _WIN32" >> eina_amalgamation.c
+       @echo "#define _GNU_SOURCE" >> eina_amalgamation.c
+       @echo "#endif" >> eina_amalgamation.c
+
+       @echo "#ifdef HAVE_ALLOCA_H" >> edje_amalgamation.c
+       @echo "# include <alloca.h>" >> edje_amalgamation.c
+       @echo "#elif defined __GNUC__" >> edje_amalgamation.c
+       @echo "# define alloca __builtin_alloca" >> edje_amalgamation.c
+       @echo "#elif defined _AIX" >> edje_amalgamation.c
+       @echo "# define alloca __alloca" >> edje_amalgamation.c
+       @echo "#elif defined _MSC_VER" >> edje_amalgamation.c
+       @echo "# include <malloc.h>" >> edje_amalgamation.c
+       @echo "# define alloca _alloca" >> edje_amalgamation.c
+       @echo "#else" >> edje_amalgamation.c
+       @echo "# include <stddef.h>" >> edje_amalgamation.c
+       @echo "# ifdef __cplusplus" >> edje_amalgamation.c
+       @echo "#extern \"C\"" >> edje_amalgamation.c
+       @echo "# endif" >> edje_amalgamation.c
+       @echo "#void *alloca (size_t);" >> edje_amalgamation.c
+       @echo "#endif" >> edje_amalgamation.c
+
+       @echo "#include <string.h>" >> edje_amalgamation.c
+       @echo "#include <math.h>" >> edje_amalgamation.c
+       @echo "#include <time.h>" >> edje_amalgamation.c
+       @echo "#include <limits.h>" >> edje_amalgamation.c
+       @echo "#include <errno.h>" >> edje_amalgamation.c
+       @echo "#include <sys/stat.h>" >> edje_amalgamation.c
+
+       @echo "#ifndef _MSC_VER" >> edje_amalgamation.c
+       @echo "# include <unistd.h>" >> edje_amalgamation.c
+       @echo "#endif" >> edje_amalgamation.c
+
+       @echo "#ifdef HAVE_LOCALE_H" >> edje_amalgamation.c
+       @echo "# include <locale.h>" >> edje_amalgamation.c
+       @echo "#endif" >> edje_amalgamation.c
+
+       @echo "#include <lua.h>" >> edje_amalgamation.c
+       @echo "#include <lauxlib.h>" >> edje_amalgamation.c
+
+       @echo "#ifdef HAVE_EVIL" >> edje_amalgamation.c
+       @echo "# include <Evil.h>" >> edje_amalgamation.c
+       @echo "#endif" >> edje_amalgamation.c
+
+       @echo "#include <Eina.h>" >> edje_amalgamation.c
+       @echo "#include <Edje.h>" >> edje_amalgamation.c
+       @echo "#include <Evas.h>" >> edje_amalgamation.c
+       @echo "#include <Ecore.h>" >> edje_amalgamation.c
+       @echo "#include <Embryo.h>" >> edje_amalgamation.c
+
+       @echo "#ifdef HAVE_ECORE_IMF" >> edje_amalgamation.c
+       @echo "# include <Ecore_IMF.h>" >> edje_amalgamation.c
+       @echo "#endif" >> edje_amalgamation.c
+
+       @echo "#include <edje_private.h>" >> edje_amalgamation.c
+
+       @for f in $(base_sources); do \
+          if [ `echo $$f | sed -e 's/^...\(.\).*/\1/'` != '/' ]; then \
+                 file="$(srcdir)/$$f" ; \
+          else \
+                 file="$$f" ; \
+          fi ; \
+          echo "/* file: $$file */" >> edje_amalgamation.c; \
+          grep -v -e '^# *include \+.\(config\|\|Evil\|Eina\|Eet\|Evas\|Ecore\|Embryo\|Ecore_IMF\|string\|math\|limits\|sys/stat\|errno\|time\|unistd\|locale\|lua\|lauxlib\|edje_private\)[.]h.*' $$file >> edje_amalgamation.c; \
+       done
+       @echo "edje_amalgamation.c generated"
+
+else
+libedje_la_SOURCES = $(base_sources)
+endif
+
+libedje_la_LIBADD = @EDJE_LIBS@ @ECORE_IMF_LIBS@ @EVIL_LIBS@ -lm
+libedje_la_LDFLAGS = -no-undefined @lt_enable_auto_import@ -version-info @version_info@ @release_info@
+
+EXTRA_DIST = edje_private.h edje_container.h
+
+clean-local:
+       @rm -rf  edje_amalgamation.c
diff --git a/src/lib/edje_cache.c b/src/lib/edje_cache.c
new file mode 100644 (file)
index 0000000..4665321
--- /dev/null
@@ -0,0 +1,683 @@
+/*
+ * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
+ */
+/* EDJE - EFL graphical design and layout library based on Evas
+ * Copyright (C) 2008 Cedric Bail
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef HAVE_ALLOCA_H
+# include <alloca.h>
+#elif defined __GNUC__
+# define alloca __builtin_alloca
+#elif defined _AIX
+# define alloca __alloca
+#elif defined _MSC_VER
+# include <malloc.h>
+# define alloca _alloca
+#else
+# include <stddef.h>
+# ifdef  __cplusplus
+extern "C"
+# endif
+void *alloca (size_t);
+#endif
+
+#include <string.h>
+#include <sys/stat.h>
+
+#include "edje_private.h"
+
+
+/**
+ * @cond
+ */
+
+static Eina_Hash   *_edje_file_hash = NULL;
+static int          _edje_file_cache_size = 16;
+static Eina_List   *_edje_file_cache = NULL;
+
+static int          _edje_collection_cache_size = 16;
+
+static Edje_Part_Collection *
+_edje_file_coll_open(Edje_File *edf, const char *coll)
+{
+   Edje_Part_Collection *edc = NULL;
+   Edje_Part_Collection_Directory_Entry *ce;
+   Eina_List *l = NULL;
+   int id = -1, size = 0;
+   char buf[256];
+   void *data;
+
+   EINA_LIST_FOREACH(edf->collection_dir->entries, l, ce)
+     {
+       if ((ce->entry) && (!strcmp(ce->entry, coll)))
+         {
+            id = ce->id;
+            break;
+         }
+     }
+   if (id < 0) return NULL;
+
+   snprintf(buf, sizeof(buf), "collections/%i", id);
+   edc = eet_data_read(edf->ef, _edje_edd_edje_part_collection, buf);
+   if (!edc) return NULL;
+
+   snprintf(buf, sizeof(buf), "scripts/%i", id);
+   data = eet_read(edf->ef, buf, &size);
+
+   if (data)
+     {
+       edc->script = embryo_program_new(data, size);
+       free(data);
+     }
+
+   snprintf(buf, sizeof(buf), "lua_scripts/%i", id);
+   data = eet_read(edf->ef, buf, &size);
+
+   if (data)
+     {
+#ifdef LUA2
+        _edje_lua2_script_load(edc, data, size);
+#else        
+       int err_code;
+
+       //printf("lua chunk size: %d\n", size);
+       _edje_lua_new_reg(_edje_lua_state_get(), -1, edc); // gets freed in 'edje_load::_edje_collectoin_free'
+
+       if ((err_code = luaL_loadbuffer(_edje_lua_state_get(), data, size, "edje_lua_script")))
+         {
+            if (err_code == LUA_ERRSYNTAX)
+              ERR("lua load syntax error: %s", lua_tostring(_edje_lua_state_get(), -1));
+            else if (err_code == LUA_ERRMEM)
+              ERR("lua load memory allocation error: %s", lua_tostring(_edje_lua_state_get(), -1));
+         }
+       if (lua_pcall(_edje_lua_state_get(), 0, 0, 0))
+         ERR("lua call error: %s", lua_tostring(_edje_lua_state_get(), -1));
+#endif        
+       free(data);
+     }
+   
+   edc->part = eina_stringshare_add(coll);
+   edc->references = 1;
+   if (!edf->collection_hash)
+     edf->collection_hash = eina_hash_string_small_new(NULL);
+   eina_hash_add(edf->collection_hash, coll, edc);
+   return edc;
+}
+
+static int
+_edje_font_hash(Edje_File *edf)
+{
+   int count = 0;
+
+   if (!edf->font_hash)
+     edf->font_hash = eina_hash_string_small_new(NULL);
+
+   if (edf->font_dir)
+     {
+       Eina_List *l;
+       Edje_Font_Directory_Entry  *fnt;
+
+       EINA_LIST_FOREACH(edf->font_dir->entries, l, fnt)
+         {
+            int                         length;
+            char                       *tmp;
+
+            length = strlen(fnt->entry) + 7;
+            tmp = alloca(length);
+
+            snprintf(tmp, length, "fonts/%s", fnt->entry);
+            fnt->path = eina_stringshare_add(tmp);
+             if (edf->free_strings)
+               eina_stringshare_del(fnt->entry);
+            fnt->entry = fnt->path + 6;
+            eina_hash_direct_add(edf->font_hash, fnt->entry, fnt);
+
+            count++;
+         }
+     }
+   return count;
+}
+
+static Edje_File *
+_edje_file_open(const char *file, const char *coll, int *error_ret, Edje_Part_Collection **edc_ret)
+{
+   Edje_File *edf;
+   Edje_Part_Collection *edc;
+   Edje_Data *di;
+   Eet_File *ef;
+   Eina_List *l;
+   struct stat st;
+
+   if (stat(file, &st) != 0)
+     {
+       *error_ret = EDJE_LOAD_ERROR_DOES_NOT_EXIST;
+       return NULL;
+     }
+
+   ef = eet_open(file, EET_FILE_MODE_READ);
+   if (!ef)
+     {
+       *error_ret = EDJE_LOAD_ERROR_UNKNOWN_FORMAT;
+       return NULL;
+     }
+   edf = eet_data_read(ef, _edje_edd_edje_file, "edje_file");
+   if (!edf)
+     {
+       *error_ret = EDJE_LOAD_ERROR_CORRUPT_FILE;
+       eet_close(ef);
+       return NULL;
+     }
+
+   edf->free_strings = eet_dictionary_get(ef) ? 0 : 1;
+
+   edf->ef = ef;
+   edf->mtime = st.st_mtime;
+
+   if (edf->version != EDJE_FILE_VERSION)
+     {
+       *error_ret = EDJE_LOAD_ERROR_INCOMPATIBLE_FILE;
+       _edje_file_free(edf);
+       return NULL;
+     }
+   if (!edf->collection_dir)
+     {
+       *error_ret = EDJE_LOAD_ERROR_CORRUPT_FILE;
+       _edje_file_free(edf);
+       return NULL;
+     }
+
+   edf->path = eina_stringshare_add(file);
+   edf->references = 1;
+
+   _edje_textblock_style_parse_and_fix(edf);
+
+   if (!edf->data_cache)
+     edf->data_cache = eina_hash_string_small_new(NULL);
+
+   EINA_LIST_FOREACH(edf->data, l, di)
+     eina_hash_add(edf->data_cache, di->key, di->value);
+
+   if (coll)
+     {
+       edc = _edje_file_coll_open(edf, coll);
+       if (!edc)
+         {
+            *error_ret = EDJE_LOAD_ERROR_UNKNOWN_COLLECTION;
+         }
+       if (edc_ret) *edc_ret = edc;
+     }
+
+   edf->font_hash = NULL;
+
+   _edje_font_hash(edf);
+
+   return edf;
+}
+
+static void
+_edje_file_dangling(Edje_File *edf)
+{
+   if (edf->dangling) return;
+   edf->dangling = EINA_TRUE;
+
+   eina_hash_del(_edje_file_hash, edf->path, edf);
+   if (!eina_hash_population(_edje_file_hash))
+     {
+       eina_hash_free(_edje_file_hash);
+       _edje_file_hash = NULL;
+     }
+}
+
+Edje_File *
+_edje_cache_file_coll_open(const char *file, const char *coll, int *error_ret, Edje_Part_Collection **edc_ret)
+{
+   Edje_File *edf = NULL;
+   Eina_List *l, *hist;
+   Edje_Part_Collection *edc;
+   Edje_Part *ep;
+   struct stat st;
+
+   if (stat(file, &st) != 0)
+     {
+       return NULL;
+     }
+
+   if (!_edje_file_hash)
+     {
+       _edje_file_hash = eina_hash_string_small_new(NULL);
+       goto open_new;
+     }
+
+   edf = eina_hash_find(_edje_file_hash, file);
+   if (edf)
+     {
+       if (edf->mtime != st.st_mtime)
+         {
+            _edje_file_dangling(edf);
+            edf = NULL;
+            goto open_new;
+         }
+
+       edf->references++;
+       goto open;
+     }
+
+   EINA_LIST_FOREACH(_edje_file_cache, l, edf)
+     {
+       if (!strcmp(edf->path, file))
+         {
+            if (edf->mtime != st.st_mtime)
+              {
+                 _edje_file_cache = eina_list_remove_list(_edje_file_cache, l);
+                 _edje_file_free(edf);
+                 edf = NULL;
+                 goto open_new;
+              }
+
+            edf->references = 1;
+            _edje_file_cache = eina_list_remove_list(_edje_file_cache, l);
+            eina_hash_add(_edje_file_hash, file, edf);
+            break;
+         }
+       edf = NULL;
+     }
+
+ open_new:
+   if (!edf)
+     {
+       if (!_edje_file_hash)
+         _edje_file_hash = eina_hash_string_small_new(NULL);
+       edf = _edje_file_open(file, coll, error_ret, edc_ret);
+       if (!edf) return NULL;
+       eina_hash_add(_edje_file_hash, file, edf);
+       return edf;
+     }
+
+ open:
+
+   if (!coll) return edf;
+
+   if (!edf->collection_hash)
+     edf->collection_hash = eina_hash_string_small_new(NULL);
+
+   edc = eina_hash_find(edf->collection_hash, coll);
+   if (edc)
+     {
+       edc->references++;
+     }
+   else
+     {
+        EINA_LIST_FOREACH(edf->collection_cache, l, edc)
+         {
+            if (!strcmp(edc->part, coll))
+              {
+                 edc->references = 1;
+                 edf->collection_cache = eina_list_remove_list(edf->collection_cache, l);
+                 eina_hash_add(edf->collection_hash, coll, edc);
+                 break;
+              }
+            edc = NULL;
+         }
+     }
+   if (!edc)
+     {
+       edc = _edje_file_coll_open(edf, coll);
+       if (!edc)
+         {
+            *error_ret = EDJE_LOAD_ERROR_UNKNOWN_COLLECTION;
+         }
+       else
+         {
+           EINA_LIST_FOREACH(edc->parts, l, ep)
+              {
+                 Edje_Part *ep2;
+
+                 /* Register any color classes in this parts descriptions. */
+                 hist = NULL;
+                 hist = eina_list_append(hist, ep);
+                 ep2 = ep;
+                 while (ep2->dragable.confine_id >= 0)
+                   {
+                      ep2 = eina_list_nth(edc->parts, ep2->dragable.confine_id);
+                      if (eina_list_data_find(hist, ep2))
+                        {
+                           ERR("confine_to loops. invalidating loop.");
+                           ep2->dragable.confine_id = -1;
+                           break;
+                        }
+                      hist = eina_list_append(hist, ep2);
+                   }
+                 eina_list_free(hist);
+                 hist = NULL;
+                 hist = eina_list_append(hist, ep);
+                 ep2 = ep;
+                 while (ep2->dragable.events_id >= 0)
+                   {
+                      Edje_Part* prev;
+
+                      prev = ep2;
+
+                      ep2 = eina_list_nth(edc->parts, ep2->dragable.events_id);
+                      if (!ep2->dragable.x && !ep2->dragable.y)
+                        {
+                           prev->dragable.events_id = -1;
+                           break;
+                        }
+
+                      if (eina_list_data_find(hist, ep2))
+                        {
+                           ERR("events_to loops. invalidating loop.");
+                           ep2->dragable.events_id = -1;
+                           break;
+                        }
+                      hist = eina_list_append(hist, ep2);
+                   }
+                 eina_list_free(hist);
+                 hist = NULL;
+                 hist = eina_list_append(hist, ep);
+                 ep2 = ep;
+                 while (ep2->clip_to_id >= 0)
+                   {
+                      ep2 = eina_list_nth(edc->parts, ep2->clip_to_id);
+                      if (eina_list_data_find(hist, ep2))
+                        {
+                           ERR("clip_to loops. invalidating loop.");
+                           ep2->clip_to_id = -1;
+                           break;
+                        }
+                      hist = eina_list_append(hist, ep2);
+                   }
+                 eina_list_free(hist);
+                 hist = NULL;
+              }
+         }
+     }
+   if (edc_ret) *edc_ret = edc;
+
+   if (eina_hash_population(edf->collection_hash) == 0)
+     {
+       eina_hash_free(edf->collection_hash);
+       edf->collection_hash = NULL;
+     }
+   return edf;
+}
+
+void
+_edje_cache_coll_clean(Edje_File *edf)
+{
+   int count;
+
+   count = eina_list_count(edf->collection_cache);
+   while ((edf->collection_cache) && (count > _edje_collection_cache_size))
+     {
+       Edje_Part_Collection *edc;
+
+       edc = eina_list_data_get(eina_list_last(edf->collection_cache));
+       edf->collection_cache = eina_list_remove_list(edf->collection_cache, eina_list_last(edf->collection_cache));
+       _edje_collection_free(edf, edc);
+       count = eina_list_count(edf->collection_cache);
+     }
+}
+
+void
+_edje_cache_coll_flush(Edje_File *edf)
+{
+   while (edf->collection_cache)
+     {
+       Edje_Part_Collection *edc;
+
+       edc = eina_list_data_get(eina_list_last(edf->collection_cache));
+       edf->collection_cache = eina_list_remove_list(edf->collection_cache, eina_list_last(edf->collection_cache));
+       _edje_collection_free(edf, edc);
+     }
+}
+
+void
+_edje_cache_coll_unref(Edje_File *edf, Edje_Part_Collection *edc)
+{
+   edc->references--;
+   if (edc->references != 0) return;
+   eina_hash_del(edf->collection_hash, edc->part, edc);
+   if (eina_hash_population(edf->collection_hash) == 0)
+     {
+       eina_hash_free(edf->collection_hash);
+       edf->collection_hash = NULL;
+     }
+   edf->collection_cache = eina_list_prepend(edf->collection_cache, edc);
+   _edje_cache_coll_clean(edf);
+}
+
+static void
+_edje_cache_file_clean(void)
+{
+   int count;
+
+   count = eina_list_count(_edje_file_cache);
+   while ((_edje_file_cache) && (count > _edje_file_cache_size))
+     {
+       Edje_File *edf;
+
+       edf = eina_list_data_get(eina_list_last(_edje_file_cache));
+       _edje_file_cache = eina_list_remove_list(_edje_file_cache, eina_list_last(_edje_file_cache));
+       _edje_file_free(edf);
+       count = eina_list_count(_edje_file_cache);
+     }
+}
+
+void
+_edje_cache_file_unref(Edje_File *edf)
+{
+   edf->references--;
+   if (edf->references != 0) return;
+
+   if (edf->dangling)
+     {
+       _edje_file_free(edf);
+       return;
+     }
+
+   eina_hash_del(_edje_file_hash, edf->path, edf);
+   if (!eina_hash_population(_edje_file_hash))
+     {
+       eina_hash_free(_edje_file_hash);
+       _edje_file_hash = NULL;
+     }
+   _edje_file_cache = eina_list_prepend(_edje_file_cache, edf);
+   _edje_cache_file_clean();
+}
+
+void
+_edje_file_cache_shutdown(void)
+{
+   edje_file_cache_flush();
+}
+
+
+
+/**
+ * @endcond
+ */
+
+/*============================================================================*
+ *                                 Global                                     *
+ *============================================================================*/
+
+/*============================================================================*
+ *                                   API                                      *
+ *============================================================================*/
+
+/**
+ * @addtogroup Edje_cache_Group Cache
+ *
+ * @brief These functions provide an abstraction layer between the
+ * application code and the interface, while allowing extremely
+ * flexible dynamic layouts and animations.
+ *
+ * @{
+ */
+
+/**
+ * @brief Set the file cache size.
+ *
+ * @param count The file cache size in edje file units. Default is 16.
+ *
+ * This function sets the file cache size. Edje keeps this cache in
+ * order to prevent duplicates of edje file entries in memory. The
+ * file cache size can be retrieved with edje_file_cache_get().
+ *
+ * @see edje_file_cache_get()
+ * @see edje_file_cache_flush()
+ *
+ */
+
+EAPI void
+edje_file_cache_set(int count)
+{
+   if (count < 0) count = 0;
+   _edje_file_cache_size = count;
+   _edje_cache_file_clean();
+}
+
+/**
+ * @brief Return the file cache size.
+ *
+ * @return The file cache size in edje file units. Default is 16.
+ *
+ * This function returns the file cache size set by
+ * edje_file_cache_set().
+ *
+ * @see edje_file_cache_set()
+ * @see edje_file_cache_flush()
+ *
+ */
+
+EAPI int
+edje_file_cache_get(void)
+{
+   return _edje_file_cache_size;
+}
+
+/**
+ * @brief Clean the file cache.
+ *
+ * @return The file cache size.
+ *
+ * This function cleans the file cache entries, but keeps this cache's
+ * size to the last value set.
+ *
+ * @see edje_file_cache_set()
+ * @see edje_file_cache_get()
+ *
+ */
+
+EAPI void
+edje_file_cache_flush(void)
+{
+   int ps;
+
+   ps = _edje_file_cache_size;
+   _edje_file_cache_size = 0;
+   _edje_cache_file_clean();
+   _edje_file_cache_size = ps;
+}
+
+/**
+ * @brief Set the collection cache size.
+ *
+ * @param count The collection cache size, in edje object units. Default is 16.
+ *
+ * This function sets the collection cache size. Edje keeps this cache
+ * in order to prevent duplicates of edje {collection,group,part}
+ * entries in memory. The collection cache size can be retrieved with
+ * edje_collection_cache_get().
+ *
+ * @see edje_collection_cache_get()
+ * @see edje_collection_cache_flush()
+ *
+ */
+
+EAPI void
+edje_collection_cache_set(int count)
+{
+   Eina_List *l;
+   Edje_File *edf;
+
+   if (count < 0) count = 0;
+   _edje_collection_cache_size = count;
+   EINA_LIST_FOREACH(_edje_file_cache, l, edf)
+     _edje_cache_coll_clean(edf);
+   /* FIXME: freach in file hash too! */
+}
+
+/**
+ * @brief Return the collection cache size.
+ *
+ * @return The collection cache size, in edje object units. Default is 16.
+ *
+ * This function returns the collection cache size set by
+ * edje_collection_cache_set().
+ *
+ * @see edje_collection_cache_set()
+ * @see edje_collection_cache_flush()
+ *
+ */
+
+EAPI int
+edje_collection_cache_get(void)
+{
+   return _edje_collection_cache_size;
+}
+
+/**
+ * @brief Clean the collection cache.
+ *
+ * @return The collection cache size.
+ *
+ * This function cleans the collection cache, but keeps this cache's
+ * size to the last value set.
+ *
+ * @see edje_collection_cache_set()
+ * @see edje_collection_cache_get()
+ *
+ */
+
+EAPI void
+edje_collection_cache_flush(void)
+{
+   int ps;
+   Eina_List *l;
+   Edje_File *edf;
+
+   ps = _edje_collection_cache_size;
+   _edje_collection_cache_size = 0;
+   EINA_LIST_FOREACH(_edje_file_cache, l, edf)
+     _edje_cache_coll_flush(edf);
+   /* FIXME: freach in file hash too! */
+   _edje_collection_cache_size = ps;
+}
+
+/**
+ *
+ * @}
+ */
diff --git a/src/lib/edje_calc.c b/src/lib/edje_calc.c
new file mode 100644 (file)
index 0000000..6e48ccd
--- /dev/null
@@ -0,0 +1,2473 @@
+/*
+ * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
+ */
+
+#include <string.h>
+#include <math.h>
+
+#include "edje_private.h"
+
+#define FLAG_NONE 0
+#define FLAG_X    0x01
+#define FLAG_Y    0x02
+#define FLAG_XY   (FLAG_X | FLAG_Y)
+
+static void _edje_part_recalc_single(Edje *ed, Edje_Real_Part *ep, Edje_Part_Description *desc, Edje_Part_Description *chosen_desc, Edje_Real_Part *rel1_to_x, Edje_Real_Part *rel1_to_y, Edje_Real_Part *rel2_to_x, Edje_Real_Part *rel2_to_y, Edje_Real_Part *confine_to, Edje_Calc_Params *params, int flags);
+static void _edje_part_recalc(Edje *ed, Edje_Real_Part *ep, int flags);
+
+void
+_edje_part_pos_set(Edje *ed, Edje_Real_Part *ep, int mode, FLOAT_T pos)
+{
+   FLOAT_T fp_pos;
+   FLOAT_T npos;
+
+   pos = CLAMP(pos, ZERO, FROM_INT(1));
+
+   fp_pos = pos;
+
+   npos = ZERO;
+   /* take linear pos along timescale and use interpolation method */
+   switch (mode)
+     {
+      case EDJE_TWEEN_MODE_SINUSOIDAL:
+        /* npos = (1.0 - cos(pos * PI)) / 2.0; */
+        npos = DIV2(SUB(FROM_INT(1),
+                        COS(MUL(fp_pos,
+                                PI))));
+        break;
+      case EDJE_TWEEN_MODE_ACCELERATE:
+        /* npos = 1.0 - sin((PI / 2.0) + (pos * PI / 2.0)); */
+        npos = SUB(FROM_INT(1),
+                   SIN(ADD(DIV2(PI),
+                           MUL(fp_pos,
+                               DIV2(PI)))));
+        break;
+      case EDJE_TWEEN_MODE_DECELERATE:
+        /* npos = sin(pos * PI / 2.0); */
+        npos = SIN(MUL(fp_pos,
+                       DIV2(PI)));
+       break;
+      case EDJE_TWEEN_MODE_LINEAR:
+        npos = fp_pos;
+        break;
+      default:
+        break;
+     }
+   if (npos == ep->description_pos) return;
+
+   ep->description_pos = npos;
+
+   ed->dirty = 1;
+#ifdef EDJE_CALC_CACHE
+   ep->invalidate = 1;
+#endif
+}
+
+Edje_Part_Description *
+_edje_part_description_find(Edje *ed __UNUSED__, Edje_Real_Part *rp, const char *name,
+                            double val)
+{
+   Edje_Part *ep = rp->part;
+   Edje_Part_Description *ret = NULL;
+   Edje_Part_Description *d;
+   Eina_List *l;
+   double min_dst = 99999.0;
+
+   if (!strcmp(name, "default") && val == 0.0)
+     return ep->default_desc;
+
+   if (!strcmp(name, "custom"))
+     return rp->custom ? rp->custom->description : NULL;
+
+   if (!strcmp(name, "default"))
+     {
+       ret = ep->default_desc;
+       min_dst = ABS(ep->default_desc->state.value - val);
+     }
+   EINA_LIST_FOREACH(ep->other_desc, l, d)
+     {
+       if (!strcmp(d->state.name, name))
+         {
+            double dst;
+
+            dst = ABS(d->state.value - val);
+            if (dst < min_dst)
+              {
+                 ret = d;
+                 min_dst = dst;
+              }
+         }
+     }
+
+   return ret;
+}
+
+void
+_edje_part_description_apply(Edje *ed, Edje_Real_Part *ep, const char *d1, double v1, const char *d2, double v2)
+{
+   Edje_Part_Description *epd1;
+   Edje_Part_Description *epd2 = NULL;
+   Edje_Part_Description *chosen_desc;
+
+   if (!d1) d1 = "default";
+
+   epd1 = _edje_part_description_find(ed, ep, d1, v1);
+   if (!epd1)
+     epd1 = ep->part->default_desc; /* never NULL */
+
+   if (d2)
+     epd2 = _edje_part_description_find(ed, ep, d2, v2);
+
+   /* There is an animation if both description are different or if description is an image with tweens */
+   if (epd2 != NULL && (epd1 != epd2 || (ep->part->type == EDJE_PART_TYPE_IMAGE && epd2->image.tween_list)))
+     {
+       if (!ep->param2)
+         ep->param2 = eina_mempool_malloc(_edje_real_part_state_mp, sizeof (Edje_Real_Part_State));
+       else if (ep->part->type == EDJE_PART_TYPE_EXTERNAL)
+         _edje_external_parsed_params_free(ep->swallowed_object, ep->param2->external_params);
+       ep->param2->external_params = NULL;
+     }
+   else
+     if (ep->param2)
+       {
+         if (ep->part->type == EDJE_PART_TYPE_EXTERNAL)
+           _edje_external_parsed_params_free(ep->swallowed_object, ep->param2->external_params);
+         eina_mempool_free(_edje_real_part_state_mp, ep->param2);
+         ep->param2 = NULL;
+       }
+
+   chosen_desc = ep->chosen_description;
+   ep->param1.description = epd1;
+   ep->chosen_description = epd1;
+
+   ep->param1.rel1_to_x = ep->param1.rel1_to_y = NULL;
+   ep->param1.rel2_to_x = ep->param1.rel2_to_y = NULL;
+
+   if (ep->param1.description->rel1.id_x >= 0)
+     ep->param1.rel1_to_x = ed->table_parts[ep->param1.description->rel1.id_x % ed->table_parts_size];
+   if (ep->param1.description->rel1.id_y >= 0)
+     ep->param1.rel1_to_y = ed->table_parts[ep->param1.description->rel1.id_y % ed->table_parts_size];
+   if (ep->param1.description->rel2.id_x >= 0)
+     ep->param1.rel2_to_x = ed->table_parts[ep->param1.description->rel2.id_x % ed->table_parts_size];
+   if (ep->param1.description->rel2.id_y >= 0)
+     ep->param1.rel2_to_y = ed->table_parts[ep->param1.description->rel2.id_y % ed->table_parts_size];
+
+   if (ep->part->type == EDJE_PART_TYPE_EXTERNAL)
+     {
+       if (ep->param1.external_params)
+         _edje_external_parsed_params_free(ep->swallowed_object, ep->param1.external_params);
+       ep->param1.external_params = _edje_external_params_parse(ep->swallowed_object, ep->param1.description->external_params);
+     }
+
+   if (ep->param2)
+     {
+       ep->param2->description = epd2;
+
+       ep->param2->rel1_to_x = ep->param2->rel1_to_y = NULL;
+       ep->param2->rel2_to_x = ep->param2->rel2_to_y = NULL;
+
+       if (ep->param2->description)
+         {
+            if (ep->param2->description->rel1.id_x >= 0)
+              ep->param2->rel1_to_x = ed->table_parts[ep->param2->description->rel1.id_x % ed->table_parts_size];
+            if (ep->param2->description->rel1.id_y >= 0)
+              ep->param2->rel1_to_y = ed->table_parts[ep->param2->description->rel1.id_y % ed->table_parts_size];
+            if (ep->param2->description->rel2.id_x >= 0)
+              ep->param2->rel2_to_x = ed->table_parts[ep->param2->description->rel2.id_x % ed->table_parts_size];
+            if (ep->param2->description->rel2.id_y >= 0)
+              ep->param2->rel2_to_y = ed->table_parts[ep->param2->description->rel2.id_y % ed->table_parts_size];
+
+            if (ep->part->type == EDJE_PART_TYPE_EXTERNAL)
+              ep->param2->external_params = _edje_external_params_parse(ep->swallowed_object, ep->param2->description->external_params);
+         }
+
+       if (ep->description_pos != 0.0)
+         ep->chosen_description = epd2;
+     }
+
+   if (chosen_desc != ep->chosen_description &&
+       ep->part->type == EDJE_PART_TYPE_EXTERNAL)
+     _edje_external_recalc_apply(ed, ep, NULL, chosen_desc);
+
+   ed->dirty = 1;
+#ifdef EDJE_CALC_CACHE
+   ep->invalidate = 1;
+#endif
+}
+
+void
+_edje_recalc(Edje *ed)
+{
+   if ((ed->freeze > 0) || (_edje_freeze_val > 0))
+     {
+       ed->recalc = 1;
+       if (!ed->calc_only)
+         {
+            if (_edje_freeze_val > 0)
+               {
+                  if (!ed->freeze_calc)
+                    {
+                       _edje_freeze_calc_count++;
+                       _edje_freeze_calc_list = eina_list_append(_edje_freeze_calc_list, ed);
+                       ed->freeze_calc = 1;
+                    }
+               }
+            return;
+         }
+     }
+   if (ed->postponed) return;
+   evas_object_smart_changed(ed->obj);
+   ed->postponed = 1;
+}
+
+void
+_edje_recalc_do(Edje *ed)
+{
+   int i;
+
+   ed->postponed = 0;
+   evas_object_smart_need_recalculate_set(ed->obj, 0);
+   if (!ed->dirty) return;
+   ed->have_mapped_part = 0;
+   ed->dirty = 0;
+   ed->state++;
+   for (i = 0; i < ed->table_parts_size; i++)
+     {
+       Edje_Real_Part *ep;
+
+       ep = ed->table_parts[i];
+       ep->calculated = FLAG_NONE;
+       ep->calculating = FLAG_NONE;
+     }
+   for (i = 0; i < ed->table_parts_size; i++)
+     {
+       Edje_Real_Part *ep;
+
+       ep = ed->table_parts[i];
+       if (ep->calculated != FLAG_XY)
+         _edje_part_recalc(ed, ep, (~ep->calculated) & FLAG_XY);
+     }
+   if (!ed->calc_only) ed->recalc = 0;
+#ifdef EDJE_CALC_CACHE
+   ed->all_part_change = 0;
+   ed->text_part_change = 0;
+#endif
+}
+
+void
+_edje_part_recalc_1(Edje *ed, Edje_Real_Part *ep)
+{
+   _edje_part_recalc(ed, ep, FLAG_XY);
+}
+
+int
+_edje_part_dragable_calc(Edje *ed, Edje_Real_Part *ep, FLOAT_T *x, FLOAT_T *y)
+{
+   if (ep->drag)
+     {
+       if (ep->drag->confine_to)
+         {
+            FLOAT_T dx, dy, dw, dh;
+            int ret = 0;
+
+            if ((ep->part->dragable.x != 0) &&
+                (ep->part->dragable.y != 0 )) ret = 3;
+            else if (ep->part->dragable.x != 0) ret = 1;
+            else if (ep->part->dragable.y != 0) ret = 2;
+
+            dx = FROM_INT(ep->x - ep->drag->confine_to->x);
+            dw = FROM_INT(ep->drag->confine_to->w - ep->w);
+            if (dw != ZERO) dx = DIV(dx, dw);
+            else dx = ZERO;
+
+            dy = FROM_INT(ep->y - ep->drag->confine_to->y);
+            dh = FROM_INT(ep->drag->confine_to->h - ep->h);
+            if (dh != ZERO) dy = DIV(dy, dh);
+            else dy = ZERO;
+
+            if (x) *x = dx;
+            if (y) *y = dy;
+
+            return ret;
+         }
+       else
+         {
+            if (x) *x = ADD(FROM_INT(ep->drag->tmp.x), ep->drag->x);
+            if (y) *y = ADD(FROM_INT(ep->drag->tmp.y), ep->drag->y);
+            return 0;
+         }
+     }
+   if (x) *x = ZERO;
+   if (y) *y = ZERO;
+   return 0;
+   ed = NULL;
+}
+
+void
+_edje_dragable_pos_set(Edje *ed, Edje_Real_Part *ep, FLOAT_T x, FLOAT_T y)
+{
+   /* check whether this part is dragable at all */
+   if (!ep->drag) return ;
+
+   /* instead of checking for equality, we really should check that
+    * the difference is greater than foo, but I have no idea what
+    * value we would set foo to, because it would depend on the
+    * size of the dragable...
+    */
+   if (ep->drag->x != x || ep->drag->tmp.x)
+     {
+       ep->drag->x = x;
+       ep->drag->tmp.x = 0;
+       ep->drag->need_reset = 0;
+       ed->dirty = 1;
+     }
+
+   if (ep->drag->y != y || ep->drag->tmp.y)
+     {
+       ep->drag->y = y;
+       ep->drag->tmp.y = 0;
+       ep->drag->need_reset = 0;
+       ed->dirty = 1;
+     }
+
+#ifdef EDJE_CALC_CACHE
+   ep->invalidate = 1;
+#endif
+   _edje_recalc(ed); /* won't do anything if dirty flag isn't set */
+}
+
+static void
+_edje_part_recalc_single_rel(Edje *ed,
+                            Edje_Real_Part *ep __UNUSED__,
+                            Edje_Part_Description *desc,
+                            Edje_Real_Part *rel1_to_x,
+                            Edje_Real_Part *rel1_to_y,
+                            Edje_Real_Part *rel2_to_x,
+                            Edje_Real_Part *rel2_to_y,
+                            Edje_Calc_Params *params,
+                            int flags)
+{
+   if (flags & FLAG_X)
+     {
+        FLOAT_T x, w;
+
+       if (rel1_to_x)
+         x = ADD(FROM_INT(desc->rel1.offset_x + rel1_to_x->x),
+                 SCALE(desc->rel1.relative_x, rel1_to_x->w));
+       else
+         x = ADD(FROM_INT(desc->rel1.offset_x),
+                 SCALE(desc->rel1.relative_x, ed->w));
+       params->x = TO_INT(x);
+
+       if (rel2_to_x)
+         w = ADD(SUB(ADD(FROM_INT(desc->rel2.offset_x + rel2_to_x->x),
+                         SCALE(desc->rel2.relative_x, rel2_to_x->w)),
+                     x),
+                 FROM_INT(1));
+       else
+         w = ADD(SUB(ADD(FROM_INT(desc->rel2.offset_x),
+                         SCALE(desc->rel2.relative_x, ed->w)),
+                     x),
+                 FROM_INT(1));
+       params->w = TO_INT(w);
+     }
+   if (flags & FLAG_Y)
+     {
+        FLOAT_T y, h;
+
+       if (rel1_to_y)
+         y = ADD(FROM_INT(desc->rel1.offset_y + rel1_to_y->y),
+                 SCALE(desc->rel1.relative_y, rel1_to_y->h));
+       else
+         y = ADD(FROM_INT(desc->rel1.offset_y),
+                 SCALE(desc->rel1.relative_y, ed->h));
+       params->y = TO_INT(y);
+
+       if (rel2_to_y)
+         h = ADD(SUB(ADD(FROM_INT(desc->rel2.offset_y + rel2_to_y->y),
+                         SCALE(desc->rel2.relative_y, rel2_to_y->h)),
+                     y),
+                 FROM_INT(1));
+       else
+         h = ADD(SUB(ADD(FROM_INT(desc->rel2.offset_y),
+                         SCALE(desc->rel2.relative_y, ed->h)),
+                     y),
+                 FROM_INT(1));
+       params->h = TO_INT(h);
+     }
+}
+
+static void
+_edje_part_recalc_single_aspect(Edje_Real_Part *ep,
+                               Edje_Part_Description *desc,
+                               Edje_Calc_Params *params,
+                               int *minw, int *minh,
+                               int *maxw, int *maxh)
+{
+   int apref = -10;
+   FLOAT_T aspect, amax, amin;
+   FLOAT_T new_w = ZERO, new_h = ZERO, want_x, want_y, want_w, want_h;
+
+   if (params->h <= ZERO) aspect = FROM_INT(999999);
+   else aspect = DIV(FROM_INT(params->w), FROM_INT(params->h));
+   amax = desc->aspect.max;
+   amin = desc->aspect.min;
+   if ((ep->swallow_params.aspect.w > 0) &&
+       (ep->swallow_params.aspect.h > 0))
+     amin = amax =
+       DIV(FROM_INT(ep->swallow_params.aspect.w),
+          FROM_INT(ep->swallow_params.aspect.h));
+   want_x = FROM_INT(params->x);
+   want_w = new_w = FROM_INT(params->w);
+
+   want_y = FROM_INT(params->y);
+   want_h = new_h = FROM_INT(params->h);
+
+   if ((amin > ZERO) && (amax > ZERO))
+     {
+       apref = desc->aspect.prefer;
+       if (ep->swallow_params.aspect.mode > EDJE_ASPECT_CONTROL_NONE)
+         {
+            switch (ep->swallow_params.aspect.mode)
+              {
+               case EDJE_ASPECT_CONTROL_NEITHER:
+                  apref = EDJE_ASPECT_PREFER_NONE;
+                  break;
+               case EDJE_ASPECT_CONTROL_HORIZONTAL:
+                  apref = EDJE_ASPECT_PREFER_HORIZONTAL;
+                  break;
+               case EDJE_ASPECT_CONTROL_VERTICAL:
+                  apref = EDJE_ASPECT_PREFER_VERTICAL;
+                  break;
+               case EDJE_ASPECT_CONTROL_BOTH:
+                  apref = EDJE_ASPECT_PREFER_BOTH;
+                  break;
+               default:
+                  break;
+              }
+         }
+       switch (apref)
+         {
+          case EDJE_ASPECT_PREFER_NONE:
+             /* keep both dimensions in check */
+             /* adjust for min aspect (width / height) */
+             if ((amin > ZERO) && (aspect < amin))
+               {
+                  new_h = DIV(FROM_INT(params->w), amin);
+                  new_w = SCALE(amin, params->h);
+               }
+             /* adjust for max aspect (width / height) */
+             if ((amax > ZERO) && (aspect > amax))
+               {
+                  new_h = DIV(FROM_INT(params->w), amax);
+                  new_w = SCALE(amax, params->h);
+               }
+             if ((amax > ZERO) && (new_w < FROM_INT(params->w)))
+               {
+                  new_w = FROM_INT(params->w);
+                  new_h = DIV(FROM_INT(params->w), amax);
+               }
+             if ((amax > ZERO) && (new_h < FROM_INT(params->h)))
+               {
+                  new_w = SCALE(amax, params->h);
+                  new_h = FROM_INT(params->h);
+               }
+             break;
+             /* prefer vertical size as determiner */
+          case  EDJE_ASPECT_PREFER_VERTICAL:
+             /* keep both dimensions in check */
+             /* adjust for max aspect (width / height) */
+             if ((amax > ZERO) && (aspect > amax))
+               new_w = SCALE(amax, params->h);
+             /* adjust for min aspect (width / height) */
+             if ((amin > ZERO) && (aspect < amin))
+               new_w = SCALE(amin, params->h);
+             break;
+             /* prefer horizontal size as determiner */
+          case EDJE_ASPECT_PREFER_HORIZONTAL:
+             /* keep both dimensions in check */
+             /* adjust for max aspect (width / height) */
+             if ((amax > ZERO) && (aspect > amax))
+               new_h = DIV(FROM_INT(params->w), amax);
+             /* adjust for min aspect (width / height) */
+             if ((amin > ZERO) && (aspect < amin))
+               new_h = DIV(FROM_INT(params->w), amin);
+             break;
+          case EDJE_ASPECT_PREFER_BOTH:
+             /* keep both dimensions in check */
+             /* adjust for max aspect (width / height) */
+             if ((amax > ZERO) && (aspect > amax))
+               {
+                  new_w = SCALE(amax, params->h);
+                  new_h = DIV(FROM_INT(params->w), amax);
+               }
+             /* adjust for min aspect (width / height) */
+             if ((amin > ZERO) && (aspect < amin))
+               {
+                  new_w = SCALE(amin, params->h);
+                  new_h = DIV(FROM_INT(params->w), amin);
+               }
+             break;
+          default:
+             break;
+         }
+
+       if (!((amin > ZERO) && (amax > ZERO) && (apref == EDJE_ASPECT_PREFER_NONE)))
+         {
+            if ((*maxw >= 0) && (new_w > FROM_INT(*maxw)))
+               new_w = FROM_INT(*maxw);
+            if (new_w < FROM_INT(*minw))
+               new_w = FROM_INT(*minw);
+
+            if ((FROM_INT(*maxh) >= 0) && (new_h > FROM_INT(*maxh))) 
+               new_h = FROM_INT(*maxh);
+            if (new_h < FROM_INT(*minh))
+               new_h = FROM_INT(*minh);
+         }
+
+       /* do real adjustment */
+       if (apref == EDJE_ASPECT_PREFER_BOTH)
+         {
+            if (amin == ZERO) amin = amax;
+            if (amin != ZERO)
+              {
+                 /* fix h and vary w */
+                 if (new_w > FROM_INT(params->w))
+                   {
+                      //                 params->w = new_w;
+                      // EXCEEDS BOUNDS in W
+                      new_h = DIV(FROM_INT(params->w), amin);
+                      new_w = FROM_INT(params->w);
+                      if (new_h > FROM_INT(params->h))
+                        {
+                           new_h = FROM_INT(params->h);
+                           new_w = SCALE(amin, params->h);
+                        }
+                   }
+                 /* fix w and vary h */
+                 else
+                   {
+                      //                 params->h = new_h;
+                      // EXCEEDS BOUNDS in H
+                      new_h = FROM_INT(params->h);
+                      new_w = SCALE(amin, params->h);
+                      if (new_w > FROM_INT(params->w))
+                        {
+                           new_h = DIV(FROM_INT(params->w), amin);
+                           new_w = FROM_INT(params->w);
+                        }
+                   }
+                 params->w = TO_INT(new_w);
+                 params->h = TO_INT(new_h);
+              }
+         }
+     }
+   if (apref != EDJE_ASPECT_PREFER_BOTH)
+     {
+       if ((amin > 0.0) && (amax > ZERO) && (apref == EDJE_ASPECT_PREFER_NONE))
+         {
+            params->w = TO_INT(new_w);
+            params->h = TO_INT(new_h);
+         }
+       else if ((FROM_INT(params->h) - new_h) > (FROM_INT(params->w) - new_w))
+         {
+            if (params->h < TO_INT(new_h))
+              params->h = TO_INT(new_h);
+            else if (params->h > TO_INT(new_h))
+              params->h = TO_INT(new_h);
+            if (apref == EDJE_ASPECT_PREFER_VERTICAL)
+              params->w = TO_INT(new_w);
+         }
+       else
+         {
+            if (params->w < TO_INT(new_w))
+              params->w = TO_INT(new_w);
+            else if (params->w > TO_INT(new_w))
+              params->w = TO_INT(new_w);
+            if (apref == EDJE_ASPECT_PREFER_HORIZONTAL)
+              params->h = TO_INT(new_h);
+         }
+     }
+   params->x = TO_INT(ADD(want_x,
+                         MUL(SUB(want_w, FROM_INT(params->w)),
+                             desc->align.x)));
+   params->y = TO_INT(ADD(want_y,
+                         MUL(SUB(want_h, FROM_INT(params->h)),
+                             desc->align.y)));
+}
+
+static void
+_edje_part_recalc_single_step(Edje_Part_Description *desc,
+                             Edje_Calc_Params *params,
+                             int flags)
+{
+   if (flags & FLAG_X)
+     {
+       if (desc->step.x > 0)
+         {
+            int steps;
+            int new_w;
+
+            steps = params->w / desc->step.x;
+            new_w = desc->step.x * steps;
+            if (params->w > new_w)
+              {
+                 params->x += TO_INT(SCALE(desc->align.x, (params->w - new_w)));
+                 params->w = new_w;
+              }
+         }
+     }
+   if (flags & FLAG_Y)
+     {
+       if (desc->step.y > 0)
+         {
+            int steps;
+            int new_h;
+
+            steps = params->h / desc->step.y;
+            new_h = desc->step.y * steps;
+            if (params->h > new_h)
+              {
+                 params->y += TO_INT(SCALE(desc->align.y, (params->h - new_h)));
+                 params->h = new_h;
+              }
+         }
+     }
+}
+
+static void
+_edje_part_recalc_single_textblock(FLOAT_T sc,
+                                  Edje *ed,
+                                  Edje_Real_Part *ep,
+                                  Edje_Part_Description *chosen_desc,
+                                  Edje_Calc_Params *params,
+                                  int *minw, int *minh,
+                                  int *maxw, int *maxh)
+{
+   if (chosen_desc)
+     {
+       Evas_Coord tw, th, ins_l, ins_r, ins_t, ins_b;
+       const char *text = "";
+       const char *style = "";
+       Edje_Style *stl  = NULL;
+       Eina_List *l;
+
+       if (chosen_desc->text.id_source >= 0)
+         {
+            ep->text.source = ed->table_parts[chosen_desc->text.id_source % ed->table_parts_size];
+            if (ep->text.source->chosen_description->text.style)
+              style = ep->text.source->chosen_description->text.style;
+         }
+       else
+         {
+            ep->text.source = NULL;
+            if (chosen_desc->text.style)
+              style = chosen_desc->text.style;
+         }
+
+       if (chosen_desc->text.id_text_source >= 0)
+         {
+            ep->text.text_source = ed->table_parts[chosen_desc->text.id_text_source % ed->table_parts_size];
+            text = ep->text.text_source->chosen_description->text.text;
+            if (ep->text.text_source->text.text) text = ep->text.text_source->text.text;
+         }
+       else
+         {
+            ep->text.text_source = NULL;
+            text = chosen_desc->text.text;
+            if (ep->text.text) text = ep->text.text;
+         }
+
+       EINA_LIST_FOREACH(ed->file->styles, l, stl)
+         {
+            if ((stl->name) && (!strcmp(stl->name, style))) break;
+            stl = NULL;
+         }
+
+       if (ep->part->scale)
+         evas_object_scale_set(ep->object, TO_DOUBLE(sc));
+
+       if (stl)
+         {
+            const char *ptxt;
+
+            if (evas_object_textblock_style_get(ep->object) != stl->style)
+              evas_object_textblock_style_set(ep->object, stl->style);
+            // FIXME: need to account for editing
+            if (ep->part->entry_mode > EDJE_ENTRY_EDIT_MODE_NONE)
+              {
+                 // do nothing - should be done elsewhere
+              }
+            else
+              {
+                 ptxt = evas_object_textblock_text_markup_get(ep->object);
+                 if (((!ptxt) && (text)) ||
+                     ((ptxt) && (text) && (strcmp(ptxt, text))) ||
+                     ((ptxt) && (!text)))
+                   evas_object_textblock_text_markup_set(ep->object, text);
+              }
+            if ((chosen_desc->text.min_x) || (chosen_desc->text.min_y))
+              {
+                 int mw = 0, mh = 0;
+
+                 tw = th = 0;
+                 if (!chosen_desc->text.min_x)
+                   {
+                      evas_object_resize(ep->object, params->w, params->h);
+                      evas_object_textblock_size_formatted_get(ep->object, &tw, &th);
+                   }
+                 else
+                   evas_object_textblock_size_native_get(ep->object, &tw, &th);
+                 evas_object_textblock_style_insets_get(ep->object, &ins_l, &ins_r, &ins_t, &ins_b);
+                 mw = ins_l + tw + ins_r;
+                 mh = ins_t + th + ins_b;
+//               if (chosen_desc->text.min_x)
+                   {
+                      if (mw > *minw) *minw = mw;
+                   }
+//               if (chosen_desc->text.min_y)
+                   {
+                      if (mh > *minh) *minh = mh;
+                   }
+              }
+         }
+       if ((chosen_desc->text.max_x) || (chosen_desc->text.max_y))
+         {
+            int mw = 0, mh = 0;
+
+            tw = th = 0;
+            if (!chosen_desc->text.max_x)
+              {
+                 evas_object_resize(ep->object, params->w, params->h);
+                 evas_object_textblock_size_formatted_get(ep->object, &tw, &th);
+              }
+            else
+              evas_object_textblock_size_native_get(ep->object, &tw, &th);
+            evas_object_textblock_style_insets_get(ep->object, &ins_l, &ins_r, &ins_t, &ins_b);
+            mw = ins_l + tw + ins_r;
+            mh = ins_t + th + ins_b;
+            if (chosen_desc->text.max_x)
+              {
+                 if (mw > *maxw) *maxw = mw;
+              }
+            if (chosen_desc->text.max_y)
+              {
+                 if (mh > *maxw) *maxh = mh;
+              }
+         }
+     }
+}
+
+static void
+_edje_part_recalc_single_text(FLOAT_T sc,
+                             Edje *ed,
+                             Edje_Real_Part *ep,
+                             Edje_Part_Description *desc,
+                             Edje_Part_Description *chosen_desc,
+                             Edje_Calc_Params *params,
+                             int *minw, int *minh,
+                             int *maxw, int *maxh)
+{
+   char *sfont = NULL;
+   int size;
+
+   if (chosen_desc)
+     {
+       const char      *text;
+       const char      *font;
+       int              size;
+       Evas_Coord       tw, th;
+       int              inlined_font = 0;
+
+       /* Update a object_text part */
+
+       if (chosen_desc->text.id_source >= 0)
+         ep->text.source = ed->table_parts[chosen_desc->text.id_source % ed->table_parts_size];
+       else
+         ep->text.source = NULL;
+
+       if (chosen_desc->text.id_text_source >= 0)
+         ep->text.text_source = ed->table_parts[chosen_desc->text.id_text_source % ed->table_parts_size];
+       else
+         ep->text.text_source = NULL;
+
+       if (ep->text.text_source)
+         text = ep->text.text_source->chosen_description->text.text;
+       else
+         text = chosen_desc->text.text;
+
+       if (ep->text.source)
+         font = _edje_text_class_font_get(ed, ep->text.source->chosen_description, &size, &sfont);
+       else
+         font = _edje_text_class_font_get(ed, chosen_desc, &size, &sfont);
+
+       if (!font) font = "";
+
+       if (ep->text.text_source)
+         {
+            if (ep->text.text_source->text.text) text = ep->text.text_source->text.text;
+         }
+       else
+         {
+            if (ep->text.text) text = ep->text.text;
+         }
+
+       if (ep->text.source)
+         {
+            if (ep->text.source->text.font) font = ep->text.source->text.font;
+            if (ep->text.source->text.size > 0) size = ep->text.source->text.size;
+         }
+       else
+         {
+            if (ep->text.font) font = ep->text.font;
+            if (ep->text.size > 0) size = ep->text.size;
+         }
+       if (!text) text = "";
+
+        /* check if the font is embedded in the .eet */
+       if (ed->file->font_hash)
+         {
+            Edje_Font_Directory_Entry *fnt;
+
+            fnt = eina_hash_find(ed->file->font_hash, font);
+
+            if (fnt)
+              {
+                 font = fnt->path;
+                 inlined_font = 1;
+              }
+         }
+       if (ep->part->scale)
+         evas_object_scale_set(ep->object, TO_DOUBLE(sc));
+       if (inlined_font) evas_object_text_font_source_set(ep->object, ed->path);
+       else evas_object_text_font_source_set(ep->object, NULL);
+
+       if ((_edje_fontset_append) && (font))
+         {
+            char *font2;
+
+            font2 = malloc(strlen(font) + 1 + strlen(_edje_fontset_append) + 1);
+            if (font2)
+              {
+                 strcpy(font2, font);
+                 strcat(font2, ",");
+                 strcat(font2, _edje_fontset_append);
+                 evas_object_text_font_set(ep->object, font2, size);
+                 free(font2);
+              }
+         }
+       else
+         evas_object_text_font_set(ep->object, font, size);
+       if ((chosen_desc->text.min_x) || (chosen_desc->text.min_y) ||
+           (chosen_desc->text.max_x) || (chosen_desc->text.max_y))
+         {
+            int mw, mh;
+            Evas_Text_Style_Type style;
+            const Evas_Text_Style_Type styles[] = {
+               EVAS_TEXT_STYLE_PLAIN,
+               EVAS_TEXT_STYLE_PLAIN,
+               EVAS_TEXT_STYLE_OUTLINE,
+               EVAS_TEXT_STYLE_SOFT_OUTLINE,
+               EVAS_TEXT_STYLE_SHADOW,
+               EVAS_TEXT_STYLE_SOFT_SHADOW,
+               EVAS_TEXT_STYLE_OUTLINE_SHADOW,
+               EVAS_TEXT_STYLE_OUTLINE_SOFT_SHADOW,
+               EVAS_TEXT_STYLE_FAR_SHADOW,
+               EVAS_TEXT_STYLE_FAR_SOFT_SHADOW,
+               EVAS_TEXT_STYLE_GLOW
+            };
+
+            if (ep->part->effect < EDJE_TEXT_EFFECT_LAST)
+              style = styles[ep->part->effect];
+            else
+              style = EVAS_TEXT_STYLE_PLAIN;
+
+            evas_object_text_style_set(ep->object, style);
+            evas_object_text_text_set(ep->object, text);
+            evas_object_geometry_get(ep->object, NULL, NULL, &tw, &th);
+            if (chosen_desc->text.max_x)
+              {
+                 int l, r;
+                 evas_object_text_style_pad_get(ep->object, &l, &r, NULL, NULL);
+                 mw = tw + l + r;
+                 if ((*maxw < 0) || (mw < *maxw)) *maxw = mw;
+              }
+            if (chosen_desc->text.max_y)
+              {
+                 int t, b;
+                 evas_object_text_style_pad_get(ep->object, NULL, NULL, &t, &b);
+                 mh = th + t + b;
+                 if ((*maxh < 0) || (mh < *maxh)) *maxh = mh;
+              }
+            if (chosen_desc->text.min_x)
+              {
+                 int l, r;
+                 evas_object_text_style_pad_get(ep->object, &l, &r, NULL, NULL);
+                 mw = tw + l + r;
+                 if (mw > *minw) *minw = mw;
+              }
+            if (chosen_desc->text.min_y)
+              {
+                 int t, b;
+                 evas_object_text_style_pad_get(ep->object, NULL, NULL, &t, &b);
+                 mh = th + t + b;
+                 if (mh > *minh) *minh = mh;
+              }
+         }
+       if (sfont) free(sfont);
+     }
+
+   /* FIXME: Do we really need to call it twice if chosen_desc ? */
+   sfont = NULL;
+   _edje_text_class_font_get(ed, desc, &size, &sfont);
+   free(sfont);
+   params->type.text.size = size;
+}
+
+static void
+_edje_part_recalc_single_min(Edje_Part_Description *desc,
+                            Edje_Calc_Params *params,
+                            int minw, int minh,
+                            int flags)
+{
+   if (flags & FLAG_X)
+     {
+       if (minw >= 0)
+         {
+            if (params->w < minw)
+              {
+                 params->x += TO_INT(SCALE(desc->align.x, (params->w - minw)));
+                 params->w = minw;
+              }
+         }
+     }
+   if (flags & FLAG_Y)
+     {
+       if (minh >= 0)
+         {
+            if (params->h < minh)
+              {
+                 params->y += TO_INT(SCALE(desc->align.y, (params->h - minh)));
+                 params->h = minh;
+              }
+         }
+     }
+}
+
+static void
+_edje_part_recalc_single_max(Edje_Part_Description *desc,
+                            Edje_Calc_Params *params,
+                            int maxw, int maxh,
+                            int flags)
+{
+   if (flags & FLAG_X)
+     {
+       if (maxw >= 0)
+         {
+            if (params->w > maxw)
+              {
+                 params->x += TO_INT(SCALE(desc->align.x, (params->w - maxw)));
+                 params->w = maxw;
+              }
+         }
+     }
+   if (flags & FLAG_Y)
+     {
+       if (maxh >= 0)
+         {
+            if (params->h > maxh)
+              {
+                 params->y += TO_INT(SCALE(desc->align.y, (params->h - maxh)));
+                 params->h = maxh;
+              }
+         }
+     }
+}
+
+static void
+_edje_part_recalc_single_drag(Edje_Real_Part *ep,
+                             Edje_Real_Part *confine_to,
+                             Edje_Calc_Params *params,
+                             int minw, int minh,
+                             int maxw, int maxh,
+                             int flags)
+{
+   /* confine */
+   if (confine_to)
+     {
+       int offset;
+       int step;
+       FLOAT_T v;
+
+       /* complex dragable params */
+       if (flags & FLAG_X)
+         {
+            v = SCALE(ep->drag->size.x, confine_to->w);
+
+            if ((minw > 0) && (TO_INT(v) < minw)) params->w = minw;
+            else if ((maxw >= 0) && (TO_INT(v) > maxw)) params->w = maxw;
+            else params->w = TO_INT(v);
+
+            offset = TO_INT(SCALE(ep->drag->x, (confine_to->w - params->w)))
+              + ep->drag->tmp.x;
+            if (ep->part->dragable.step_x > 0)
+              {
+                 params->x = confine_to->x +
+                   ((offset / ep->part->dragable.step_x) * ep->part->dragable.step_x);
+              }
+            else if (ep->part->dragable.count_x > 0)
+              {
+                 step = (confine_to->w - params->w) / ep->part->dragable.count_x;
+                 if (step < 1) step = 1;
+                 params->x = confine_to->x +
+                   ((offset / step) * step);
+              }
+            params->req_drag.x = params->x;
+            params->req_drag.w = params->w;
+         }
+       if (flags & FLAG_Y)
+         {
+            v = SCALE(ep->drag->size.y, confine_to->h);
+
+            if ((minh > 0) && (TO_INT(v) < minh)) params->h = minh;
+            else if ((maxh >= 0) && (TO_INT(v) > maxh)) params->h = maxh;
+            else params->h = TO_INT(v);
+
+            offset = TO_INT(SCALE(ep->drag->y, (confine_to->h - params->h)))
+              + ep->drag->tmp.y;
+            if (ep->part->dragable.step_y > 0)
+              {
+                 params->y = confine_to->y +
+                   ((offset / ep->part->dragable.step_y) * ep->part->dragable.step_y);
+              }
+            else if (ep->part->dragable.count_y > 0)
+              {
+                 step = (confine_to->h - params->h) / ep->part->dragable.count_y;
+                 if (step < 1) step = 1;
+                 params->y = confine_to->y +
+                   ((offset / step) * step);
+              }
+            params->req_drag.y = params->y;
+            params->req_drag.h = params->h;
+         }
+       /* limit to confine */
+       if (flags & FLAG_X)
+         {
+            if (params->x < confine_to->x)
+              {
+                 params->x = confine_to->x;
+              }
+            if ((params->x + params->w) > (confine_to->x + confine_to->w))
+              {
+                 params->x = confine_to->x + confine_to->w - params->w;
+              }
+         }
+       if (flags & FLAG_Y)
+         {
+            if (params->y < confine_to->y)
+              {
+                 params->y = confine_to->y;
+              }
+            if ((params->y + params->h) > (confine_to->y + confine_to->h))
+              {
+                 params->y = confine_to->y + confine_to->h - params->h;
+              }
+         }
+     }
+   else
+     {
+       /* simple dragable params */
+       if (flags & FLAG_X)
+         {
+            params->x += TO_INT(ep->drag->x) + ep->drag->tmp.x;
+            params->req_drag.x = params->x;
+            params->req_drag.w = params->w;
+         }
+       if (flags & FLAG_Y)
+         {
+            params->y += TO_INT(ep->drag->y) + ep->drag->tmp.y;
+            params->req_drag.y = params->y;
+            params->req_drag.h = params->h;
+         }
+     }
+}
+
+static void
+_edje_part_recalc_single_fill(Edje_Real_Part *ep,
+                             Edje_Part_Description *desc,
+                             Edje_Calc_Params *params,
+                             int flags)
+{
+   if (ep->part->type == EDJE_PART_TYPE_GRADIENT && desc->gradient.use_rel && (!desc->gradient.type || !strcmp(desc->gradient.type, "linear")))
+     {
+       int x2, y2;
+       int dx, dy;
+       int angle;
+
+       params->type.common.fill.x = desc->gradient.rel1.offset_x
+         + TO_INT(SCALE(desc->gradient.rel1.relative_x, params->w));
+       params->type.common.fill.y = desc->gradient.rel1.offset_y
+         + TO_INT((SCALE(desc->gradient.rel1.relative_y, params->h)));
+
+       x2 = desc->gradient.rel2.offset_x
+         + TO_INT(SCALE(desc->gradient.rel2.relative_x, params->w));
+
+       y2 = desc->gradient.rel2.offset_y
+         + TO_INT(SCALE(desc->gradient.rel2.relative_y, params->h));
+
+       params->type.common.fill.w = 1; /* doesn't matter for linear grads */
+
+       dy = y2 - params->type.common.fill.y;
+       dx = x2 - params->type.common.fill.x;
+       params->type.common.fill.h = TO_INT(SQRT(FROM_INT(dx * dx + dy * dy)));
+
+       params->type.common.fill.spread = desc->fill.spread;
+
+       if (dx == 0 && dy == 0)
+         {
+            angle = 0;
+         }
+       else if (dx == 0)
+         {
+            if (dy > 0) angle = 0;
+            else angle = 180;
+         }
+       else if (dy == 0)
+         {
+            if (dx > 0) angle = 270;
+            else angle = 90;
+         }
+       else
+         {
+            double m; /* FIXME: atan isn't available atm in eina fp implementation */
+            m = (double)dx / (double)dy;
+            angle = atan(m) * 180 / M_PI;
+            if (dy < 0)
+              angle = 180 - angle;
+            else
+              angle = 360 - angle;
+         }
+       params->type.common.fill.angle = angle;
+     }
+   else
+     {
+       params->smooth = desc->fill.smooth;
+       if (flags & FLAG_X)
+         {
+            int fw;
+
+             if (desc->fill.type == EDJE_FILL_TYPE_TILE)
+              evas_object_image_size_get(ep->object, &fw, NULL);
+            else
+              fw = params->w;
+
+            params->type.common.fill.x = desc->fill.pos_abs_x
+              + TO_INT(SCALE(desc->fill.pos_rel_x, fw));
+            params->type.common.fill.w = desc->fill.abs_x
+              + TO_INT(SCALE(desc->fill.rel_x, fw));
+         }
+       if (flags & FLAG_Y)
+         {
+            int fh;
+
+             if (desc->fill.type == EDJE_FILL_TYPE_TILE)
+              evas_object_image_size_get(ep->object, NULL, &fh);
+            else
+              fh = params->h;
+
+            params->type.common.fill.y = desc->fill.pos_abs_y
+              + TO_INT(SCALE(desc->fill.pos_rel_y, fh));
+            params->type.common.fill.h = desc->fill.abs_y
+              + TO_INT(SCALE(desc->fill.rel_y, fh));
+         }
+       params->type.common.fill.angle = desc->fill.angle;
+       params->type.common.fill.spread = desc->fill.spread;
+     }
+
+}
+
+static void
+_edje_part_recalc_single_min_max(FLOAT_T sc,
+                                Edje_Real_Part *ep,
+                                Edje_Part_Description *desc,
+                                int *minw, int *minh,
+                                int *maxw, int *maxh,
+                                int flags __UNUSED__)
+{
+//   if (flags & FLAG_X)
+   {
+      *minw = desc->min.w;
+      if (ep->part->scale) *minw = TO_INT(SCALE(sc, *minw));
+      if (ep->swallow_params.min.w > desc->min.w)
+       *minw = ep->swallow_params.min.w;
+
+      /* XXX TODO: remove need of EDJE_INF_MAX_W, see edje_util.c */
+      if ((ep->swallow_params.max.w <= 0) ||
+         (ep->swallow_params.max.w == EDJE_INF_MAX_W))
+       {
+          *maxw = desc->max.w;
+          if (*maxw > 0)
+            {
+               if (ep->part->scale) *maxw = TO_INT(SCALE(sc, *maxw));
+               if (*maxw < 1) *maxw = 1;
+            }
+       }
+      else
+       {
+          if (desc->max.w <= 0)
+            *maxw = ep->swallow_params.max.w;
+          else
+            {
+               *maxw = desc->max.w;
+               if (*maxw > 0)
+                 {
+                    if (ep->part->scale) *maxw = TO_INT(SCALE(sc, *maxw));
+                    if (*maxw < 1) *maxw = 1;
+                 }
+               if (ep->swallow_params.max.w < *maxw)
+                 *maxw = ep->swallow_params.max.w;
+            }
+       }
+      if (*maxw >= 0)
+       {
+          if (*maxw < *minw) *maxw = *minw;
+       }
+   }
+//   if (flags & FLAG_Y)
+   {
+      *minh = desc->min.h;
+      if (ep->part->scale) *minh = TO_INT(SCALE(sc, *minh));
+      if (ep->swallow_params.min.h > desc->min.h)
+       *minh = ep->swallow_params.min.h;
+
+      /* XXX TODO: remove need of EDJE_INF_MAX_H, see edje_util.c */
+      if ((ep->swallow_params.max.h <= 0) ||
+         (ep->swallow_params.max.h == EDJE_INF_MAX_H))
+       {
+          *maxh = desc->max.h;
+          if (*maxh > 0)
+            {
+               if (ep->part->scale) *maxh = TO_INT(SCALE(sc, *maxh));
+               if (*maxh < 1) *maxh = 1;
+            }
+       }
+      else
+       {
+          if (desc->max.h <= 0)
+            *maxh = ep->swallow_params.max.h;
+          else
+            {
+               *maxh = desc->max.h;
+               if (*maxh > 0)
+                 {
+                    if (ep->part->scale) *maxh = TO_INT(SCALE(sc, *maxh));
+                    if (*maxh < 1) *maxh = 1;
+                 }
+               if (ep->swallow_params.max.h < *maxh)
+                 *maxh = ep->swallow_params.max.h;
+            }
+       }
+      if (*maxh >= 0)
+       {
+          if (*maxh < *minh) *maxh = *minh;
+       }
+   }
+}
+
+static void
+_edje_part_recalc_single(Edje *ed,
+                        Edje_Real_Part *ep,
+                        Edje_Part_Description *desc,
+                        Edje_Part_Description *chosen_desc,
+                        Edje_Real_Part *rel1_to_x,
+                        Edje_Real_Part *rel1_to_y,
+                        Edje_Real_Part *rel2_to_x,
+                        Edje_Real_Part *rel2_to_y,
+                        Edje_Real_Part *confine_to,
+                        Edje_Calc_Params *params,
+                        int flags)
+{
+   Edje_Color_Class *cc = NULL;
+   int minw = 0, minh = 0, maxw = 0, maxh = 0;
+   FLOAT_T sc;
+
+   flags = FLAG_XY;
+
+   sc = ed->scale;
+   if (sc == 0.0) sc = _edje_scale;
+   _edje_part_recalc_single_min_max(sc, ep, desc, &minw, &minh, &maxw, &maxh, flags);
+
+   /* relative coords of top left & bottom right */
+   _edje_part_recalc_single_rel(ed, ep, desc, rel1_to_x, rel1_to_y, rel2_to_x, rel2_to_y, params, flags);
+
+   /* aspect */
+   if (((flags | ep->calculated) & FLAG_XY) == FLAG_XY)
+     _edje_part_recalc_single_aspect(ep, desc, params, &minw, &minh, &maxw, &maxh);
+
+   /* size step */
+   _edje_part_recalc_single_step(desc, params, flags);
+
+   /* if we have text that wants to make the min size the text size... */
+   if (ep->part->type == EDJE_PART_TYPE_TEXTBLOCK)
+     _edje_part_recalc_single_textblock(sc, ed, ep, chosen_desc, params, &minw, &minh, &maxw, &maxh);
+   else if (ep->part->type == EDJE_PART_TYPE_TEXT)
+     _edje_part_recalc_single_text(sc, ed, ep, desc, chosen_desc, params, &minw, &minh, &maxw, &maxh);
+
+   /* remember what our size is BEFORE we go limit it */
+   params->req.x = params->x;
+   params->req.y = params->y;
+   params->req.w = params->w;
+   params->req.h = params->h;
+
+   /* adjust for min size */
+   _edje_part_recalc_single_min(desc, params, minw, minh, flags);
+
+   /* adjust for max size */
+   _edje_part_recalc_single_max(desc, params, maxw, maxh, flags);
+
+   /* take care of dragable part */
+   if (ep->drag)
+     _edje_part_recalc_single_drag(ep, confine_to, params, minw, minh, maxw, maxh, flags);
+
+   /* fill */
+   if (ep->part->type == EDJE_PART_TYPE_IMAGE ||
+       ep->part->type == EDJE_PART_TYPE_GRADIENT)
+     _edje_part_recalc_single_fill(ep, desc, params, flags);
+
+   /* colors */
+   if ((desc->color_class) && (*desc->color_class))
+     cc = _edje_color_class_find(ed, desc->color_class);
+
+   if (cc)
+     {
+       params->color.r = (((int)cc->r + 1) * desc->color.r) >> 8;
+       params->color.g = (((int)cc->g + 1) * desc->color.g) >> 8;
+       params->color.b = (((int)cc->b + 1) * desc->color.b) >> 8;
+       params->color.a = (((int)cc->a + 1) * desc->color.a) >> 8;
+     }
+   else
+     {
+       params->color.r = desc->color.r;
+       params->color.g = desc->color.g;
+       params->color.b = desc->color.b;
+       params->color.a = desc->color.a;
+     }
+
+   /* visible */
+   params->visible = desc->visible;
+
+   switch (ep->part->type)
+     {
+      case EDJE_PART_TYPE_IMAGE:
+        /* border */
+        if (flags & FLAG_X)
+          {
+             params->type.common.spec.image.l = desc->border.l;
+             params->type.common.spec.image.r = desc->border.r;
+          }
+        if (flags & FLAG_Y)
+          {
+             params->type.common.spec.image.t = desc->border.t;
+             params->type.common.spec.image.b = desc->border.b;
+          }
+        break;
+      case EDJE_PART_TYPE_GRADIENT:
+        params->type.common.spec.gradient.id = desc->gradient.id;
+        params->type.common.spec.gradient.type = desc->gradient.type;
+        break;
+      case EDJE_PART_TYPE_TEXT:
+      case EDJE_PART_TYPE_TEXTBLOCK:
+        /* text.align */
+        if (flags & FLAG_X)
+          {
+             params->type.text.align.x = desc->text.align.x;
+          }
+        if (flags & FLAG_Y)
+          {
+             params->type.text.align.y = desc->text.align.y;
+          }
+        params->type.text.elipsis = desc->text.elipsis;
+
+        /* text colors */
+        if (cc)
+          {
+            params->type.text.color2.r = (((int)cc->r2 + 1) * desc->color2.r) >> 8;
+            params->type.text.color2.g = (((int)cc->g2 + 1) * desc->color2.g) >> 8;
+            params->type.text.color2.b = (((int)cc->b2 + 1) * desc->color2.b) >> 8;
+            params->type.text.color2.a = (((int)cc->a2 + 1) * desc->color2.a) >> 8;
+            params->type.text.color3.r = (((int)cc->r3 + 1) * desc->color3.r) >> 8;
+            params->type.text.color3.g = (((int)cc->g3 + 1) * desc->color3.g) >> 8;
+            params->type.text.color3.b = (((int)cc->b3 + 1) * desc->color3.b) >> 8;
+            params->type.text.color3.a = (((int)cc->a3 + 1) * desc->color3.a) >> 8;
+          }
+        else
+          {
+             params->type.text.color2.r = desc->color2.r;
+             params->type.text.color2.g = desc->color2.g;
+             params->type.text.color2.b = desc->color2.b;
+             params->type.text.color2.a = desc->color2.a;
+             params->type.text.color3.r = desc->color3.r;
+             params->type.text.color3.g = desc->color3.g;
+             params->type.text.color3.b = desc->color3.b;
+             params->type.text.color3.a = desc->color3.a;
+          }
+        break;
+      case EDJE_PART_TYPE_RECTANGLE:
+      case EDJE_PART_TYPE_BOX:
+      case EDJE_PART_TYPE_TABLE:
+      case EDJE_PART_TYPE_SWALLOW:
+      case EDJE_PART_TYPE_GROUP:
+        break;
+     }
+}
+
+static void
+_edje_gradient_recalc_apply(Edje *ed, Edje_Real_Part *ep, Edje_Calc_Params *p3, Edje_Part_Description *chosen_desc __UNUSED__)
+{
+   evas_object_gradient_fill_angle_set(ep->object, p3->type.common.fill.angle);
+   evas_object_gradient_fill_spread_set(ep->object, p3->type.common.fill.spread);
+   evas_object_gradient_fill_set(ep->object, p3->type.common.fill.x, p3->type.common.fill.y,
+                                p3->type.common.fill.w, p3->type.common.fill.h);
+
+   if (p3->type.common.spec.gradient.type && p3->type.common.spec.gradient.type[0])
+     evas_object_gradient_type_set(ep->object, p3->type.common.spec.gradient.type, NULL);
+
+   if (ed->file->spectrum_dir && ed->file->spectrum_dir->entries &&
+       p3->type.common.spec.gradient.id != ep->gradient_id)
+     {
+       Edje_Spectrum_Directory_Entry *se;
+       Edje_Spectrum_Color *sc;
+       Eina_List *l;
+
+       se = eina_list_nth(ed->file->spectrum_dir->entries, p3->type.common.spec.gradient.id);
+       if (se)
+         {
+            evas_object_gradient_clear(ep->object);
+            EINA_LIST_FOREACH(se->color_list, l, sc)
+              {
+                 evas_object_gradient_color_stop_add(ep->object, sc->r,
+                                                     sc->g, sc->b, 255,
+                                                     sc->d);
+                 evas_object_gradient_alpha_stop_add(ep->object,
+                                                     sc->a, sc->d);
+              }
+            ep->gradient_id = p3->type.common.spec.gradient.id;
+         }
+     }
+}
+
+static void
+_edje_box_recalc_apply(Edje *ed __UNUSED__, Edje_Real_Part *ep, Edje_Calc_Params *p3, Edje_Part_Description *chosen_desc)
+{
+   Evas_Object_Box_Layout layout;
+   void (*free_data)(void *data);
+   void *data;
+   int min_w, min_h;
+
+   if (!_edje_box_layout_find(chosen_desc->box.layout, &layout, &data, &free_data))
+     {
+       if ((!chosen_desc->box.alt_layout) ||
+           (!_edje_box_layout_find(chosen_desc->box.alt_layout, &layout, &data, &free_data)))
+         {
+            ERR("box layout '%s' (fallback '%s') not available, using horizontal.",
+                chosen_desc->box.layout, chosen_desc->box.alt_layout);
+            layout = evas_object_box_layout_horizontal;
+            free_data = NULL;
+            data = NULL;
+         }
+     }
+
+   evas_object_box_layout_set(ep->object, layout, data, free_data);
+   evas_object_box_align_set(ep->object, TO_DOUBLE(chosen_desc->box.align.x), TO_DOUBLE(chosen_desc->box.align.y));
+   evas_object_box_padding_set(ep->object, chosen_desc->box.padding.x, chosen_desc->box.padding.y);
+
+   if (evas_object_smart_need_recalculate_get(ep->object))
+     {
+       evas_object_smart_need_recalculate_set(ep->object, 0);
+       evas_object_smart_calculate(ep->object);
+     }
+   evas_object_size_hint_min_get(ep->object, &min_w, &min_h);
+   if (chosen_desc->box.min.h && (p3->w < min_w))
+     p3->w = min_w;
+   if (chosen_desc->box.min.v && (p3->h < min_h))
+     p3->h = min_h;
+}
+
+static void
+_edje_table_recalc_apply(Edje *ed __UNUSED__, Edje_Real_Part *ep, Edje_Calc_Params *p3 __UNUSED__, Edje_Part_Description *chosen_desc)
+{
+   evas_object_table_homogeneous_set(ep->object, chosen_desc->table.homogeneous);
+   evas_object_table_align_set(ep->object, TO_DOUBLE(chosen_desc->table.align.x), TO_DOUBLE(chosen_desc->table.align.y));
+   evas_object_table_padding_set(ep->object, chosen_desc->table.padding.x, chosen_desc->table.padding.y);
+   if (evas_object_smart_need_recalculate_get(ep->object))
+     {
+       evas_object_smart_need_recalculate_set(ep->object, 0);
+       evas_object_smart_calculate(ep->object);
+     }
+}
+
+static void
+_edje_image_recalc_apply(Edje *ed, Edje_Real_Part *ep, Edje_Calc_Params *p3, Edje_Part_Description *chosen_desc, FLOAT_T pos)
+{
+   int image_id;
+   int image_count, image_num;
+   FLOAT_T sc;
+
+   sc = ed->scale;
+   if (sc == 0.0) sc = _edje_scale;
+   evas_object_image_fill_set(ep->object, p3->type.common.fill.x, p3->type.common.fill.y,
+                             p3->type.common.fill.w, p3->type.common.fill.h);
+   evas_object_image_smooth_scale_set(ep->object, p3->smooth);
+   if (chosen_desc->border.scale)
+     evas_object_image_border_scale_set(ep->object, TO_DOUBLE(sc));
+   else
+     evas_object_image_border_scale_set(ep->object, 1.0);
+   evas_object_image_border_set(ep->object, p3->type.common.spec.image.l, p3->type.common.spec.image.r,
+                               p3->type.common.spec.image.t, p3->type.common.spec.image.b);
+   if (chosen_desc->border.no_fill == 0)
+     evas_object_image_border_center_fill_set(ep->object, EVAS_BORDER_FILL_DEFAULT);
+   else if (chosen_desc->border.no_fill == 1)
+     evas_object_image_border_center_fill_set(ep->object, EVAS_BORDER_FILL_NONE);
+   else if (chosen_desc->border.no_fill == 2)
+     evas_object_image_border_center_fill_set(ep->object, EVAS_BORDER_FILL_SOLID);
+   image_id = ep->param1.description->image.id;
+   if (image_id < 0)
+     {
+       Edje_Image_Directory_Entry *ie;
+
+       if (!ed->file->image_dir) ie = NULL;
+       else ie = eina_list_nth(ed->file->image_dir->entries, (-image_id) - 1);
+       if ((ie) &&
+           (ie->source_type == EDJE_IMAGE_SOURCE_TYPE_EXTERNAL) &&
+           (ie->entry))
+         {
+            evas_object_image_file_set(ep->object, ie->entry, NULL);
+         }
+     }
+   else
+     {
+       image_count = 2;
+       if (ep->param2)
+         image_count += eina_list_count(ep->param2->description->image.tween_list);
+       image_num = TO_INT(MUL(pos, SUB(FROM_INT(image_count),
+                                       FROM_DOUBLE(0.5))));
+       if (image_num > (image_count - 1))
+         image_num = image_count - 1;
+       if (image_num == 0)
+         image_id = ep->param1.description->image.id;
+       else
+         if (ep->param2)
+           {
+              if (image_num == (image_count - 1))
+                image_id = ep->param2->description->image.id;
+              else
+                {
+                   Edje_Part_Image_Id *imid;
+
+                   imid = eina_list_nth(ep->param2->description->image.tween_list,
+                                        image_num - 1);
+                   if (imid) image_id = imid->id;
+                }
+           }
+       if (image_id < 0)
+         {
+            ERR("¨Part \"%s\" has description, "
+                "\"%s\" %3.3f with a missing image id!!!",
+                ep->part->name,
+                ep->param1.description->state.name,
+                ep->param1.description->state.value);
+         }
+       else
+         {
+            char buf[1024];
+
+            /* Replace snprint("images/%i") == memcpy + itoa */
+#define IMAGES "images/"
+            memcpy(buf, IMAGES, strlen(IMAGES));
+            eina_convert_itoa(image_id, buf + strlen(IMAGES)); /* No need to check length as 2³² need only 10 characteres. */
+
+            evas_object_image_file_set(ep->object, ed->file->path, buf);
+            if (evas_object_image_load_error_get(ep->object) != EVAS_LOAD_ERROR_NONE)
+              {
+                 ERR("Error loading image collection \"%s\" from "
+                     "file \"%s\". Missing EET Evas loader module?",
+                     buf, ed->file->path);
+                 switch (evas_object_image_load_error_get(ep->object))
+                   {
+                    case EVAS_LOAD_ERROR_GENERIC:
+                       ERR("Error type: EVAS_LOAD_ERROR_GENERIC");
+                       break;
+                    case EVAS_LOAD_ERROR_DOES_NOT_EXIST:
+                       ERR("Error type: EVAS_LOAD_ERROR_DOES_NOT_EXIST");
+                       break;
+                    case EVAS_LOAD_ERROR_PERMISSION_DENIED:
+                       ERR("Error type: EVAS_LOAD_ERROR_PERMISSION_DENIED");
+                       break;
+                    case EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED:
+                       ERR("Error type: EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED");
+                       break;
+                    case EVAS_LOAD_ERROR_CORRUPT_FILE:
+                       ERR("Error type: EVAS_LOAD_ERROR_CORRUPT_FILE");
+                       break;
+                    case EVAS_LOAD_ERROR_UNKNOWN_FORMAT:
+                       ERR("Error type: EVAS_LOAD_ERROR_UNKNOWN_FORMAT");
+                       break;
+                   }
+              }
+         }
+     }
+}
+
+
+static void
+_edje_part_recalc(Edje *ed, Edje_Real_Part *ep, int flags)
+{
+#ifdef EDJE_CALC_CACHE
+   int state1 = -1;
+   int state2 = -1;
+   int statec = -1;
+#else
+   Edje_Calc_Params lp1, lp2;
+#endif
+   Edje_Calc_Params *p1, *pf;
+   Edje_Part_Description *chosen_desc;
+   Edje_Real_Part *confine_to = NULL;
+   FLOAT_T pos = ZERO;
+   Edje_Calc_Params lp3;
+
+   if ((ep->calculated & FLAG_XY) == FLAG_XY)
+     {
+       return;
+     }
+   if (ep->calculating & flags)
+     {
+#if 1
+       const char *axes = "NONE", *faxes = "NONE";
+
+       if ((ep->calculating & FLAG_X) &&
+           (ep->calculating & FLAG_Y))
+         axes = "XY";
+       else if ((ep->calculating & FLAG_X))
+         axes = "X";
+       else if ((ep->calculating & FLAG_Y))
+         axes = "Y";
+
+       if ((flags & FLAG_X) &&
+           (flags & FLAG_Y))
+         faxes = "XY";
+       else if ((flags & FLAG_X))
+         faxes = "X";
+       else if ((flags & FLAG_Y))
+         faxes = "Y";
+       ERR("Circular dependency when calculating part \"%s\"\n"
+           "Already calculating %s [%02x] axes\n"
+           "Need to calculate %s [%02x] axes",
+           ep->part->name,
+           axes, ep->calculating,
+           faxes, flags);
+#endif
+       return;
+     }
+#ifdef EDJE_CALC_CACHE
+   if (ep->state == ed->state)
+     return ;
+#endif
+
+   if (flags & FLAG_X)
+     {
+       ep->calculating |= flags & FLAG_X;
+       if (ep->param1.rel1_to_x)
+         {
+            _edje_part_recalc(ed, ep->param1.rel1_to_x, FLAG_X);
+#ifdef EDJE_CALC_CACHE
+            state1 = ep->param1.rel1_to_x->state;
+#endif
+         }
+       if (ep->param1.rel2_to_x)
+         {
+            _edje_part_recalc(ed, ep->param1.rel2_to_x, FLAG_X);
+#ifdef EDJE_CALC_CACHE
+            if (state1 < ep->param1.rel2_to_x->state)
+              state1 = ep->param1.rel2_to_x->state;
+#endif
+         }
+       if (ep->param2)
+         {
+            if (ep->param2->rel1_to_x)
+              {
+                 _edje_part_recalc(ed, ep->param2->rel1_to_x, FLAG_X);
+#ifdef EDJE_CALC_CACHE
+                 state2 = ep->param2->rel1_to_x->state;
+#endif
+              }
+            if (ep->param2->rel2_to_x)
+              {
+                 _edje_part_recalc(ed, ep->param2->rel2_to_x, FLAG_X);
+#ifdef EDJE_CALC_CACHE
+                 if (state2 < ep->param2->rel2_to_x->state)
+                   state2 = ep->param2->rel2_to_x->state;
+#endif
+              }
+         }
+     }
+   if (flags & FLAG_Y)
+     {
+       ep->calculating |= flags & FLAG_Y;
+       if (ep->param1.rel1_to_y)
+         {
+            _edje_part_recalc(ed, ep->param1.rel1_to_y, FLAG_Y);
+#ifdef EDJE_CALC_CACHE
+            if (state1 < ep->param1.rel1_to_y->state)
+              state1 = ep->param1.rel1_to_y->state;
+#endif
+         }
+       if (ep->param1.rel2_to_y)
+         {
+            _edje_part_recalc(ed, ep->param1.rel2_to_y, FLAG_Y);
+#ifdef EDJE_CALC_CACHE
+            if (state1 < ep->param1.rel2_to_y->state)
+              state1 = ep->param1.rel2_to_y->state;
+#endif
+         }
+       if (ep->param2)
+         {
+            if (ep->param2->rel1_to_y)
+              {
+                 _edje_part_recalc(ed, ep->param2->rel1_to_y, FLAG_Y);
+#ifdef EDJE_CALC_CACHE
+                 if (state2 < ep->param2->rel1_to_y->state)
+                   state2 = ep->param2->rel1_to_y->state;
+#endif
+              }
+            if (ep->param2->rel2_to_y)
+              {
+                 _edje_part_recalc(ed, ep->param2->rel2_to_y, FLAG_Y);
+#ifdef EDJE_CALC_CACHE
+                 if (state2 < ep->param2->rel2_to_y->state)
+                   state2 = ep->param2->rel2_to_y->state;
+#endif
+              }
+         }
+     }
+   if (ep->drag && ep->drag->confine_to)
+     {
+       confine_to = ep->drag->confine_to;
+       _edje_part_recalc(ed, confine_to, flags);
+#ifdef EDJE_CALC_CACHE
+       statec = confine_to->state;
+#endif
+     }
+//   if (ep->text.source)       _edje_part_recalc(ed, ep->text.source, flags);
+//   if (ep->text.text_source)  _edje_part_recalc(ed, ep->text.text_source, flags);
+
+   /* actually calculate now */
+   chosen_desc = ep->chosen_description;
+   if (!chosen_desc)
+     {
+       ep->calculating = FLAG_NONE;
+       ep->calculated |= flags;
+       return;
+     }
+
+#ifndef EDJE_CALC_CACHE
+   p1 = &lp1;
+#else
+   p1 = &ep->param1.p;
+#endif
+
+   if (ep->param1.description)
+     {
+#ifdef EDJE_CALC_CACHE
+       if (ed->all_part_change ||
+           ep->invalidate ||
+           state1 >= ep->param1.state ||
+           statec >= ep->param1.state ||
+           ((ep->part->type == EDJE_PART_TYPE_TEXT || ep->part->type == EDJE_PART_TYPE_TEXTBLOCK) && ed->text_part_change))
+#endif
+         {
+            _edje_part_recalc_single(ed, ep, ep->param1.description, chosen_desc,
+                                     ep->param1.rel1_to_x, ep->param1.rel1_to_y, ep->param1.rel2_to_x, ep->param1.rel2_to_y,
+                                     confine_to,
+                                     p1,
+                                     flags);
+
+#ifdef EDJE_CALC_CACHE
+            ep->param1.state = ed->state;
+#endif
+         }
+     }
+   if (ep->param2 && ep->description_pos != ZERO)
+     {
+       int beginning_pos, part_type;
+       Edje_Calc_Params *p2, *p3;
+
+       p3 = &lp3;
+
+#ifndef EDJE_CALC_CACHE
+       p2 = &lp2;
+#else
+       p2 = &ep->param2->p;
+
+       if (ed->all_part_change ||
+           ep->invalidate ||
+           state2 >= ep->param2->state ||
+           statec >= ep->param2->state ||
+           ((ep->part->type == EDJE_PART_TYPE_TEXT || ep->part->type == EDJE_PART_TYPE_TEXTBLOCK) && ed->text_part_change))
+#endif
+         {
+            _edje_part_recalc_single(ed, ep, ep->param2->description, chosen_desc,
+                                     ep->param2->rel1_to_x, ep->param2->rel1_to_y, ep->param2->rel2_to_x, ep->param2->rel2_to_y,
+                                     confine_to,
+                                     p2,
+                                     flags);
+#ifdef EDJE_CALC_CACHE
+            ep->param2->state = ed->state;
+#endif
+         }
+
+       pos = ep->description_pos;
+       beginning_pos = (pos < FROM_DOUBLE(0.5));
+       part_type = ep->part->type;
+
+       /* visible is special */
+       if ((p1->visible) && (!p2->visible))
+         p3->visible = (pos != FROM_INT(1));
+       else if ((!p1->visible) && (p2->visible))
+         p3->visible = (pos != ZERO);
+       else
+         p3->visible = p1->visible;
+
+       p3->smooth = (beginning_pos) ? p1->smooth : p2->smooth;
+
+       /* FIXME: do x and y separately base on flag */
+#define FINTP(_x1, _x2, _p)                                            \
+       (((_x1) == (_x2))                                               \
+        ? FROM_INT((_x1))                                              \
+        : ADD(FROM_INT(_x1),                                           \
+              SCALE((_p), (_x2) - (_x1))))
+
+#define FFP(_x1, _x2, _p)                      \
+       (((_x1) == (_x2))                       \
+        ? (_x1)                                \
+        : ADD(_x1, MUL(_p, SUB(_x2, _x1))));
+
+#define INTP(_x1, _x2, _p) TO_INT(FINTP(_x1, _x2, _p))
+
+       p3->x = INTP(p1->x, p2->x, pos);
+       p3->y = INTP(p1->y, p2->y, pos);
+       p3->w = INTP(p1->w, p2->w, pos);
+       p3->h = INTP(p1->h, p2->h, pos);
+
+       p3->req.x = INTP(p1->req.x, p2->req.x, pos);
+       p3->req.y = INTP(p1->req.y, p2->req.y, pos);
+       p3->req.w = INTP(p1->req.w, p2->req.w, pos);
+       p3->req.h = INTP(p1->req.h, p2->req.h, pos);
+
+       if (ep->part->dragable.x)
+         {
+            p3->req_drag.x = INTP(p1->req_drag.x, p2->req_drag.x, pos);
+            p3->req_drag.w = INTP(p1->req_drag.w, p2->req_drag.w, pos);
+         }
+       if (ep->part->dragable.y)
+         {
+            p3->req_drag.y = INTP(p1->req_drag.y, p2->req_drag.y, pos);
+            p3->req_drag.h = INTP(p1->req_drag.h, p2->req_drag.h, pos);
+         }
+
+       p3->color.r = INTP(p1->color.r, p2->color.r, pos);
+       p3->color.g = INTP(p1->color.g, p2->color.g, pos);
+       p3->color.b = INTP(p1->color.b, p2->color.b, pos);
+       p3->color.a = INTP(p1->color.a, p2->color.a, pos);
+
+       switch (part_type)
+         {
+          case EDJE_PART_TYPE_IMAGE:
+          case EDJE_PART_TYPE_GRADIENT:
+             p3->type.common.fill.x = INTP(p1->type.common.fill.x, p2->type.common.fill.x, pos);
+             p3->type.common.fill.y = INTP(p1->type.common.fill.y, p2->type.common.fill.y, pos);
+             p3->type.common.fill.w = INTP(p1->type.common.fill.w, p2->type.common.fill.w, pos);
+             p3->type.common.fill.h = INTP(p1->type.common.fill.h, p2->type.common.fill.h, pos);
+             if (part_type == EDJE_PART_TYPE_GRADIENT)
+               {
+                  p3->type.common.fill.angle = INTP(p1->type.common.fill.angle, p2->type.common.fill.angle, pos);
+                  p3->type.common.fill.spread = (beginning_pos) ? p1->type.common.fill.spread : p2->type.common.fill.spread;
+                  p3->type.common.spec.gradient = (beginning_pos) ? p1->type.common.spec.gradient : p2->type.common.spec.gradient;
+               }
+             else
+               {
+                  p3->type.common.spec.image.l = INTP(p1->type.common.spec.image.l, p2->type.common.spec.image.l, pos);
+                  p3->type.common.spec.image.r = INTP(p1->type.common.spec.image.r, p2->type.common.spec.image.r, pos);
+                  p3->type.common.spec.image.t = INTP(p1->type.common.spec.image.t, p2->type.common.spec.image.t, pos);
+                  p3->type.common.spec.image.b = INTP(p1->type.common.spec.image.b, p2->type.common.spec.image.b, pos);
+               }
+             break;
+          case EDJE_PART_TYPE_TEXT:
+             p3->type.text.size = INTP(p1->type.text.size, p2->type.text.size, pos);
+          case EDJE_PART_TYPE_TEXTBLOCK:
+             p3->type.text.color2.r = INTP(p1->type.text.color2.r, p2->type.text.color2.r, pos);
+             p3->type.text.color2.g = INTP(p1->type.text.color2.g, p2->type.text.color2.g, pos);
+             p3->type.text.color2.b = INTP(p1->type.text.color2.b, p2->type.text.color2.b, pos);
+             p3->type.text.color2.a = INTP(p1->type.text.color2.a, p2->type.text.color2.a, pos);
+
+             p3->type.text.color3.r = INTP(p1->type.text.color3.r, p2->type.text.color3.r, pos);
+             p3->type.text.color3.g = INTP(p1->type.text.color3.g, p2->type.text.color3.g, pos);
+             p3->type.text.color3.b = INTP(p1->type.text.color3.b, p2->type.text.color3.b, pos);
+             p3->type.text.color3.a = INTP(p1->type.text.color3.a, p2->type.text.color3.a, pos);
+
+             p3->type.text.align.x = FFP(p1->type.text.align.x, p2->type.text.align.x, pos);
+             p3->type.text.align.y = FFP(p1->type.text.align.y, p2->type.text.align.y, pos);
+             p3->type.text.elipsis = TO_DOUBLE(FINTP(p1->type.text.elipsis, p2->type.text.elipsis, pos));
+             break;
+         }
+
+       pf = p3;
+     }
+   else
+     {
+       pf = p1;
+     }
+
+   ep->req = pf->req;
+
+   if (ep->drag && ep->drag->need_reset)
+     {
+       FLOAT_T dx, dy;
+
+       dx = ZERO;
+       dy = ZERO;
+       _edje_part_dragable_calc(ed, ep, &dx, &dy);
+        ep->drag->x = dx;
+       ep->drag->y = dy;
+       ep->drag->tmp.x = 0;
+       ep->drag->tmp.y = 0;
+       ep->drag->need_reset = 0;
+     }
+   if (!ed->calc_only)
+     {
+        Evas_Object *mo;
+
+       /* Common move, resize and color_set for all part. */
+       switch (ep->part->type)
+         {
+          case EDJE_PART_TYPE_IMAGE:
+             evas_object_image_scale_hint_set(ep->object, 
+                                              chosen_desc->image.scale_hint);
+          case EDJE_PART_TYPE_RECTANGLE:
+          case EDJE_PART_TYPE_TEXTBLOCK:
+          case EDJE_PART_TYPE_GRADIENT:
+          case EDJE_PART_TYPE_BOX:
+          case EDJE_PART_TYPE_TABLE:
+             evas_object_color_set(ep->object,
+                                   (pf->color.r * pf->color.a) / 255,
+                                   (pf->color.g * pf->color.a) / 255,
+                                   (pf->color.b * pf->color.a) / 255,
+                                   pf->color.a);
+             if (!pf->visible)
+               {
+                  evas_object_hide(ep->object);
+                  break;
+               }
+             evas_object_show(ep->object);
+             /* move and resize are needed for all previous object => no break here. */
+          case EDJE_PART_TYPE_SWALLOW:
+          case EDJE_PART_TYPE_GROUP:
+          case EDJE_PART_TYPE_EXTERNAL:
+             /* visibility and color have no meaning on SWALLOW and GROUP part. */
+             evas_object_move(ep->object, ed->x + pf->x, ed->y + pf->y);
+             evas_object_resize(ep->object, pf->w, pf->h);
+             if (ep->part->entry_mode > EDJE_ENTRY_EDIT_MODE_NONE)
+               _edje_entry_real_part_configure(ep);
+             break;
+          case EDJE_PART_TYPE_TEXT:
+             /* This is correctly handle in _edje_text_recalc_apply at the moment. */
+             break;
+         }
+
+       /* Some object need special recalc. */
+       switch (ep->part->type)
+         {
+          case EDJE_PART_TYPE_TEXT:
+             _edje_text_recalc_apply(ed, ep, pf, chosen_desc);
+             break;
+          case EDJE_PART_TYPE_IMAGE:
+             _edje_image_recalc_apply(ed, ep, pf, chosen_desc, pos);
+             break;
+          case EDJE_PART_TYPE_GRADIENT:
+             _edje_gradient_recalc_apply(ed, ep, pf, chosen_desc);
+             break;
+          case EDJE_PART_TYPE_BOX:
+             _edje_box_recalc_apply(ed, ep, pf, chosen_desc);
+             break;
+          case EDJE_PART_TYPE_TABLE:
+             _edje_table_recalc_apply(ed, ep, pf, chosen_desc);
+             break;
+          case EDJE_PART_TYPE_EXTERNAL:
+          case EDJE_PART_TYPE_RECTANGLE:
+          case EDJE_PART_TYPE_SWALLOW:
+          case EDJE_PART_TYPE_GROUP:
+          case EDJE_PART_TYPE_TEXTBLOCK:
+             /* Nothing special to do for this type of object. */
+             break;
+         }
+
+       if (ep->swallowed_object)
+         {
+//// the below really is wrong - swallow color shouldnt affect swallowed object
+//// color - the edje color as a WHOLE should though - and that should be
+//// done via the clipper anyway. this created bugs when objects had their
+//// colro set and were swallowed - then had their color changed.
+//          evas_object_color_set(ep->swallowed_object,
+//                                (pf->color.r * pf->color.a) / 255,
+//                                (pf->color.g * pf->color.a) / 255,
+//                                (pf->color.b * pf->color.a) / 255,
+//                                pf->color.a);
+            if (pf->visible)
+              {
+                 evas_object_move(ep->swallowed_object, ed->x + pf->x, ed->y + pf->y);
+                 evas_object_resize(ep->swallowed_object, pf->w, pf->h);
+                 evas_object_show(ep->swallowed_object);
+              }
+            else evas_object_hide(ep->swallowed_object);
+             mo = ep->swallowed_object;
+         }
+        else mo = ep->object;
+        if (chosen_desc->map.on)
+          {
+             Evas_Map *map;
+             Evas_Coord cx, cy, cz;
+             double rx, ry, rz;
+             Edje_Part_Description *desc1, *desc2;
+
+             desc1 = ep->param1.description;
+             desc2 = NULL;
+             if (ep->param2) desc2 = ep->param2->description;
+             pos = ep->description_pos;
+
+             ed->have_mapped_part = 1;
+             // create map and populate with part geometry
+             map = evas_map_new(4);
+             evas_map_util_points_populate_from_object(map, ep->object);
+             if (ep->part->type == EDJE_PART_TYPE_IMAGE)
+               {
+                  int iw = 1, ih = 1;
+
+                  evas_object_image_size_get(mo, &iw, &ih);
+                  evas_map_point_image_uv_set(map, 0, 0.0, 0.0);
+                  evas_map_point_image_uv_set(map, 1, iw , 0.0);
+                  evas_map_point_image_uv_set(map, 2, iw , ih );
+                  evas_map_point_image_uv_set(map, 3, 0.0, ih );
+               }
+
+             // default center - center of part
+             cx = ed->x + pf->x + (pf->w / 2);
+             cy = ed->y + pf->y + (pf->h / 2);
+             cz = 0;
+
+             // if another center is specified - find it and caculate it
+             if ((desc1) &&
+                 (desc1->map.rot.id_center >= 0) &&
+                 (desc1->map.rot.id_center != ep->part->id))
+               {
+                  Evas_Coord cx1, cy1, cz1, cx2, cy2, cz2;
+                  Edje_Real_Part *ep2 =
+                    ed->table_parts[desc1->map.rot.id_center %
+                                    ed->table_parts_size];
+                  // get center for desc1
+                  if (ep2)
+                    {
+                      if (!ep2->calculated) _edje_part_recalc(ed, ep2, flags);
+                       cx1 = ed->x + ep2->x + (ep2->w / 2);
+                       cy1 = ed->y + ep2->y + (ep2->h / 2);
+                       cz1 = 0;
+                    }
+                  // if we have a desc2 and are on a partiual position to it
+                  if ((pos != ZERO) && (desc2) &&
+                      (desc2->map.rot.id_center >= 0) &&
+                      (desc2->map.rot.id_center != ep->part->id))
+                    {
+                       ep2 = ed->table_parts[desc2->map.rot.id_center %
+                                             ed->table_parts_size];
+                       // get 2nd center & merge with pos with center 1
+                       if (ep2)
+                         {
+                            if (!ep2->calculated) _edje_part_recalc(ed, ep2, flags);
+                            cx2 = ed->x + ep2->x + (ep2->w / 2);
+                            cy2 = ed->y + ep2->y + (ep2->h / 2);
+                            cz2 = 0;
+                            cx1 += SCALE(pos, cx2 - cx1);
+                            cy1 += SCALE(pos, cy2 - cy1);
+                            cz1 += SCALE(pos, cz2 - cz1);
+                         }
+                    }
+                  cx = cx1;
+                  cy = cy1;
+                  cz = cz1;
+               }
+
+             // rotation - interpolate wit pos, if appropriate
+             if ((pos != ZERO) && (desc2))
+               {
+                  rx = TO_DOUBLE(ADD(desc1->map.rot.x,
+                                     MUL(pos, SUB(desc2->map.rot.x,
+                                                  desc1->map.rot.x))));
+                  ry = TO_DOUBLE(ADD(desc1->map.rot.y,
+                                    MUL(pos, SUB(desc2->map.rot.y,
+                                                  desc1->map.rot.y))));
+                  rz = TO_DOUBLE(ADD(desc1->map.rot.z,
+                                    MUL(pos, SUB(desc2->map.rot.z,
+                                                  desc1->map.rot.z))));
+               }
+             else
+               {
+                  // no 2 descriptions - just use rot
+                  rx = TO_DOUBLE(desc1->map.rot.x);
+                  ry = TO_DOUBLE(desc1->map.rot.y);
+                  rz = TO_DOUBLE(desc1->map.rot.z);
+               }
+             evas_map_util_3d_rotate(map, rx, ry, rz, cx, cy, cz);
+
+             // calculate light color & position etc. if there is one
+             if (((desc1) &&
+                  (desc1->map.id_light >= 0) &&
+                  (desc1->map.id_light != ep->part->id)) ||
+                 ((desc2) &&
+                  (desc2->map.id_light >= 0) &&
+                  (desc2->map.id_light != ep->part->id)))
+               {
+                  Evas_Coord lx, ly, lz;
+                  int lr, lg, lb, lar, lag, lab;
+                  Evas_Coord lx1, ly1, lz1;
+                  int lr1, lg1, lb1, lar1, lag1, lab1, do1;
+                  Evas_Coord lx2, ly2, lz2;
+                  int lr2, lg2, lb2, lar2, lag2, lab2, do2;
+
+                  do1 = do2 = 0;
+
+                  if ((desc1) &&
+                      (desc1->map.id_light >= 0) &&
+                      (desc1->map.id_light != ep->part->id))
+                    {
+                       Edje_Real_Part *ep2 =
+                         ed->table_parts[desc1->map.id_light %
+                                         ed->table_parts_size];
+                       // get light part
+                       if (ep2)
+                         {
+                            Edje_Part_Description *ep2desc1, *ep2desc2;
+                            FLOAT_T ep2pos;
+
+                            do1 = 1;
+                            if (!ep2->calculated)
+                              _edje_part_recalc(ed, ep2, flags);
+                            ep2desc1 = ep2->param1.description;
+                            ep2desc2 = NULL;
+                            if (ep2->param2) ep2desc2 = ep2->param2->description;
+                            ep2pos = ep2->description_pos;
+
+                            // light x and y are already interpolated in part geom
+                            lx1 = ed->x + ep2->x + (ep2->w / 2);
+                            ly1 = ed->y + ep2->y + (ep2->h / 2);
+                            // if light is transitioning - interpolate it
+                            if ((ep2pos != ZERO) && (ep2desc2))
+                              {
+                                 lz1 = ep2desc1->persp.zplane + 
+                                   TO_INT(SCALE(ep2pos, ep2desc2->persp.zplane -
+                                                ep2desc1->persp.zplane));
+                                 lr1 = ep2desc1->color.r +
+                                   TO_INT(SCALE(ep2pos, ep2desc2->color.r -
+                                                ep2desc1->color.r));
+                                 lg1 = ep2desc1->color.g +
+                                   TO_INT(SCALE(ep2pos, ep2desc2->color.g -
+                                                ep2desc1->color.b));
+                                 lb1 = ep2desc1->color.b +
+                                   TO_INT(SCALE(ep2pos, ep2desc2->color.g -
+                                                ep2desc1->color.b));
+                                 lar1 = ep2desc1->color2.r +
+                                   TO_INT(SCALE(ep2pos, ep2desc2->color2.r -
+                                                ep2desc1->color2.r));
+                                 lag1 = ep2desc1->color2.g +
+                                   TO_INT(SCALE(ep2pos, ep2desc2->color2.g -
+                                                ep2desc1->color2.b));
+                                 lab1 = ep2desc1->color2.b +
+                                   TO_INT(SCALE(ep2pos, ep2desc2->color2.g -
+                                                ep2desc1->color2.b));
+                              }
+                            else
+                              {
+                                 lz1 = ep2desc1->persp.zplane;
+                                 lr1 = ep2desc1->color.r;
+                                 lg1 = ep2desc1->color.g;
+                                 lb1 = ep2desc1->color.b;
+                                 lar1 = ep2desc1->color2.r;
+                                 lag1 = ep2desc1->color2.g;
+                                 lab1 = ep2desc1->color2.b;
+                              }
+                         }
+                    }
+                  if ((desc2) &&
+                      (desc2->map.id_light >= 0) &&
+                      (desc2->map.id_light != ep->part->id))
+                    {
+                       Edje_Real_Part *ep2 =
+                         ed->table_parts[desc2->map.id_light %
+                                         ed->table_parts_size];
+                       // get light part
+                       if (ep2)
+                         {
+                            Edje_Part_Description *ep2desc1, *ep2desc2;
+                            FLOAT_T ep2pos;
+
+                            do2 = 1;
+                            if (!ep2->calculated)
+                              _edje_part_recalc(ed, ep2, flags);
+                            ep2desc1 = ep2->param1.description;
+                            ep2desc2 = NULL;
+                            if (ep2->param2) ep2desc2 = ep2->param2->description;
+                            ep2pos = ep2->description_pos;
+
+                            // light x and y are already interpolated in part geom
+                            lx2 = ed->x + ep2->x + (ep2->w / 2);
+                            ly2 = ed->y + ep2->y + (ep2->h / 2);
+                            // if light is transitioning - interpolate it
+                            if ((ep2pos != ZERO) && (ep2desc2))
+                              {
+                                 lz2 = ep2desc1->persp.zplane + 
+                                   TO_INT(SCALE(ep2pos, ep2desc2->persp.zplane -
+                                                ep2desc1->persp.zplane));
+                                 lr2 = ep2desc1->color.r +
+                                   TO_INT(SCALE(ep2pos, ep2desc2->color.r -
+                                                ep2desc1->color.r));
+                                 lg2 = ep2desc1->color.g +
+                                   TO_INT(SCALE(ep2pos, ep2desc2->color.g -
+                                                ep2desc1->color.b));
+                                 lb2 = ep2desc1->color.b +
+                                   TO_INT(SCALE(ep2pos, ep2desc2->color.g -
+                                                ep2desc1->color.b));
+                                 lar2 = ep2desc1->color2.r +
+                                   TO_INT(SCALE(ep2pos, ep2desc2->color2.r -
+                                                ep2desc1->color2.r));
+                                 lag2 = ep2desc1->color2.g +
+                                   TO_INT(SCALE(ep2pos, ep2desc2->color2.g -
+                                                ep2desc1->color2.b));
+                                 lab2 = ep2desc1->color2.b +
+                                   TO_INT(SCALE(ep2pos, ep2desc2->color2.g -
+                                                ep2desc1->color2.b));
+                              }
+                            else
+                              {
+                                 lz2 = ep2desc1->persp.zplane;
+                                 lr2 = ep2desc1->color.r;
+                                 lg2 = ep2desc1->color.g;
+                                 lb2 = ep2desc1->color.b;
+                                 lar2 = ep2desc1->color2.r;
+                                 lag2 = ep2desc1->color2.g;
+                                 lab2 = ep2desc1->color2.b;
+                              }
+                         }
+                    }
+                  if ((do1 && do2))
+                    {
+                       lx = lx1 + TO_INT(SCALE(pos, lx2 - lx1));
+                       ly = ly1 + TO_INT(SCALE(pos, ly2 - ly1));
+                       lz = lz1 + TO_INT(SCALE(pos, lz2 - lz1));
+                       lr = lr1 + TO_INT(SCALE(pos, lr2 - lr1));
+                       lg = lg1 + TO_INT(SCALE(pos, lg2 - lg1));
+                       lb = lb1 + TO_INT(SCALE(pos, lb2 - lb1));
+                       lar = lar1 + TO_INT(SCALE(pos, lar2 - lar1));
+                       lag = lag1 + TO_INT(SCALE(pos, lag2 - lag1));
+                       lab = lab1 + TO_INT(SCALE(pos, lab2 - lab1));
+                    }
+                  else if (do1)
+                    {
+                       lx = lx1; ly = ly1; lz = lz1;
+                       lr = lr1; lg = lg1; lb = lb1;
+                       lar = lar1; lag = lag1; lab = lab1;
+                    }
+                  else
+                    {
+                       lx = lx2; ly = ly2; lz = lz2;
+                       lr = lr2; lg = lg2; lb = lb2;
+                       lar = lar2; lag = lag2; lab = lab2;
+                    }
+                  evas_map_util_3d_lighting(map,
+                                            lx, ly, lz,
+                                            lr, lg, lb, 
+                                            lar, lag, lab);
+               }
+
+             // calculate perspective point
+             if (chosen_desc->map.persp_on)
+               {
+                  Evas_Coord px, py, zplane, foc;
+                  Evas_Coord px1, py1, zplane1, foc1;
+                  Evas_Coord px2, py2, zplane2, foc2;
+                  int do1, do2;
+
+                  do1 = do2 = 0;
+
+                  // default perspective point
+                  px = ed->x + (ed->w / 2);
+                  py = ed->y + (ed->h / 2);
+                  zplane = 0;
+                  foc = 1000;
+
+                  if ((desc1) &&
+                      (desc1->map.id_persp >= 0) &&
+                      (desc1->map.id_persp != ep->part->id))
+                    {
+                       Edje_Real_Part *ep2 = ed->table_parts[desc1->map.id_persp %
+                                                             ed->table_parts_size];
+                       if (ep2)
+                         {
+                            Edje_Part_Description *ep2desc1, *ep2desc2;
+                            FLOAT_T ep2pos;
+
+                            do1 = 1;
+                            if (!ep2->calculated)
+                              _edje_part_recalc(ed, ep2, flags);
+                            ep2desc1 = ep2->param1.description;
+                            ep2desc2 = NULL;
+                            if (ep2->param2) ep2desc2 = ep2->param2->description;
+                            ep2pos = ep2->description_pos;
+
+                            px1 = ed->x + ep2->x + (ep2->w / 2);
+                            py1 = ed->y + ep2->y + (ep2->h / 2);
+                            if ((ep2pos != ZERO) && (ep2desc2))
+                              {
+                                 zplane1 = ep2desc1->persp.zplane + 
+                                   TO_INT(SCALE(ep2pos, ep2desc2->persp.zplane -
+                                                ep2desc1->persp.zplane));
+                                 foc1 = ep2desc1->persp.focal + 
+                                   TO_INT(SCALE(ep2pos, ep2desc2->persp.focal -
+                                                ep2desc1->persp.focal));
+                              }
+                            else
+                              {
+                                 zplane1 = ep2desc1->persp.zplane;
+                                 foc1 = ep2desc1->persp.focal;
+                              }
+                         }
+                    }
+
+                  if ((desc2) &&
+                      (desc2->map.id_persp >= 0) &&
+                      (desc2->map.id_persp != ep->part->id))
+                    {
+                       Edje_Real_Part *ep2 = ed->table_parts[desc2->map.id_persp %
+                                                             ed->table_parts_size];
+                       if (ep2)
+                         {
+                            Edje_Part_Description *ep2desc1, *ep2desc2;
+                            FLOAT_T ep2pos;
+
+                            do2 = 1;
+                            if (!ep2->calculated)
+                              _edje_part_recalc(ed, ep2, flags);
+                            ep2desc1 = ep2->param1.description;
+                            ep2desc2 = NULL;
+                            if (ep2->param2) ep2desc2 = ep2->param2->description;
+                            ep2pos = ep2->description_pos;
+
+                            px2 = ed->x + ep2->x + (ep2->w / 2);
+                            py2 = ed->y + ep2->y + (ep2->h / 2);
+                            if ((ep2pos != ZERO) && (ep2desc2))
+                              {
+                                 zplane2 = ep2desc1->persp.zplane + 
+                                   TO_INT(SCALE(ep2pos, ep2desc2->persp.zplane -
+                                                ep2desc1->persp.zplane));
+                                 foc2 = ep2desc1->persp.focal + 
+                                   TO_INT(SCALE(ep2pos, ep2desc2->persp.focal -
+                                                ep2desc1->persp.focal));
+                              }
+                            else
+                              {
+                                 zplane2 = ep2desc1->persp.zplane;
+                                 foc2 = ep2desc1->persp.focal;
+                              }
+                         }
+                    }
+
+                  if ((do1) && (do2))
+                    {
+                       px = px1 + TO_INT(SCALE(pos, px2 - px1));
+                       py = py1 + TO_INT(SCALE(pos, py2 - py1));
+                       zplane = zplane1 + TO_INT(SCALE(pos, zplane2 - zplane1));
+                       foc = foc1 + TO_INT(SCALE(pos, foc2 - foc1));
+                    }
+                  else if (do1)
+                    {
+                       px = px1; py = py1; zplane = zplane1; foc = foc1;
+                    }
+                  else if (do2)
+                    {
+                       px = px2; py = py2; zplane = zplane2; foc = foc2;
+                    }
+                  else
+                    {
+                       if (ed->persp)
+                         {
+                            px = ed->persp->px; py = ed->persp->py;
+                            zplane = ed->persp->z0; foc = ed->persp->foc;
+                         }
+                       else
+                         {
+                            const Edje_Perspective *ps;
+
+                            // fixme: a tad inefficient as this is a has lookup
+                            ps = edje_object_perspective_get(ed->obj);
+                            if (ps)
+                              {
+                                 px = ps->px; py = ps->py;
+                                 zplane = ps->z0; foc = ps->foc;
+                              }
+                         }
+                    }
+                  evas_map_util_3d_perspective(map, px, py, zplane, foc);
+               }
+
+             // handle backface culling (object is facing away from view
+             if (chosen_desc->map.backcull)
+               {
+                  if (pf->visible)
+                    {
+                       if (evas_map_util_clockwise_get(map))
+                         evas_object_show(mo);
+                       else evas_object_hide(mo);
+                    }
+               }
+
+             // handle smooth
+             if (chosen_desc->map.smooth) evas_map_smooth_set(map, 1);
+             else evas_map_smooth_set(map, 0);
+             // handle alpha
+             if (chosen_desc->map.alpha) evas_map_alpha_set(map, 1);
+             else evas_map_alpha_set(map, 0);
+
+             evas_object_map_set(mo, map);
+             evas_object_map_enable_set(mo, 1);
+             evas_map_free(map);
+          }
+        else
+          {
+             evas_object_map_enable_set(mo, 0);
+             evas_object_map_set(mo, NULL);
+          }
+     }
+
+   ep->x = pf->x;
+   ep->y = pf->y;
+   ep->w = pf->w;
+   ep->h = pf->h;
+
+   ep->calculated |= flags;
+   ep->calculating = FLAG_NONE;
+
+#ifdef EDJE_CALC_CACHE
+   if (ep->calculated == FLAG_XY)
+     {
+       ep->state = ed->state;
+       ep->invalidate = 0;
+     }
+#endif
+
+}
diff --git a/src/lib/edje_callbacks.c b/src/lib/edje_callbacks.c
new file mode 100644 (file)
index 0000000..ffc281d
--- /dev/null
@@ -0,0 +1,559 @@
+/*
+ * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
+ */
+
+#include "edje_private.h"
+
+static void
+_edje_hold_signal_cb(void *data, Evas * e, Evas_Object * obj, void *event_info)
+{
+   Evas_Event_Hold *ev;
+   Edje *ed;
+   Edje_Real_Part *rp;
+
+   ev = event_info;
+   ed = data;
+   rp = evas_object_data_get(obj, "real_part");
+   if (!rp) return;
+   if (ev->hold)
+     _edje_emit(ed, "hold,on", rp->part->name);
+   else
+     _edje_emit(ed, "hold,off", rp->part->name);
+   return;
+   e = NULL;
+}
+
+static void
+_edje_focus_in_signal_cb(void *data, Evas * e, Evas_Object * obj, void *event_info)
+{
+   Edje *ed;
+   Edje_Real_Part *rp;
+
+   ed = data;
+   rp = evas_object_data_get(obj, "real_part");
+   if ((!rp) || (!ed))
+     return;
+
+   _edje_emit(ed, "focus,part,in", rp->part->name);
+   return;
+   e = NULL;
+}
+
+static void
+_edje_focus_out_signal_cb(void *data, Evas * e, Evas_Object * obj, void *event_info)
+{
+   Edje *ed;
+   Edje_Real_Part *rp;
+
+   ed = data;
+   rp = evas_object_data_get(obj, "real_part");
+   if ((!rp) || (!ed))
+     return;
+
+   _edje_emit(ed, "focus,part,out", rp->part->name);
+   return;
+   e = NULL;
+}
+
+static void
+_edje_mouse_in_signal_cb(void *data, Evas * e, Evas_Object * obj, void *event_info)
+{
+   Evas_Event_Mouse_In *ev;
+   Edje *ed;
+   Edje_Real_Part *rp;
+
+   ev = event_info;
+   ed = data;
+   rp = evas_object_data_get(obj, "real_part");
+   if ((!rp) ||
+       ((ev->event_flags) &&
+       (rp->part->ignore_flags & ev->event_flags))) return;
+   _edje_emit(ed, "mouse,in", rp->part->name);
+   return;
+   e = NULL;
+}
+
+static void
+_edje_mouse_out_signal_cb(void *data, Evas * e, Evas_Object * obj, void *event_info)
+{
+   Evas_Event_Mouse_Out *ev;
+   Edje *ed;
+   Edje_Real_Part *rp;
+
+   ev = event_info;
+   ed = data;
+   rp = evas_object_data_get(obj, "real_part");
+   if ((!rp) ||
+       ((ev->event_flags) &&
+       (rp->part->ignore_flags & ev->event_flags))) return;
+   _edje_emit(ed, "mouse,out", rp->part->name);
+   return;
+   e = NULL;
+}
+
+static void
+_edje_mouse_down_signal_cb(void *data, Evas * e, Evas_Object * obj, void *event_info)
+{
+   Evas_Event_Mouse_Down *ev;
+   Edje *ed;
+   Edje_Real_Part *rp;
+   char buf[256];
+   int ignored;
+
+   ev = event_info;
+   ed = data;
+   rp = evas_object_data_get(obj, "real_part");
+   if (!rp) return;
+
+   ignored = rp->part->ignore_flags & ev->event_flags;
+
+   _edje_ref(ed);
+   _edje_freeze(ed);
+
+   if ((!ev->event_flags) || (!ignored))
+     {
+       if (ev->flags & EVAS_BUTTON_TRIPLE_CLICK)
+         snprintf(buf, sizeof(buf), "mouse,down,%i,triple", ev->button);
+       else if (ev->flags & EVAS_BUTTON_DOUBLE_CLICK)
+         snprintf(buf, sizeof(buf), "mouse,down,%i,double", ev->button);
+       else
+         snprintf(buf, sizeof(buf), "mouse,down,%i", ev->button);
+       _edje_emit(ed, buf, rp->part->name);
+     }
+
+   if (rp->events_to)
+     {
+       int x = 0, y = 0;
+       Edje_Real_Part *events;
+
+       events = rp->events_to;
+       evas_object_geometry_get(rp->object, &x, &y, NULL, NULL);
+
+       if ((events->part->dragable.x) || (events->part->dragable.y))
+         {
+            if (events->part->dragable.x)
+              {
+                 events->drag->down.x = ev->canvas.x;
+                 events->drag->tmp.x = 0;
+              }
+            if (events->part->dragable.y)
+              {
+                 events->drag->down.y = ev->canvas.y;
+                 events->drag->tmp.y = 0;
+              }
+
+            if (!ignored)
+              {
+                 snprintf(buf, sizeof(buf), "mouse,down,%i", ev->button);
+                 _edje_emit(ed, buf, events->part->name);
+              }
+            ed->dirty = 1;
+#ifdef EDJE_CALC_CACHE
+            rp->invalidate = 1;
+#endif
+         }
+       _edje_recalc_do(ed);
+       /*
+         _edje_thaw(ed);
+         _edje_unref(ed);
+         _edje_ref(ed);
+         _edje_freeze(ed);
+       */
+       rp = events;
+       {
+          FLOAT_T dx = ZERO, dy = ZERO;
+
+          _edje_part_dragable_calc(ed, rp, &dx, &dy);
+
+          if ((dx != rp->drag->val.x) || (dy != rp->drag->val.y))
+            {
+               rp->drag->val.x = dx;
+               rp->drag->val.y = dy;
+               if (!ignored)
+                 _edje_emit(ed, "drag", rp->part->name);
+               ed->dirty = 1;
+#ifdef EDJE_CALC_CACHE
+               rp->invalidate = 1;
+#endif
+               rp->drag->need_reset = 1;
+               _edje_recalc_do(ed);
+            }
+       }
+     }
+
+   if (rp->drag)
+     {
+       if (rp->drag->down.count == 0)
+         {
+            if (rp->part->dragable.x)
+              rp->drag->down.x = ev->canvas.x;
+            if (rp->part->dragable.y)
+              rp->drag->down.y = ev->canvas.y;
+            if (!ignored)
+              _edje_emit(ed, "drag,start", rp->part->name);
+         }
+       rp->drag->down.count++;
+     }
+
+   if (rp->clicked_button == 0)
+     {
+       rp->clicked_button = ev->button;
+       rp->still_in = 1;
+     }
+//   _edje_recalc_do(ed);
+   _edje_thaw(ed);
+   _edje_unref(ed);
+   return;
+   e = NULL;
+}
+
+static void
+_edje_mouse_up_signal_cb(void *data, Evas * e, Evas_Object * obj, void *event_info)
+{
+   Evas_Event_Mouse_Up *ev;
+   Edje *ed;
+   Edje_Real_Part *rp;
+   char buf[256];
+   int ignored;
+
+   ev = event_info;
+   ed = data;
+   rp = evas_object_data_get(obj, "real_part");
+   if (!rp) return;
+
+   ignored = rp->part->ignore_flags & ev->event_flags;
+
+   _edje_ref(ed);
+   _edje_freeze(ed);
+
+   if ((!ev->event_flags) || (!ignored))
+     {
+       snprintf(buf, sizeof(buf), "mouse,up,%i", ev->button);
+       _edje_emit(ed, buf, rp->part->name);
+     }
+
+   if (rp->events_to)
+     {
+       rp = rp->events_to;
+       if (!ignored)
+         {
+            snprintf(buf, sizeof(buf), "mouse,up,%i", ev->button);
+            _edje_emit(ed, buf, rp->part->name);
+         }
+     }
+
+   if (rp->drag)
+     {
+       if (rp->drag->down.count > 0)
+         {
+            rp->drag->down.count--;
+            if (rp->drag->down.count == 0)
+              {
+                 rp->drag->need_reset = 1;
+                 ed->dirty = 1;
+#ifdef EDJE_CALC_CACHE
+                 rp->invalidate = 1;
+#endif
+                 if (!ignored)
+                   _edje_emit(ed, "drag,stop", rp->part->name);
+              }
+         }
+     }
+
+   if ((rp->still_in) && (rp->clicked_button == ev->button) && (!ignored))
+     {
+       snprintf(buf, sizeof(buf), "mouse,clicked,%i", ev->button);
+       _edje_emit(ed, buf, rp->part->name);
+     }
+   rp->clicked_button = 0;
+   rp->still_in = 0;
+
+//   _edje_recalc_do(ed);
+   _edje_thaw(ed);
+   _edje_unref(ed);
+   return;
+   e = NULL;
+}
+
+static void
+_edje_mouse_move_signal_cb(void *data, Evas * e, Evas_Object * obj, void *event_info)
+{
+   Evas_Event_Mouse_Move *ev;
+   Edje *ed;
+   Edje_Real_Part *rp;
+   int ignored;
+
+   ev = event_info;
+   ed = data;
+   rp = evas_object_data_get(obj, "real_part");
+   if (!rp) return;
+   if (rp->events_to) rp = rp->events_to;
+
+   ignored = rp->part->ignore_flags & ev->event_flags;
+
+   _edje_ref(ed);
+   if ((!ev->event_flags) || (!ignored))
+     _edje_emit(ed, "mouse,move", rp->part->name);
+
+   if (rp->still_in)
+     {
+       Evas_Coord x, y, w, h;
+
+       evas_object_geometry_get(obj, &x, &y, &w, &h);
+       if ((ev->cur.canvas.x < x) || (ev->cur.canvas.y < y) ||
+           (ev->cur.canvas.x >= (x + w)) || (ev->cur.canvas.y >= (y + h)))
+         rp->still_in = 0;
+     }
+   else
+     {
+       Evas_Coord x, y, w, h;
+
+       evas_object_geometry_get(obj, &x, &y, &w, &h);
+       if ((ev->cur.canvas.x >= x) && (ev->cur.canvas.y >= y) &&
+           (ev->cur.canvas.x < (x + w)) && (ev->cur.canvas.y < (y + h)))
+         rp->still_in = 1;
+     }
+   _edje_freeze(ed);
+   if (rp->drag)
+     {
+       if (rp->drag->down.count > 0)
+         {
+            if (rp->part->dragable.x)
+              rp->drag->tmp.x = ev->cur.canvas.x - rp->drag->down.x;
+            if (rp->part->dragable.y)
+              rp->drag->tmp.y = ev->cur.canvas.y - rp->drag->down.y;
+            ed->dirty = 1;
+#ifdef EDJE_CALC_CACHE
+            rp->invalidate = 1;
+#endif
+         }
+       _edje_recalc_do(ed);
+
+       if (rp->drag->down.count > 0)
+         {
+            FLOAT_T dx, dy;
+
+            _edje_part_dragable_calc(ed, rp, &dx, &dy);
+            if ((dx != rp->drag->val.x) || (dy != rp->drag->val.y))
+              {
+                 rp->drag->val.x = dx;
+                 rp->drag->val.y = dy;
+                 if (!ignored)
+                   _edje_emit(ed, "drag", rp->part->name);
+                 ed->dirty = 1;
+#ifdef EDJE_CALC_CACHE
+                 rp->invalidate = 1;
+#endif
+                 _edje_recalc_do(ed);
+              }
+         }
+     }
+   _edje_unref(ed);
+   _edje_thaw(ed);
+   return;
+   e = NULL;
+}
+
+static void
+_edje_mouse_wheel_signal_cb(void *data, Evas * e, Evas_Object * obj, void *event_info)
+{
+   Evas_Event_Mouse_Wheel *ev;
+   Edje *ed;
+   Edje_Real_Part *rp;
+   char buf[256];
+
+   ev = event_info;
+   ed = data;
+   rp = evas_object_data_get(obj, "real_part");
+   if ((!rp) || 
+       ((ev->event_flags) && 
+       (!(rp->part->ignore_flags & ev->event_flags)))) return;
+
+   snprintf(buf, sizeof(buf), "mouse,wheel,%i,%i", ev->direction, (ev->z < 0) ? (-1) : (1));
+   _edje_emit(ed, buf, rp->part->name);
+   return;
+   e = NULL;
+}
+
+int
+_edje_timer_cb(void *data)
+{
+   double t;
+   Eina_List *l;
+   Eina_List *animl = NULL;
+   Edje *ed;
+
+   t = ecore_loop_time_get();
+   EINA_LIST_FOREACH(_edje_animators, l, ed)
+     {
+       _edje_ref(ed);
+       animl = eina_list_append(animl, ed);
+     }
+   while (animl)
+     {
+       Eina_List *newl = NULL;
+
+       ed = eina_list_data_get(animl);
+       _edje_block(ed);
+       _edje_freeze(ed);
+       animl = eina_list_remove(animl, eina_list_data_get(animl));
+       if ((!ed->paused) && (!ed->delete_me))
+         {
+            const void *tmp;
+
+            ed->walking_actions = 1;
+            EINA_LIST_FOREACH(ed->actions, l, tmp)
+              newl = eina_list_append(newl, tmp);
+            while (newl)
+              {
+                 Edje_Running_Program *runp;
+
+                 runp = eina_list_data_get(newl);
+                 newl = eina_list_remove(newl, eina_list_data_get(newl));
+                 if (!runp->delete_me)
+                   _edje_program_run_iterate(runp, t);
+                 if (_edje_block_break(ed))
+                   {
+                      eina_list_free(newl);
+                      newl = NULL;
+                      goto break_prog;
+                   }
+              }
+            EINA_LIST_FOREACH(ed->actions, l, tmp)
+              newl = eina_list_append(newl, tmp);
+            while (newl)
+              {
+                 Edje_Running_Program *runp;
+
+                 runp = eina_list_data_get(newl);
+                 newl = eina_list_remove(newl, eina_list_data_get(newl));
+                 if (runp->delete_me)
+                   {
+                      _edje_anim_count--;
+                      runp->edje->actions =
+                        eina_list_remove(runp->edje->actions, runp);
+                      if (!runp->edje->actions)
+                        _edje_animators =
+                        eina_list_remove(_edje_animators, runp->edje);
+                      free(runp);
+                   }
+              }
+            ed->walking_actions = 0;
+         }
+       break_prog:
+       _edje_unblock(ed);
+       _edje_thaw(ed);
+       _edje_unref(ed);
+     }
+   if (_edje_anim_count > 0) return 1;
+   _edje_timer = NULL;
+   return 0;
+   data = NULL;
+}
+
+int
+_edje_pending_timer_cb(void *data)
+{
+   Edje_Pending_Program *pp;
+
+   pp = data;
+   pp->edje->pending_actions = eina_list_remove(pp->edje->pending_actions, pp);
+   _edje_program_run(pp->edje, pp->program, 1, "", "");
+   free(pp);
+   return 0;
+}
+
+void
+_edje_callbacks_add(Evas_Object *obj, Edje *ed, Edje_Real_Part *rp)
+{
+   evas_object_event_callback_add(obj,
+                                  EVAS_CALLBACK_HOLD,
+                                  _edje_hold_signal_cb,
+                                  ed);
+   evas_object_event_callback_add(obj,
+                                  EVAS_CALLBACK_MOUSE_IN,
+                                  _edje_mouse_in_signal_cb,
+                                  ed);
+   evas_object_event_callback_add(obj,
+                                  EVAS_CALLBACK_MOUSE_OUT,
+                                  _edje_mouse_out_signal_cb,
+                                  ed);
+   evas_object_event_callback_add(obj,
+                                  EVAS_CALLBACK_MOUSE_DOWN,
+                                  _edje_mouse_down_signal_cb,
+                                  ed);
+   evas_object_event_callback_add(obj,
+                                  EVAS_CALLBACK_MOUSE_UP,
+                                  _edje_mouse_up_signal_cb,
+                                  ed);
+   evas_object_event_callback_add(obj,
+                                  EVAS_CALLBACK_MOUSE_MOVE,
+                                  _edje_mouse_move_signal_cb,
+                                  ed);
+   evas_object_event_callback_add(obj,
+                                  EVAS_CALLBACK_MOUSE_WHEEL,
+                                  _edje_mouse_wheel_signal_cb,
+                                  ed);
+   evas_object_data_set(obj, "real_part", rp);
+}
+
+void
+_edje_callbacks_del(Evas_Object *obj, Edje *ed)
+{
+   evas_object_event_callback_del_full(obj,
+                                      EVAS_CALLBACK_HOLD,
+                                      _edje_hold_signal_cb,
+                                      ed);
+   evas_object_event_callback_del_full(obj,
+                                      EVAS_CALLBACK_MOUSE_IN,
+                                      _edje_mouse_in_signal_cb,
+                                      ed);
+   evas_object_event_callback_del_full(obj,
+                                      EVAS_CALLBACK_MOUSE_OUT,
+                                      _edje_mouse_out_signal_cb,
+                                      ed);
+   evas_object_event_callback_del_full(obj,
+                                      EVAS_CALLBACK_MOUSE_DOWN,
+                                      _edje_mouse_down_signal_cb,
+                                      ed);
+   evas_object_event_callback_del_full(obj,
+                                      EVAS_CALLBACK_MOUSE_UP,
+                                      _edje_mouse_up_signal_cb,
+                                      ed);
+   evas_object_event_callback_del_full(obj,
+                                      EVAS_CALLBACK_MOUSE_MOVE,
+                                      _edje_mouse_move_signal_cb,
+                                      ed);
+   evas_object_event_callback_del_full(obj,
+                                      EVAS_CALLBACK_MOUSE_WHEEL,
+                                      _edje_mouse_wheel_signal_cb,
+                                      ed);
+   evas_object_data_del(obj, "real_part");
+}
+
+void
+_edje_callbacks_focus_add(Evas_Object *obj, Edje *ed, Edje_Real_Part *rp)
+{
+   evas_object_event_callback_add(obj,
+                                 EVAS_CALLBACK_FOCUS_IN,
+                                 _edje_focus_in_signal_cb,
+                                 ed);
+   evas_object_event_callback_add(obj,
+                                 EVAS_CALLBACK_FOCUS_OUT,
+                                 _edje_focus_out_signal_cb,
+                                 ed);
+   evas_object_data_set(obj, "real_part", rp);
+}
+
+void
+_edje_callbacks_focus_del(Evas_Object *obj, Edje *ed)
+{
+   evas_object_event_callback_del_full(obj,
+                                      EVAS_CALLBACK_FOCUS_IN,
+                                      _edje_focus_in_signal_cb,
+                                      ed);
+   evas_object_event_callback_del_full(obj,
+                                      EVAS_CALLBACK_FOCUS_OUT,
+                                      _edje_focus_out_signal_cb,
+                                      ed);
+}
diff --git a/src/lib/edje_container.c b/src/lib/edje_container.c
new file mode 100644 (file)
index 0000000..6a6795d
--- /dev/null
@@ -0,0 +1,959 @@
+/*
+ * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
+ */
+
+#include "edje_private.h"
+#include "edje_container.h"
+
+#if 0
+
+static void
+_edje_container_relayout(Smart_Data *sd)
+{
+   Eina_List *l;
+   Evas_Coord x, y, w, h, sw;
+   Edje_Item *ei;
+
+   if (sd->freeze > 0) return;
+   if (!sd->need_layout) return;
+
+   if (sd->w < sd->min_w) sw = sd->min_w;
+   else if (sd->w > sd->max_w) sw = sd->max_w;
+   else sw = sd->w;
+
+   y = 0;
+   x = 0;
+   w = 0;
+   h = 0;
+
+   EINA_LIST_FOREACH(sd->children, l, ei)
+     {
+       if (sd->homogenous) h = sd->min_row_h;
+
+       ei->y = y;
+       ei->h = h;
+//     ei->w = w;
+//     ei->h = h;
+     }
+
+   sd->need_layout = 0;
+}
+
+static void
+_edje_container_recalc(Smart_Data *sd)
+{
+   Eina_List *l;
+   Edje_Item *ei;
+   int any_max_h = 0, any_max_w = 0;
+   int i;
+
+   if (sd->freeze > 0) return;
+   if (!sd->changed) return;
+
+   sd->min_h = 0;
+   sd->max_h = -1;
+   sd->min_w = 0;
+   sd->max_w = -1;
+   sd->min_row_h = 0;
+   sd->max_row_h = -1;
+   sd->contents_h = 0;
+   sd->contents_w = 0;
+
+   for (i = 0; i < sd->cols; i++)
+     {
+       sd->min_w += sd->colinfo[i].minw;
+       if (sd->colinfo[i].maxw >= 0)
+         {
+            if (sd->max_w >= 0)
+              sd->max_w += sd->colinfo[i].maxw;
+            else
+              sd->max_w = sd->colinfo[i].maxw;
+         }
+       else
+         any_max_w = 1;
+     }
+   if (any_max_w) sd->max_w = -1;
+
+   if (sd->w < sd->min_w)
+     sd->contents_w = sd->min_w;
+   else if ((sd->max_w >= 0) && (sd->w < sd->max_w))
+     sd->w = sd->max_w;
+
+   EINA_LIST_FOREACH(sd->children, l, ei)
+     {
+       if (ei->minh > sd->min_row_h)
+         sd->min_row_h = ei->minh;
+       if (sd->max_row_h >= 0)
+         {
+            if (ei->maxh >= 0)
+              {
+                 if (sd->max_row_h > ei->maxh)
+                   sd->max_row_h = ei->maxh;
+              }
+            else
+              any_max_h = 1;
+         }
+       sd->min_h += ei->minh;
+       if (ei->maxh >= 0)
+         {
+            if (sd->max_h >= 0)
+              sd->max_h += ei->maxh;
+            else
+              sd->max_h = ei->maxh;
+         }
+       else
+         any_max_h = 1;
+     }
+   if (any_max_h)
+     {
+       sd->max_h = -1;
+       sd->max_row_h = -1;
+     }
+   if (sd->homogenous)
+     {
+       sd->min_h = eina_list_count(sd->children) * sd->min_row_h;
+     }
+
+   sd->changed = 0;
+   sd->change_child = 0;
+   sd->change_child_list = 0;
+   sd->change_cols = 0;
+
+   sd->need_layout = 1;
+   _edje_container_relayout(sd);
+}
+
+static void
+_edje_item_recalc(Edje_Item *ei)
+{
+   int i;
+
+   if (ei->freeze > 0) return;
+   if (!ei->recalc) return;
+   if (!ei->sd) return;
+
+   ei->minh = 0;
+   ei->maxh = -1;
+   for (i = 0; i < ((Smart_Data *)(ei->sd))->cols; i++)
+     {
+       if (ei->cells[i].minh > ei->minh) ei->minh = ei->cells[i].minh;
+       if (ei->cells[i].maxh >= 0)
+         {
+            if (ei->maxh >= 0)
+              {
+                 if (ei->cells[i].maxh < ei->maxh)
+                   ei->maxh = ei->cells[i].maxh;
+              }
+            else
+              ei->maxh = ei->cells[i].maxh;
+         }
+       if (((Smart_Data *)(ei->sd))->colinfo[i].minw < ei->cells[i].minw)
+         ((Smart_Data *)(ei->sd))->colinfo[i].minw = ei->cells[i].minw;
+       if (((Smart_Data *)(ei->sd))->colinfo[i].maxw >= 0)
+         {
+            if (ei->cells[i].maxw >= 0)
+              {
+                 if (((Smart_Data *)(ei->sd))->colinfo[i].maxw > ei->cells[i].maxw)
+                   ((Smart_Data *)(ei->sd))->colinfo[i].maxw = ei->cells[i].maxw;
+              }
+         }
+       else
+         ((Smart_Data *)(ei->sd))->colinfo[i].maxw = ei->cells[i].maxw;
+     }
+
+   ei->recalc = 0;
+
+   _edje_container_recalc(ei->sd);
+}
+
+
+/*****************************/
+/**
+ * @endcond
+ */
+
+/*============================================================================*
+ *                                 Global                                     *
+ *============================================================================*/
+
+/*============================================================================*
+ *                                   API                                      *
+ *============================================================================*/
+
+/**
+ * @addtogroup Edje_container_Group Container
+ *
+ * @brief These functions provides an abstraction layer between the application
+ * code and the interface, while allowing extremely flexible dynamic layouts
+ * and animations.
+ *
+ * For more information, you can look at the @ref tutorial_list_page.
+ *
+ * @{
+ */
+
+/**
+ * @brief Create an edje item.
+ *
+ * @param cl The edje item of type Edje_Item_Class.
+ * @param data The edje item data.
+ *
+ * @return The new edje item created.
+ *
+ * This function creates an new edje item. The edje item data can be
+ * retrieved with edje_item_data_get().
+ *
+ * @see edje_item_del()
+ * @see edje_item_data_set()
+ * @see edje_item_data_get()
+ *
+ */
+
+Edje_Item *
+edje_item_add(Edje_Item_Class *cl, void *data)
+{
+   Edje_Item *ei;
+
+   ei = calloc(sizeof(Edje_Item), 1);
+
+   ei->class = cl;
+   ei->class_data = data;
+
+   return ei;
+}
+
+/**
+ * @brief Delete an edje item.
+ *
+ * @param ei The edje item to be deleted.
+ *
+ * This function deletes the edje item from memory.
+ *
+ * @see edje_item_add()
+ * @see edje_item_data_set()
+ * @see edje_item_data_get()
+ *
+ */
+
+void
+edje_item_del(Edje_Item *ei)
+{
+   Smart_Data *sd;
+
+   sd = ei->sd;
+   if (ei->object) evas_object_del(ei->object);
+   if (ei->overlay_object) evas_object_del(ei->overlay_object);
+   free(ei);
+   if (!sd) return;
+   sd->changed = 1;
+   sd->change_child_list = 1;
+   _edje_container_recalc(sd);
+}
+
+/**
+ * @brief Return the smart object of the edje item.
+ *
+ * @param ei The edje item wich the smart object of type Evas_Object is get
+ * from.
+ *
+ * This function returns the smart object in the edje item.
+ *
+ */
+
+Evas_Object *
+edje_item_container_get(Edje_Item *ei)
+{
+   if (!ei->sd) return NULL;
+   return ((Smart_Data *)(ei->sd))->smart_obj;
+}
+
+/* an arbitary data pointer to use to track other data */
+/**
+ * @brief Set the edje item data.
+ *
+ * @param ei The edje item of type Edje_Item_Class.
+ * @param data The edje item data.
+ *
+ * This function set the data of the edje item. The edje item data can be
+ * retrieved with edje_item_data_get().
+ *
+ * @see edje_item_add()
+ * @see edje_item_del()
+ * @see edje_item_data_get()
+ *
+ */
+
+void
+edje_item_data_set(Edje_Item *ei, void *data)
+{
+   ei->data = data;
+}
+
+/**
+ * @brief Get the data of the edje item.
+ *
+ * @param ei The edje item of type Edje_Item_Class.
+ *
+ * This function get the data of the edje item set by edje_item_data_set().
+ *
+ * @see edje_item_data_set()
+ * @see edje_item_add()
+ * @see edje_item_del()
+ *
+ */
+
+void *
+edje_item_data_get(Edje_Item *ei)
+{
+   return ei->data;
+}
+
+/* this object covers the entire item */
+
+void
+edje_item_overlay_object_set(Edje_Item *ei, Evas_Object *obj)
+{
+   if (ei->overlay_object)
+     {
+       /* FIXME: if it changed - remove...*/
+     }
+   ei->overlay_object = obj;
+   if (ei->sd)
+     evas_object_smart_member_add(((Smart_Data *)(ei->sd))->smart_obj, obj);
+}
+
+
+
+Evas_Object *
+edje_item_overlay_object_get(Edje_Item *ei)
+{
+   return ei->overlay_object;
+}
+
+/* this object goes under entire item */
+void
+edje_item_object_set(Edje_Item *ei, Evas_Object *obj)
+{
+   if (ei->object)
+     {
+       /* FIXME: if it changed - remove...*/
+     }
+   ei->object = obj;
+   if (ei->sd)
+     evas_object_smart_member_add(((Smart_Data *)(ei->sd))->smart_obj, obj);
+}
+
+Evas_Object *
+edje_item_object_get(Edje_Item *ei)
+{
+   return ei->object;
+}
+
+/* optionally you can manage each column's object yourself OR let Edje do it */
+void
+edje_item_object_column_set(Edje_Item *ei, int col, Evas_Object *obj)
+{
+   if (ei->cells_num <= (col + 1))
+     {
+       /* FIXME: unsafe realloc */
+       ei->cells = realloc(ei->cells, sizeof(Edje_Item_Cell) * col);
+       ei->cells_num = col + 1;
+     }
+   ei->cells[col].obj = obj;
+}
+
+Evas_Object *
+edje_item_object_column_get(Edje_Item *ei, int col)
+{
+   if (ei->cells_num <= (col + 1)) return NULL;
+   return ei->cells[col].obj;
+}
+
+/* query the item for the items preferred co-ords */
+void
+edje_item_geometry_get(Edje_Item *ei, Evas_Coord *x, Evas_Coord *y, Evas_Coord *w, Evas_Coord *h)
+{
+   if (!ei->sd)
+     {
+       if (x) *x = 0;
+       if (y) *y = 0;
+       if (w) *w = 0;
+       if (h) *h = 0;
+       return;
+     }
+   if (x) *x = ((Smart_Data *)(ei->sd))->x;
+   if (y) *y = ((Smart_Data *)(ei->sd))->y + ei->y;
+   if (w) *w = ((Smart_Data *)(ei->sd))->w;
+   if (h) *h = ei->h;
+}
+
+/* freeze and thaw items if u are about to do a bunch of changes */
+int
+edje_item_freeze(Edje_Item *ei)
+{
+   ei->freeze++;
+   return ei->freeze;
+}
+
+int
+edje_item_thaw(Edje_Item *ei)
+{
+   ei->freeze--;
+   if (ei->freeze > 0) return ei->freeze;
+   if (!ei->sd) return ei->freeze;
+   if (ei->recalc) _edje_item_recalc(ei);
+   return ei->freeze;
+}
+
+/* column info */
+void
+edje_item_column_size_set(Edje_Item *ei, int col, Evas_Coord minw, Evas_Coord maxw, Evas_Coord minh, Evas_Coord maxh)
+{
+   if (ei->cells_num <= (col + 1))
+     {
+       /* FIXME: unsafe realloc */
+       ei->cells = realloc(ei->cells, sizeof(Edje_Item_Cell) * col);
+       ei->cells_num = col + 1;
+     }
+   if ((ei->cells[col].minw == minw) &&
+       (ei->cells[col].minh == minh) &&
+       (ei->cells[col].maxw == maxw) &&
+       (ei->cells[col].maxh == maxh)) return;
+   ei->cells[col].minh = minh;
+   ei->cells[col].maxh = maxh;
+   ei->cells[col].minw = minw;
+   ei->cells[col].maxw = maxw;
+   ei->recalc = 1;
+   if (ei->sd)
+     {
+       ((Smart_Data *)(ei->sd))->changed = 1;
+       ((Smart_Data *)(ei->sd))->change_child = 1;
+     }
+   _edje_item_recalc(ei);
+}
+
+void
+edje_item_column_size_get(Edje_Item *ei, int col, Evas_Coord *minw, Evas_Coord *maxw, Evas_Coord *minh, Evas_Coord *maxh)
+{
+   if (ei->cells_num <= (col + 1))
+     {
+       if (minw) *minw = 0;
+       if (minh) *minh = 0;
+       if (maxw) *maxw = -1;
+       if (maxh) *maxh = -1;
+     }
+   if (minw) *minw = ei->cells[col].minw;
+   if (minh) *minh = ei->cells[col].minh;
+   if (maxw) *maxw = ei->cells[col].maxw;
+   if (maxh) *maxh = ei->cells[col].maxh;
+}
+
+/* selection stuff */
+void
+edje_item_select(Edje_Item *ei)
+{
+   ei->selected = 1;
+   /* FIXME: trigger item to change visually */
+}
+
+void
+edje_item_unselect(Edje_Item *ei)
+{
+   ei->selected = 0;
+   /* FIXME: trigger item to change visually */
+}
+
+/* focus stuff - only 1 can be focuesd */
+void
+edje_item_focus(Edje_Item *ei)
+{
+//   ei->focused = 1;
+}
+
+void
+edje_item_unfocus(Edje_Item *ei)
+{
+//   ei->focused = 0;
+}
+
+/* disable/enable stuff - stops focus and selection working on these items */
+void
+edje_item_enable(Edje_Item *ei)
+{
+//   ei->disabled = 0;
+}
+
+void
+edje_item_disable(Edje_Item *ei)
+{
+//   ei->disabled = 1;
+}
+
+/* item utils */
+int
+edje_item_selected_get(Edje_Item *ei)
+{
+   return ei->selected;
+}
+
+int
+edje_item_focused_get(Edje_Item *ei)
+{
+   return ei->focused;
+}
+
+int
+edje_item_disabled_get(Edje_Item *ei)
+{
+   return ei->disabled;
+}
+
+/***** container calls *****/
+
+int
+edje_container_freeze(Evas_Object *obj)
+{
+   Smart_Data *sd;
+
+   sd = evas_object_smart_data_get(obj);
+   if (!sd) return 0;
+   sd->freeze++;
+   return sd->freeze;
+}
+
+int
+edje_container_thaw(Evas_Object *obj)
+{
+   Smart_Data *sd;
+
+   sd = evas_object_smart_data_get(obj);
+   if (!sd) return 0;
+   sd->freeze--;
+   if (sd->freeze <= 0) _edje_container_recalc(sd);
+   return sd->freeze;
+}
+
+void
+edje_container_item_append(Evas_Object *obj, Edje_Item *ei)
+{
+   Smart_Data *sd;
+
+   sd = evas_object_smart_data_get(obj);
+   if (!sd) return;
+   sd->children = eina_list_append(sd->children, ei);
+   sd->changed = 1;
+   sd->change_child_list = 1;
+   sd->rows = eina_list_count(sd->children);
+   _edje_container_recalc(sd);
+}
+
+void
+edje_container_item_prepend(Evas_Object *obj, Edje_Item *ei)
+{
+   Smart_Data *sd;
+
+   sd = evas_object_smart_data_get(obj);
+   if (!sd) return;
+   sd->children = eina_list_prepend(sd->children, ei);
+   sd->changed = 1;
+   sd->change_child_list = 1;
+   sd->rows = eina_list_count(sd->children);
+   _edje_container_recalc(sd);
+}
+
+void
+edje_container_item_append_relative(Evas_Object *obj, Edje_Item *ei, Edje_Item *rel)
+{
+   Smart_Data *sd;
+
+   sd = evas_object_smart_data_get(obj);
+   if (!sd) return;
+   sd->children = eina_list_append_relative(sd->children, ei, rel);
+   sd->changed = 1;
+   sd->change_child_list = 1;
+   sd->rows = eina_list_count(sd->children);
+   _edje_container_recalc(sd);
+}
+
+void
+edje_container_item_prepend_relative(Evas_Object *obj, Edje_Item *ei, Edje_Item *rel)
+{
+   Smart_Data *sd;
+
+   sd = evas_object_smart_data_get(obj);
+   if (!sd) return;
+   sd->children = eina_list_prepend_relative(sd->children, ei, rel);
+   sd->changed = 1;
+   sd->change_child_list = 1;
+   sd->rows = eina_list_count(sd->children);
+   _edje_container_recalc(sd);
+}
+
+void
+edje_container_item_insert(Evas_Object *obj, Edje_Item *ei, int n)
+{
+   Smart_Data *sd;
+   void *rel;
+
+   sd = evas_object_smart_data_get(obj);
+   if (!sd) return;
+   rel = eina_list_nth(sd->children, n);
+   if (!rel)
+     sd->children = eina_list_append(sd->children, ei);
+   else
+     sd->children = eina_list_append_relative(sd->children, ei, rel);
+   sd->changed = 1;
+   sd->change_child_list = 1;
+   sd->rows = eina_list_count(sd->children);
+   _edje_container_recalc(sd);
+}
+
+void
+edje_container_item_remove(Evas_Object *obj, Edje_Item *ei)
+{
+   Smart_Data *sd;
+
+   sd = evas_object_smart_data_get(obj);
+   if (!sd) return;
+   sd->children = eina_list_remove(sd->children, ei);
+   sd->changed = 1;
+   sd->change_child_list = 1;
+   sd->rows = eina_list_count(sd->children);
+   _edje_container_recalc(sd);
+}
+
+void
+edje_container_columns_set(Evas_Object *obj, int cols)
+{
+   Smart_Data *sd;
+
+   sd = evas_object_smart_data_get(obj);
+   if (!sd) return;
+   if (sd->cols == cols) return;
+   sd->colinfo = realloc(sd->colinfo, cols * sizeof(Smart_Data_Colinfo));
+   if (cols > sd->cols)
+     {
+       int i;
+
+       for (i = sd->cols; i < cols; i++)
+         {
+            sd->colinfo[i].minw = 0;
+            sd->colinfo[i].maxw = -1;
+         }
+     }
+   sd->cols = cols;
+   sd->changed = 1;
+   sd->change_cols = 1;
+   _edje_container_recalc(sd);
+}
+
+int
+edje_container_columns_get(Evas_Object *obj)
+{
+   Smart_Data *sd;
+
+   sd = evas_object_smart_data_get(obj);
+   if (!sd) return 0;
+   return sd->cols;
+}
+
+void
+edje_container_min_size_get(Evas_Object *obj, Evas_Coord *minw, Evas_Coord *minh)
+{
+   Smart_Data *sd;
+
+   sd = evas_object_smart_data_get(obj);
+   if (!sd) return;
+   if (sd->changed)
+     {
+       int freeze;
+
+       freeze = sd->freeze;
+       sd->freeze = 0;
+       _edje_container_recalc(sd);
+       sd->freeze = freeze;
+     }
+   if (minw) *minw = sd->min_w;
+   if (minh) *minh = sd->min_h;
+}
+
+void
+edje_container_max_size_get(Evas_Object *obj, Evas_Coord *maxw, Evas_Coord *maxh)
+{
+   Smart_Data *sd;
+
+   sd = evas_object_smart_data_get(obj);
+   if (!sd) return;
+   if (sd->changed)
+     {
+       int freeze;
+
+       freeze = sd->freeze;
+       sd->freeze = 0;
+       _edje_container_recalc(sd);
+       sd->freeze = freeze;
+     }
+   if (maxw) *maxw = sd->max_w;
+   if (maxh) *maxh = sd->max_h;
+}
+
+void
+edje_containter_align_set(Evas_Object *obj, double halign, double valign)
+{
+   Smart_Data *sd;
+
+   sd = evas_object_smart_data_get(obj);
+   if (!sd) return;
+   if ((sd->align_x == halign) && (sd->align_y == valign)) return;
+   sd->align_x = halign;
+   sd->align_y = valign;
+   sd->need_layout = 1;
+   _edje_container_relayout(sd);
+}
+
+void
+edje_container_align_get(Evas_Object *obj, double *halign, double *valign)
+{
+   Smart_Data *sd;
+
+   sd = evas_object_smart_data_get(obj);
+   if (!sd) return;
+   if (halign) *halign = sd->align_x;
+   if (valign) *valign = sd->align_y;
+}
+
+int
+edje_container_count_get(Evas_Object *obj)
+{
+   Smart_Data *sd;
+
+   sd = evas_object_smart_data_get(obj);
+   if (!sd) return 0;
+   return eina_list_count(sd->children);
+}
+
+Edje_Item *
+edje_container_item_first_get(Evas_Object *obj)
+{
+   Smart_Data *sd;
+
+   sd = evas_object_smart_data_get(obj);
+   if (!sd) return NULL;
+   if (!sd->children) return NULL;
+   return eina_list_data_get(sd->children);
+}
+
+Edje_Item *
+edje_container_item_last_get(Evas_Object *obj)
+{
+   Smart_Data *sd;
+
+   sd = evas_object_smart_data_get(obj);
+   if (!sd) return NULL;
+   if (!sd->children) return NULL;
+   return0 eina_list_data_get(eina_list_last(sd->children));
+}
+
+Edje_Item *
+edje_container_item_nth_get(Evas_Object *obj, int n)
+{
+   Smart_Data *sd;
+
+   sd = evas_object_smart_data_get(obj);
+   if (!sd) return NULL;
+   return eina_list_nth(sd->children, n);
+}
+
+void
+edje_container_homogenous_size_set(Evas_Object *obj, int homog)
+{
+   Smart_Data *sd;
+
+   sd = evas_object_smart_data_get(obj);
+   if (!sd) return;
+   if (((homog) && (sd->homogenous)) ||
+       ((!homog) && (!sd->homogenous))) return;
+   sd->homogenous = homog;
+   sd->changed = 1;
+   sd->change_child = 1;
+   _edje_container_recalc(sd);
+}
+
+int
+edje_container_homogenous_size_get(Evas_Object *obj)
+{
+   Smart_Data *sd;
+
+   sd = evas_object_smart_data_get(obj);
+   if (!sd) return 0;
+   return sd->homogenous;
+}
+
+void
+edje_container_scroll_set(Evas_Object *obj, double pos, double shift)
+{
+   Smart_Data *sd;
+
+   sd = evas_object_smart_data_get(obj);
+   if (!sd) return;
+   if ((sd->scroll_y == pos) && (sd->scroll_x == shift)) return;
+   sd->scroll_y = pos;
+   sd->scroll_x = shift;
+   sd->need_layout = 1;
+   _edje_container_relayout(sd);
+}
+
+void
+edje_container_scroll_get(Evas_Object *obj, double *pos, double *shift)
+{
+   Smart_Data *sd;
+
+   sd = evas_object_smart_data_get(obj);
+   if (!sd) return;
+   if (pos) *pos = sd->scroll_y;
+   if (shift) *shift = sd->scroll_x;
+}
+
+static void _smart_init(void);
+static void _smart_add(Evas_Object * obj);
+static void _smart_del(Evas_Object * obj);
+static void _smart_move(Evas_Object * obj, Evas_Coord x, Evas_Coord y);
+static void _smart_resize(Evas_Object * obj, Evas_Coord w, Evas_Coord h);
+static void _smart_show(Evas_Object * obj);
+static void _smart_hide(Evas_Object * obj);
+static void _smart_color_set(Evas_Object * obj, int r, int g, int b, int a);
+static void _smart_clip_set(Evas_Object * obj, Evas_Object * clip);
+static void _smart_clip_unset(Evas_Object * obj);
+
+static Evas_Smart  *smart = NULL;
+
+Evas_Object *
+edje_container_object_add(Evas *evas)
+{
+   _smart_init();
+   return evas_object_smart_add(evas, smart);
+}
+
+/*******************************************/
+/* Internal smart object required routines */
+/*******************************************/
+static void
+_smart_init(void)
+{
+   if (smart) return;
+     {
+       static const Evas_Smart_Class sc =
+         {
+            E_OBJ_NAME,
+              _smart_add,
+              _smart_del,
+              _smart_move,
+              _smart_resize,
+              _smart_show,
+              _smart_hide,
+              _smart_color_set,
+              _smart_clip_set,
+              _smart_clip_unset,
+              NULL,
+              NULL,
+              NULL
+         };
+        smart = evas_smart_class_new(&sc);
+     }
+}
+
+static void
+_smart_add(Evas_Object *obj)
+{
+   Smart_Data *sd;
+
+   sd = calloc(1, sizeof(Smart_Data));
+   if (!sd) return;
+//   evas_object_smart_member_add(sd->obj, obj);
+   evas_object_smart_data_set(obj, sd);
+   sd->smart_obj = obj;
+}
+
+static void
+_smart_del(Evas_Object *obj)
+{
+   Smart_Data *sd;
+
+   sd = evas_object_smart_data_get(obj);
+   if (!sd) return;
+   if (sd->colinfo) free(sd->colinfo);
+//   evas_object_del(sd->obj);
+   free(sd);
+}
+
+static void
+_smart_move(Evas_Object *obj, Evas_Coord x, Evas_Coord y)
+{
+   Smart_Data *sd;
+
+   sd = evas_object_smart_data_get(obj);
+   if (!sd) return;
+//   evas_object_move(sd->obj, x, y);
+}
+
+static void
+_smart_resize(Evas_Object *obj, Evas_Coord w, Evas_Coord h)
+{
+   Smart_Data *sd;
+
+   sd = evas_object_smart_data_get(obj);
+   if (!sd) return;
+//   evas_object_resize(sd->obj, w, h);
+}
+
+static void
+_smart_show(Evas_Object *obj)
+{
+   Smart_Data *sd;
+
+   sd = evas_object_smart_data_get(obj);
+   if (!sd) return;
+//   evas_object_show(sd->obj);
+}
+
+static void
+_smart_hide(Evas_Object *obj)
+{
+   Smart_Data *sd;
+
+   sd = evas_object_smart_data_get(obj);
+   if (!sd) return;
+//   evas_object_hide(sd->obj);
+}
+
+static void
+_smart_color_set(Evas_Object *obj, int r, int g, int b, int a)
+{
+   Smart_Data *sd;
+
+   sd = evas_object_smart_data_get(obj);
+   if (!sd) return;
+//   evas_object_color_set(sd->obj, r, g, b, a);
+}
+
+static void
+_smart_clip_set(Evas_Object *obj, Evas_Object *clip)
+{
+   Smart_Data *sd;
+
+   sd = evas_object_smart_data_get(obj);
+   if (!sd) return;
+//   evas_object_clip_set(sd->obj, clip);
+}
+
+static void
+_smart_clip_unset(Evas_Object *obj)
+{
+   Smart_Data *sd;
+
+   sd = evas_object_smart_data_get(obj);
+   if (!sd) return;
+//   evas_object_clip_unset(sd->obj);
+}
+
+#endif
diff --git a/src/lib/edje_container.h b/src/lib/edje_container.h
new file mode 100644 (file)
index 0000000..b2b154e
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+ * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
+ */
+
+#include "edje_private.h"
+
+
+#define E_SMART_OBJ_GET(smart, o, type) \
+     { \
+       char *_e_smart_str; \
+       \
+       if (!o) return; \
+       smart = evas_object_smart_data_get(o); \
+       if (!smart) return; \
+       _e_smart_str = (char *)evas_object_type_get(o); \
+       if (!_e_smart_str) return; \
+       if (strcmp(_e_smart_str, type)) return; \
+     }
+
+#define E_SMART_OBJ_GET_RETURN(smart, o, type, ret) \
+   { \
+      char *_e_smart_str; \
+      \
+      if (!o) return ret; \
+      smart = evas_object_smart_data_get(o); \
+      if (!smart) return ret; \
+      _e_smart_str = (char *)evas_object_type_get(o); \
+      if (!_e_smart_str) return ret; \
+      if (strcmp(_e_smart_str, type)) return ret; \
+   }
+
+#define E_OBJ_NAME "edje_container_object"
+
+typedef struct _Smart_Data         Smart_Data;
+typedef struct _Smart_Data_Colinfo Smart_Data_Colinfo;
+
+struct _Smart_Data
+{
+   Evas_Coord     x, y, w, h;
+   Eina_List     *children;
+   Evas_Object   *smart_obj;
+   int            cols, rows;
+
+   Evas_Coord     contents_w, contents_h;
+   Evas_Coord     min_row_h, max_row_h;
+   Evas_Coord     min_w, max_w, min_h, max_h;
+
+   Smart_Data_Colinfo *colinfo;
+
+   int            freeze;
+
+   double         scroll_x, scroll_y;
+   double         align_x, align_y;
+
+   unsigned char  changed : 1;
+   unsigned char  change_child : 1;
+   unsigned char  change_child_list : 1;
+   unsigned char  change_cols : 1;
+   unsigned char  change_scroll : 1;
+
+   unsigned char  need_layout : 1;
+
+   unsigned char  homogenous : 1;
+};
+
+struct _Smart_Data_Colinfo
+{
+   Evas_Coord minw, maxw;
+};
+
+/* All items are virtual constructs that provide Evas_Objects at some point.
+ * Edje may move, resize, show, hide, clip, unclip, raise, lower etc. this
+ * item AFTER it calls the item's add() method and before it calls the del()
+ * method. Edje may call add() and del() at any time as often items may not
+ * be visible and so may not need to exist at all - they are merely information
+ * used for layout, and nothing more. this helps save cpu and memory keeping
+ * things responsive for BIG lists of items. you create an item from an item
+ * class then ask that item to be appended/prepended etc. to the container.
+ */
+typedef struct _Edje_Item       Edje_Item;
+typedef struct _Edje_Item_Cell  Edje_Item_Cell;
+typedef struct _Edje_Item_Class Edje_Item_Class;
+
+struct _Edje_Item_Class
+{
+   Evas_Object *(*add)      (Edje_Item *ei);
+   void         (*del)      (Edje_Item *ei);
+   void         (*select)   (Edje_Item *ei);
+   void         (*deselect) (Edje_Item *ei);
+   void         (*focus)    (Edje_Item *ei);
+   void         (*unfocus)  (Edje_Item *ei);
+};
+
+/* private */
+struct _Edje_Item
+{
+   Edje_Item_Class *class;
+   void            *class_data;
+
+   void            *sd;
+
+   void            *data;
+
+   Evas_Object     *object;
+   Evas_Object     *overlay_object;
+   int              freeze;
+   Evas_Coord       y, h;
+
+   Evas_Coord       minh, maxh;
+
+   int              cells_num;
+   Edje_Item_Cell  *cells;
+
+   unsigned char    accessible : 1;
+
+   unsigned char    recalc : 1;
+   unsigned char    selected : 1;
+   unsigned char    disabled : 1;
+   unsigned char    focused : 1;
+};
+
+struct _Edje_Item_Cell
+{
+   Evas_Object *obj;
+   Evas_Coord   x, w;
+   Evas_Coord   minw, minh, maxw, maxh;
+};
+
+/* here is an item for a vertical list - with 1 or more columns. this has 3 */
+/* just rotate for a horizontal list */
+
+/*
+ *             COL 0                 COL 1          COL 2
+ *
+ * +-----------------------------+ +-------+ +----------------+
+ * |          pad_top            | |       | |                |
+ * | pad_left  OBJECT  pad_right | |  OBJ  | |     OBJECT     | ROW 0
+ * |         pad_bottom          | |       | |                |
+ * +-----------------------------+ +-------+ +----------------+
+ *               /\              /|\
+ *     space_row ||               +-- space_col
+ *               \/
+ * +-----------------------------+ +-------+ +----------------+
+ * |                             | |       | |                |
+ * |                             | |       | |                | ROW 1
+ * |                             | |       | |                |
+ * +-----------------------------+ +-------+ +----------------+
+ *
+ * spacer object:
+ * 1 Edje object goes in-between each row as a spacer object (opt)
+ * 1 Edje object goes in-between each column as a spacer object (opt)
+ *
+ * surround object:
+ * 1 Edje object goes around each item - item swallowed into "item" part (opt)
+ *   if no "item" part then just underlay it
+ *   on select send "select" "" signal
+ *   on unselect send "unselect" "" signal
+ *   on focus send "focus" "" signal
+ *   on unfocus send "unfocus" signal
+ *
+ *   if any list item/cell is an Edje object emit this to them too.
+ *
+ *   also call callbacks.
+ *   if a surround object emits such a signal itself then call callbacks too
+ *
+ * only 1 or 0 items can be focused
+ * disabled items cannot be focused or selected/deselected
+ *
+ */
diff --git a/src/lib/edje_data.c b/src/lib/edje_data.c
new file mode 100644 (file)
index 0000000..e62f16e
--- /dev/null
@@ -0,0 +1,452 @@
+/*
+ * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
+ */
+
+#include "edje_private.h"
+
+EAPI Eet_Data_Descriptor *_edje_edd_edje_file = NULL;
+EAPI Eet_Data_Descriptor *_edje_edd_edje_style = NULL;
+EAPI Eet_Data_Descriptor *_edje_edd_edje_style_tag = NULL;
+EAPI Eet_Data_Descriptor *_edje_edd_edje_color_class = NULL;
+EAPI Eet_Data_Descriptor *_edje_edd_edje_data = NULL;
+EAPI Eet_Data_Descriptor *_edje_edd_edje_external_directory = NULL;
+EAPI Eet_Data_Descriptor *_edje_edd_edje_external_directory_entry = NULL;
+EAPI Eet_Data_Descriptor *_edje_edd_edje_font_directory = NULL;
+EAPI Eet_Data_Descriptor *_edje_edd_edje_font_directory_entry = NULL;
+EAPI Eet_Data_Descriptor *_edje_edd_edje_image_directory = NULL;
+EAPI Eet_Data_Descriptor *_edje_edd_edje_image_directory_entry = NULL;
+EAPI Eet_Data_Descriptor *_edje_edd_edje_spectrum_directory = NULL;
+EAPI Eet_Data_Descriptor *_edje_edd_edje_spectrum_directory_entry = NULL;
+EAPI Eet_Data_Descriptor *_edje_edd_edje_spectrum_color = NULL;
+EAPI Eet_Data_Descriptor *_edje_edd_edje_program = NULL;
+EAPI Eet_Data_Descriptor *_edje_edd_edje_program_target = NULL;
+EAPI Eet_Data_Descriptor *_edje_edd_edje_program_after = NULL;
+EAPI Eet_Data_Descriptor *_edje_edd_edje_part_collection_directory = NULL;
+EAPI Eet_Data_Descriptor *_edje_edd_edje_part_collection_directory_entry = NULL;
+EAPI Eet_Data_Descriptor *_edje_edd_edje_pack_element = NULL;
+EAPI Eet_Data_Descriptor *_edje_edd_edje_part_collection = NULL;
+EAPI Eet_Data_Descriptor *_edje_edd_edje_part = NULL;
+EAPI Eet_Data_Descriptor *_edje_edd_edje_part_description = NULL;
+EAPI Eet_Data_Descriptor *_edje_edd_edje_part_image_id = NULL;
+EAPI Eet_Data_Descriptor *_edje_edd_edje_external_param = NULL;
+
+#define FREED(eed) \
+   if (eed) \
+   { \
+      eet_data_descriptor_free((eed)); \
+      (eed) = NULL; \
+   }
+
+void
+_edje_edd_shutdown(void)
+{
+   FREED(_edje_edd_edje_file);
+   FREED(_edje_edd_edje_style);
+   FREED(_edje_edd_edje_style_tag);
+   FREED(_edje_edd_edje_color_class);
+   FREED(_edje_edd_edje_data);
+   FREED(_edje_edd_edje_external_directory);
+   FREED(_edje_edd_edje_external_directory_entry);
+   FREED(_edje_edd_edje_font_directory);
+   FREED(_edje_edd_edje_font_directory_entry);
+   FREED(_edje_edd_edje_image_directory);
+   FREED(_edje_edd_edje_image_directory_entry);
+   FREED(_edje_edd_edje_spectrum_directory);
+   FREED(_edje_edd_edje_spectrum_directory_entry);
+   FREED(_edje_edd_edje_spectrum_color);
+   FREED(_edje_edd_edje_program);
+   FREED(_edje_edd_edje_program_target);
+   FREED(_edje_edd_edje_program_after);
+   FREED(_edje_edd_edje_part_collection_directory);
+   FREED(_edje_edd_edje_part_collection_directory_entry);
+   FREED(_edje_edd_edje_pack_element);
+   FREED(_edje_edd_edje_part_collection);
+   FREED(_edje_edd_edje_part);
+   FREED(_edje_edd_edje_part_description);
+   FREED(_edje_edd_edje_part_image_id);
+   FREED(_edje_edd_edje_external_param);
+}
+
+void
+_edje_edd_init(void)
+{
+   Eet_Data_Descriptor_Class eddc;
+
+   /* external directory */
+   EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Edje_External_Directory_Entry);
+   _edje_edd_edje_external_directory_entry =
+     eet_data_descriptor_file_new(&eddc);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_external_directory_entry, Edje_External_Directory_Entry, "entry", entry, EET_T_STRING);
+
+   EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Edje_External_Directory);
+   _edje_edd_edje_external_directory =
+     eet_data_descriptor_file_new(&eddc);
+   EET_DATA_DESCRIPTOR_ADD_LIST(_edje_edd_edje_external_directory, Edje_External_Directory, "entries", entries, _edje_edd_edje_external_directory_entry);
+
+   /* font directory */
+   EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Edje_Font_Directory_Entry);
+   _edje_edd_edje_font_directory_entry =
+     eet_data_descriptor_file_new(&eddc);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_font_directory_entry, Edje_Font_Directory_Entry, "entry", entry, EET_T_STRING);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_font_directory_entry, Edje_Font_Directory_Entry, "file", file, EET_T_STRING);
+
+   EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Edje_Font_Directory);
+   _edje_edd_edje_font_directory =
+     eet_data_descriptor_file_new(&eddc);
+   EET_DATA_DESCRIPTOR_ADD_LIST(_edje_edd_edje_font_directory, Edje_Font_Directory, "entries", entries, _edje_edd_edje_font_directory_entry);
+
+   /* image directory */
+   EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Edje_Image_Directory_Entry);
+   _edje_edd_edje_image_directory_entry =
+     eet_data_descriptor_file_new(&eddc);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_image_directory_entry, Edje_Image_Directory_Entry, "entry", entry, EET_T_STRING);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_image_directory_entry, Edje_Image_Directory_Entry, "source_type", source_type, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_image_directory_entry, Edje_Image_Directory_Entry, "source_param", source_param, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_image_directory_entry, Edje_Image_Directory_Entry, "id", id, EET_T_INT);
+
+   EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Edje_Image_Directory);
+   _edje_edd_edje_image_directory =
+     eet_data_descriptor_file_new(&eddc);
+   EET_DATA_DESCRIPTOR_ADD_LIST(_edje_edd_edje_image_directory, Edje_Image_Directory, "entries", entries, _edje_edd_edje_image_directory_entry);
+
+   /* spectrum directory */
+   EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Edje_Spectrum_Color);
+   _edje_edd_edje_spectrum_color =
+     eet_data_descriptor_file_new(&eddc);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_spectrum_color, Edje_Spectrum_Color, "r", r, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_spectrum_color, Edje_Spectrum_Color, "g", g, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_spectrum_color, Edje_Spectrum_Color, "b", b, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_spectrum_color, Edje_Spectrum_Color, "a", a, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_spectrum_color, Edje_Spectrum_Color, "d", d, EET_T_INT);
+
+   EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Edje_Spectrum_Directory_Entry);
+   _edje_edd_edje_spectrum_directory_entry =
+     eet_data_descriptor_file_new(&eddc);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_spectrum_directory_entry, Edje_Spectrum_Directory_Entry, "entry", entry, EET_T_STRING);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_spectrum_directory_entry, Edje_Spectrum_Directory_Entry, "filename", filename, EET_T_STRING);
+   EET_DATA_DESCRIPTOR_ADD_LIST(_edje_edd_edje_spectrum_directory_entry, Edje_Spectrum_Directory_Entry, "color_list", color_list, _edje_edd_edje_spectrum_color);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_spectrum_directory_entry, Edje_Spectrum_Directory_Entry, "id", id, EET_T_INT);
+
+   EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Edje_Spectrum_Directory);
+   _edje_edd_edje_spectrum_directory =
+     eet_data_descriptor_file_new(&eddc);
+   EET_DATA_DESCRIPTOR_ADD_LIST(_edje_edd_edje_spectrum_directory, Edje_Spectrum_Directory, "entries", entries, _edje_edd_edje_spectrum_directory_entry);
+
+   /* collection directory */
+   EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Edje_Part_Collection_Directory_Entry);
+   _edje_edd_edje_part_collection_directory_entry =
+     eet_data_descriptor_file_new(&eddc);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_collection_directory_entry, Edje_Part_Collection_Directory_Entry, "entry", entry, EET_T_STRING);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_collection_directory_entry, Edje_Part_Collection_Directory_Entry, "id", id, EET_T_INT);
+
+   EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Edje_Part_Collection_Directory);
+   _edje_edd_edje_part_collection_directory =
+     eet_data_descriptor_file_new(&eddc);
+   EET_DATA_DESCRIPTOR_ADD_LIST(_edje_edd_edje_part_collection_directory, Edje_Part_Collection_Directory, "entries", entries, _edje_edd_edje_part_collection_directory_entry);
+
+   /* generic data attachment */
+   EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Edje_Data);
+   _edje_edd_edje_data =
+     eet_data_descriptor_file_new(&eddc);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_data, Edje_Data, "key", key, EET_T_STRING);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_data, Edje_Data, "value", value, EET_T_STRING);
+
+   EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Edje_Style_Tag);
+   _edje_edd_edje_style_tag =
+     eet_data_descriptor_file_new(&eddc);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_style_tag, Edje_Style_Tag, "key", key, EET_T_STRING);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_style_tag, Edje_Style_Tag, "value", value, EET_T_STRING);
+
+   EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Edje_Style);
+   _edje_edd_edje_style =
+     eet_data_descriptor_file_new(&eddc);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_style, Edje_Style, "name", name, EET_T_STRING);
+   EET_DATA_DESCRIPTOR_ADD_LIST(_edje_edd_edje_style, Edje_Style, "tags", tags, _edje_edd_edje_style_tag);
+
+   EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Edje_Color_Class);
+   _edje_edd_edje_color_class =
+     eet_data_descriptor_file_new(&eddc);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_color_class, Edje_Color_Class, "name", name, EET_T_STRING);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_color_class, Edje_Color_Class, "r", r, EET_T_UCHAR);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_color_class, Edje_Color_Class, "g", g, EET_T_UCHAR);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_color_class, Edje_Color_Class, "b", b, EET_T_UCHAR);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_color_class, Edje_Color_Class, "a", a, EET_T_UCHAR);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_color_class, Edje_Color_Class, "r2", r2, EET_T_UCHAR);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_color_class, Edje_Color_Class, "g2", g2, EET_T_UCHAR);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_color_class, Edje_Color_Class, "b2", b2, EET_T_UCHAR);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_color_class, Edje_Color_Class, "a2", a2, EET_T_UCHAR);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_color_class, Edje_Color_Class, "r3", r3, EET_T_UCHAR);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_color_class, Edje_Color_Class, "g3", g3, EET_T_UCHAR);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_color_class, Edje_Color_Class, "b3", b3, EET_T_UCHAR);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_color_class, Edje_Color_Class, "a3", a3, EET_T_UCHAR);
+
+   /* the main file directory */
+   EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Edje_File);
+   _edje_edd_edje_file =
+     eet_data_descriptor_file_new(&eddc);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_file, Edje_File, "compiler", compiler, EET_T_STRING);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_file, Edje_File, "version", version, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_file, Edje_File, "feature_ver", feature_ver, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_SUB(_edje_edd_edje_file, Edje_File, "external_dir", external_dir, _edje_edd_edje_external_directory);
+   EET_DATA_DESCRIPTOR_ADD_SUB(_edje_edd_edje_file, Edje_File, "font_dir", font_dir, _edje_edd_edje_font_directory);
+   EET_DATA_DESCRIPTOR_ADD_SUB(_edje_edd_edje_file, Edje_File, "image_dir", image_dir, _edje_edd_edje_image_directory);
+   EET_DATA_DESCRIPTOR_ADD_SUB(_edje_edd_edje_file, Edje_File, "spectrum_dir", spectrum_dir, _edje_edd_edje_spectrum_directory);
+   EET_DATA_DESCRIPTOR_ADD_SUB(_edje_edd_edje_file, Edje_File, "collection_dir", collection_dir, _edje_edd_edje_part_collection_directory);
+   EET_DATA_DESCRIPTOR_ADD_LIST(_edje_edd_edje_file, Edje_File, "data", data, _edje_edd_edje_data);
+   EET_DATA_DESCRIPTOR_ADD_LIST(_edje_edd_edje_file, Edje_File, "styles", styles, _edje_edd_edje_style);
+   EET_DATA_DESCRIPTOR_ADD_LIST(_edje_edd_edje_file, Edje_File, "color_classes", color_classes, _edje_edd_edje_color_class);
+
+   /* parts & programs - loaded induvidually */
+   EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Edje_Program_Target);
+   _edje_edd_edje_program_target =
+     eet_data_descriptor_file_new(&eddc);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_program_target, Edje_Program_Target, "id", id, EET_T_INT);
+
+   EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Edje_Program_After);
+   _edje_edd_edje_program_after =
+     eet_data_descriptor_file_new(&eddc);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_program_after,
+                                 Edje_Program_After, "id", id, EET_T_INT);
+
+   EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Edje_Program);
+   _edje_edd_edje_program =
+     eet_data_descriptor_file_new(&eddc);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_program, Edje_Program, "id", id, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_program, Edje_Program, "name", name, EET_T_STRING);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_program, Edje_Program, "signal", signal, EET_T_STRING);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_program, Edje_Program, "source", source, EET_T_STRING);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_program, Edje_Program, "filter_part", filter.part, EET_T_STRING);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_program, Edje_Program, "filter_state", filter.state, EET_T_STRING);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_program, Edje_Program, "in.from", in.from, EET_T_DOUBLE);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_program, Edje_Program, "in.range", in.range, EET_T_DOUBLE);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_program, Edje_Program, "action", action, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_program, Edje_Program, "state", state, EET_T_STRING);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_program, Edje_Program, "state2", state2, EET_T_STRING);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_program, Edje_Program, "value", value, EET_T_DOUBLE);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_program, Edje_Program, "value2", value2, EET_T_DOUBLE);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_program, Edje_Program, "tween.mode", tween.mode, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_program, Edje_Program, "tween.time", tween.time, EDJE_T_FLOAT);
+   EET_DATA_DESCRIPTOR_ADD_LIST(_edje_edd_edje_program, Edje_Program, "targets", targets, _edje_edd_edje_program_target);
+   EET_DATA_DESCRIPTOR_ADD_LIST(_edje_edd_edje_program, Edje_Program, "after", after, _edje_edd_edje_program_after);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_program, Edje_Program, "api.name", api.name, EET_T_STRING);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_program, Edje_Program, "api.description", api.description, EET_T_STRING);
+
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_program, Edje_Program, "param.src", param.src, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_program, Edje_Program, "param.dst", param.dst, EET_T_INT);
+
+   EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Edje_Part_Image_Id);
+   _edje_edd_edje_part_image_id =
+     eet_data_descriptor_file_new(&eddc);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_image_id, Edje_Part_Image_Id, "id", id, EET_T_INT);
+
+   EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Edje_External_Param);
+   _edje_edd_edje_external_param =
+     eet_data_descriptor_file_new(&eddc);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_external_param, Edje_External_Param, "name", name, EET_T_STRING);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_external_param, Edje_External_Param, "type", type, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_external_param, Edje_External_Param, "i", i, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_external_param, Edje_External_Param, "d", d, EET_T_DOUBLE);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_external_param, Edje_External_Param, "s", s, EET_T_STRING);
+
+   EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Edje_Part_Description);
+   _edje_edd_edje_part_description =
+     eet_data_descriptor_file_new(&eddc);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "state.name", state.name, EET_T_STRING);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "state.value", state.value, EET_T_DOUBLE);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "visible", visible, EET_T_CHAR);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "align.x", align.x, EDJE_T_FLOAT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "align.y", align.y, EDJE_T_FLOAT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "fixed.w", fixed.w, EET_T_UCHAR);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "fixed.h", fixed.h, EET_T_UCHAR);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "min.w", min.w, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "min.h", min.h, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "max.w", max.w, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "max.h", max.h, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "step.x", step.x, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "step.y", step.y, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "aspect.min", aspect.min, EDJE_T_FLOAT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "aspect.max", aspect.max, EDJE_T_FLOAT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "aspect.prefer", aspect.prefer, EET_T_CHAR);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "rel1.relative_x", rel1.relative_x, EDJE_T_FLOAT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "rel1.relative_y", rel1.relative_y, EDJE_T_FLOAT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "rel1.offset_x", rel1.offset_x, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "rel1.offset_y", rel1.offset_y, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "rel1.id_x", rel1.id_x, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "rel1.id_y", rel1.id_y, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "rel2.relative_x", rel2.relative_x, EDJE_T_FLOAT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "rel2.relative_y", rel2.relative_y, EDJE_T_FLOAT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "rel2.offset_x", rel2.offset_x, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "rel2.offset_y", rel2.offset_y, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "rel2.id_x", rel2.id_x, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "rel2.id_y", rel2.id_y, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "image.id", image.id, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_LIST(_edje_edd_edje_part_description, Edje_Part_Description, "image.tween_list", image.tween_list, _edje_edd_edje_part_image_id);
+
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "border.l", border.l, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "border.r", border.r, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "border.t", border.t, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "border.b", border.b, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "border.no_fill", border.no_fill, EET_T_UCHAR);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "border.scale", border.scale, EET_T_UCHAR);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "fill.smooth", fill.smooth, EET_T_CHAR);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "fill.pos_rel_x", fill.pos_rel_x, EDJE_T_FLOAT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "fill.pos_abs_x", fill.pos_abs_x, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "fill.rel_x", fill.rel_x, EDJE_T_FLOAT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "fill.abs_x", fill.abs_x, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "fill.pos_rel_y", fill.pos_rel_y, EDJE_T_FLOAT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "fill.pos_abs_y", fill.pos_abs_y, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "fill.rel_y", fill.rel_y, EDJE_T_FLOAT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "fill.abs_y", fill.abs_y, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "fill.angle", fill.angle, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "fill.spread", fill.spread, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "fill.type", fill.type, EET_T_CHAR);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "color_class", color_class, EET_T_STRING);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "color.r", color.r, EET_T_UCHAR);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "color.g", color.g, EET_T_UCHAR);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "color.b", color.b, EET_T_UCHAR);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "color.a", color.a, EET_T_UCHAR);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "color2.r", color2.r, EET_T_UCHAR);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "color2.g", color2.g, EET_T_UCHAR);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "color2.b", color2.b, EET_T_UCHAR);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "color2.a", color2.a, EET_T_UCHAR);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "color3.r", color3.r, EET_T_UCHAR);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "color3.g", color3.g, EET_T_UCHAR);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "color3.b", color3.b, EET_T_UCHAR);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "color3.a", color3.a, EET_T_UCHAR);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "text.text", text.text, EET_T_STRING);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "text.text_class", text.text_class, EET_T_STRING);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "text.style", text.style, EET_T_STRING);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "text.font", text.font, EET_T_STRING);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "text.repch", text.repch, EET_T_STRING);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "text.size", text.size, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "text.fit_x", text.fit_x, EET_T_UCHAR);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "text.fit_y", text.fit_y, EET_T_UCHAR);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "text.min_x", text.min_x, EET_T_UCHAR);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "text.min_y", text.min_y, EET_T_UCHAR);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "text.max_x", text.max_x, EET_T_UCHAR);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "text.max_y", text.max_y, EET_T_UCHAR);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "text.align.x", text.align.x, EDJE_T_FLOAT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "text.align.y", text.align.y, EDJE_T_FLOAT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "text.id_source", text.id_source, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "text.id_text_source", text.id_text_source, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "text.elipsis", text.elipsis, EET_T_DOUBLE);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "gradient.id", gradient.id, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "gradient.type", gradient.type, EET_T_STRING);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "gradient.use_rel", gradient.use_rel, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "gradient.rel1.relative_x", gradient.rel1.relative_x, EDJE_T_FLOAT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "gradient.rel1.relative_y", gradient.rel1.relative_y, EDJE_T_FLOAT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "gradient.rel1.offset_x", gradient.rel1.offset_x, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "gradient.rel1.offset_y", gradient.rel1.offset_y, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "gradient.rel2.relative_x", gradient.rel2.relative_x, EDJE_T_FLOAT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "gradient.rel2.relative_y", gradient.rel2.relative_y, EDJE_T_FLOAT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "gradient.rel2.offset_x", gradient.rel2.offset_x, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "gradient.rel2.offset_y", gradient.rel2.offset_y, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "box.layout", box.layout, EET_T_STRING);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "box.alt_layout", box.alt_layout, EET_T_STRING);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "box.align.x", box.align.x, EDJE_T_FLOAT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "box.align.y", box.align.y, EDJE_T_FLOAT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "box.padding.x", box.padding.x, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "box.padding.y", box.padding.y, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "box.min.h", box.min.h, EET_T_UCHAR);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "box.min.v", box.min.v, EET_T_UCHAR);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "table.homogeneous", table.homogeneous, EET_T_UCHAR);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "table.align.x", table.align.x, EDJE_T_FLOAT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "table.align.y", table.align.y, EDJE_T_FLOAT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "table.padding.x", table.padding.x, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "table.padding.y", table.padding.y, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "map.id_persp", map.id_persp, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "map.id_light", map.id_light, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "map.rot.id_center", map.rot.id_center, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "map.rot.x", map.rot.x, EDJE_T_FLOAT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "map.rot.y", map.rot.y, EDJE_T_FLOAT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "map.rot.z", map.rot.z, EDJE_T_FLOAT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "map.on", map.on, EET_T_UCHAR);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "map.smooth", map.smooth, EET_T_UCHAR);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "map.alpha", map.alpha, EET_T_UCHAR);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "map.persp_on", map.persp_on, EET_T_UCHAR);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "map.backcull", map.backcull, EET_T_UCHAR);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "persp.zplane", persp.zplane, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_description, Edje_Part_Description, "persp.focal", persp.focal, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_LIST(_edje_edd_edje_part_description, Edje_Part_Description, "external_params", external_params, _edje_edd_edje_external_param);
+
+   EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Edje_Pack_Element);
+   _edje_edd_edje_pack_element =
+      eet_data_descriptor_file_new(&eddc);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_pack_element, Edje_Pack_Element, "type", type, EET_T_UCHAR);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_pack_element, Edje_Pack_Element, "name", name, EET_T_STRING);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_pack_element, Edje_Pack_Element, "source", source, EET_T_STRING);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_pack_element, Edje_Pack_Element, "min.w", min.w, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_pack_element, Edje_Pack_Element, "min.h", min.h, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_pack_element, Edje_Pack_Element, "prefer.w", prefer.w, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_pack_element, Edje_Pack_Element, "prefer.h", prefer.h, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_pack_element, Edje_Pack_Element, "max.w", max.w, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_pack_element, Edje_Pack_Element, "max.h", max.h, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_pack_element, Edje_Pack_Element, "padding.l", padding.l, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_pack_element, Edje_Pack_Element, "padding.r", padding.r, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_pack_element, Edje_Pack_Element, "padding.t", padding.t, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_pack_element, Edje_Pack_Element, "padding.b", padding.b, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_pack_element, Edje_Pack_Element, "align.x", align.x, EDJE_T_FLOAT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_pack_element, Edje_Pack_Element, "align.y", align.y, EDJE_T_FLOAT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_pack_element, Edje_Pack_Element, "weight.x", weight.x, EDJE_T_FLOAT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_pack_element, Edje_Pack_Element, "weight.y", weight.y, EDJE_T_FLOAT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_pack_element, Edje_Pack_Element, "aspect.w", aspect.w, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_pack_element, Edje_Pack_Element, "aspect.h", aspect.h, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_pack_element, Edje_Pack_Element, "aspect.mode", aspect.mode, EET_T_UCHAR);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_pack_element, Edje_Pack_Element, "options", options, EET_T_STRING);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_pack_element, Edje_Pack_Element, "col", col, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_pack_element, Edje_Pack_Element, "row", row, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_pack_element, Edje_Pack_Element, "colspan", colspan, EET_T_USHORT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_pack_element, Edje_Pack_Element, "rowspan", rowspan, EET_T_USHORT);
+
+   EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Edje_Part);
+   _edje_edd_edje_part =
+     eet_data_descriptor_file_new(&eddc);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part, Edje_Part, "name", name, EET_T_STRING);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part, Edje_Part, "id", id, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part, Edje_Part, "type", type, EET_T_UCHAR);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part, Edje_Part, "effect", effect, EET_T_UCHAR);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part, Edje_Part, "mouse_events", mouse_events, EET_T_UCHAR);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part, Edje_Part, "repeat_events", repeat_events, EET_T_UCHAR);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part, Edje_Part, "ignore_flags", ignore_flags, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part, Edje_Part, "scale", scale, EET_T_UCHAR);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part, Edje_Part, "pointer_mode", pointer_mode, EET_T_UCHAR);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part, Edje_Part, "precise_is_inside", precise_is_inside, EET_T_UCHAR);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part, Edje_Part, "clip_to_id", clip_to_id, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part, Edje_Part, "use_alternate_font_metrics", use_alternate_font_metrics, EET_T_UCHAR);
+   EET_DATA_DESCRIPTOR_ADD_SUB(_edje_edd_edje_part, Edje_Part, "default_desc", default_desc, _edje_edd_edje_part_description);
+   EET_DATA_DESCRIPTOR_ADD_LIST(_edje_edd_edje_part, Edje_Part, "other_desc", other_desc, _edje_edd_edje_part_description);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part, Edje_Part, "dragable.x", dragable.x, EET_T_CHAR);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part, Edje_Part, "dragable.step_x", dragable.step_x, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part, Edje_Part, "dragable.count_x", dragable.count_x, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part, Edje_Part, "dragable.y", dragable.y, EET_T_CHAR);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part, Edje_Part, "dragable.step_y", dragable.step_y, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part, Edje_Part, "dragable.count_y", dragable.count_y, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part, Edje_Part, "dragable.counfine_id", dragable.confine_id, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part, Edje_Part, "dragable.events_id", dragable.events_id, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part, Edje_Part, "entry_mode", entry_mode, EET_T_UCHAR);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part, Edje_Part, "select_mode", select_mode, EET_T_UCHAR);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part, Edje_Part, "multiline", multiline, EET_T_UCHAR);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part, Edje_Part, "source", source, EET_T_STRING);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part, Edje_Part, "source2", source2, EET_T_STRING);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part, Edje_Part, "source3", source3, EET_T_STRING);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part, Edje_Part, "source4", source4, EET_T_STRING);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part, Edje_Part, "source5", source5, EET_T_STRING);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part, Edje_Part, "source6", source6, EET_T_STRING);
+   EET_DATA_DESCRIPTOR_ADD_LIST(_edje_edd_edje_part, Edje_Part, "items", items, _edje_edd_edje_pack_element);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part, Edje_Part, "api.name", api.name, EET_T_STRING);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part, Edje_Part, "api.description", api.description, EET_T_STRING);
+
+   EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Edje_Part_Collection);
+   _edje_edd_edje_part_collection  =
+     eet_data_descriptor_file_new(&eddc);
+   EET_DATA_DESCRIPTOR_ADD_LIST(_edje_edd_edje_part_collection, Edje_Part_Collection, "programs", programs, _edje_edd_edje_program);
+   EET_DATA_DESCRIPTOR_ADD_LIST(_edje_edd_edje_part_collection, Edje_Part_Collection, "parts", parts, _edje_edd_edje_part);
+   EET_DATA_DESCRIPTOR_ADD_LIST(_edje_edd_edje_part_collection, Edje_Part_Collection, "data", data, _edje_edd_edje_data);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_collection, Edje_Part_Collection, "prop.min.w", prop.min.w, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_collection, Edje_Part_Collection, "prop.min.h", prop.min.h, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_collection, Edje_Part_Collection, "prop.max.w", prop.max.w, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_collection, Edje_Part_Collection, "prop.max.h", prop.max.h, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_collection, Edje_Part_Collection, "id", id, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_collection, Edje_Part_Collection, "script_only", script_only, EET_T_UCHAR);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_edje_edd_edje_part_collection, Edje_Part_Collection, "lua_script_only", lua_script_only, EET_T_UCHAR);
+}
diff --git a/src/lib/edje_edit.c b/src/lib/edje_edit.c
new file mode 100644 (file)
index 0000000..90e4e65
--- /dev/null
@@ -0,0 +1,7165 @@
+/*
+ * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
+ */
+
+/*
+ * TODO
+ * -----------------------------------------------------------------
+ * Add LUA Support :)
+ * Remove images/fonts
+ * Clean the saving routines
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <string.h>
+#include <limits.h>
+#include <sys/stat.h>
+#include <errno.h>
+
+#ifndef _MSC_VER
+# include <unistd.h>
+#endif
+
+#ifdef HAVE_LOCALE_H
+# include <locale.h>
+#endif
+
+#ifdef HAVE_EVIL
+# include <Evil.h>
+#endif
+
+#include "edje_private.h"
+
+
+/* Get ed(Edje*) from obj(Evas_Object*) */
+#define GET_ED_OR_RETURN(RET) \
+   Edje *ed; \
+   Edje_Edit *eed; \
+   if (!evas_object_smart_type_check_ptr(obj, _edje_edit_type)) \
+     return RET; \
+   eed = evas_object_smart_data_get(obj); \
+   if (!eed) return RET; \
+   ed = (Edje *)eed;
+
+/* Get rp(Edje_Real_Part*) from obj(Evas_Object*) and part(char*) */
+#define GET_RP_OR_RETURN(RET) \
+   Edje *ed; \
+   Edje_Edit *eed; \
+   Edje_Real_Part *rp; \
+   if (!evas_object_smart_type_check_ptr(obj, _edje_edit_type)) \
+     return RET; \
+   eed = evas_object_smart_data_get(obj); \
+   if (!eed) return RET; \
+   ed = (Edje *)eed; \
+   rp = _edje_real_part_get(ed, part); \
+   if (!rp) return RET;
+
+/* Get pd(Edje_Part_Description*) from obj(Evas_Object*), part(char*) and state (char*) */
+#define GET_PD_OR_RETURN(RET) \
+   Edje *ed; \
+   Edje_Edit *eed; \
+   Edje_Part_Description *pd; \
+   if (!evas_object_smart_type_check_ptr(obj, _edje_edit_type)) \
+     return RET; \
+   eed = evas_object_smart_data_get(obj); \
+   if (!eed) return RET; \
+   ed = (Edje *)eed; \
+   pd = _edje_part_description_find_byname(eed, part, state, value); \
+   if (!pd) return RET;
+
+/* Get epr(Edje_Program*) from obj(Evas_Object*) and prog(char*)*/
+#define GET_EPR_OR_RETURN(RET) \
+   Edje_Program *epr; \
+   if (!evas_object_smart_type_check_ptr(obj, _edje_edit_type)) \
+     return RET; \
+   epr = _edje_program_get_byname(obj, prog); \
+   if (!epr) return RET;
+
+static void *
+_alloc(size_t size)
+{
+   void *mem;
+
+   mem = calloc(1, size);
+   if (mem) return mem;
+   ERR("Edje_Edit: Error. memory allocation of %i bytes failed. %s",
+       (int)size, strerror(errno));
+   return NULL;
+}
+
+/*************/
+/* INTERNALS */
+/*************/
+
+/* Edje_Edit smart! Overloads the edje one adding some more control stuff */
+static const char _edje_edit_type[] = "edje_edit";
+
+typedef struct _Edje_Edit Edje_Edit;
+struct _Edje_Edit
+{
+   Edje base;
+};
+
+static void _edje_edit_smart_add(Evas_Object *obj);
+static void _edje_edit_smart_del(Evas_Object *obj);
+
+static Eina_Bool _edje_edit_smart_file_set(Evas_Object *obj, const char *file, const char *group);
+static Eina_Bool _edje_edit_edje_file_save(Eet_File *eetf, Edje_File *ef);
+
+EVAS_SMART_SUBCLASS_NEW(_edje_edit_type, _edje_edit, Edje_Smart_Api,
+                       Edje_Smart_Api, _edje_object_smart_class_get, NULL)
+
+static void
+_edje_edit_smart_set_user(Edje_Smart_Api *sc)
+{
+   sc->base.add = _edje_edit_smart_add;
+   sc->base.del = _edje_edit_smart_del;
+   sc->file_set = _edje_edit_smart_file_set;
+}
+
+static void
+_edje_edit_smart_add(Evas_Object *obj)
+{
+   Edje_Edit *eed;
+
+   eed = evas_object_smart_data_get(obj);
+   if (!eed)
+     {
+       const Evas_Smart *smart;
+       const Evas_Smart_Class *sc;
+
+       eed = calloc(1, sizeof(Edje_Edit));
+       if (!eed) return;
+
+       smart = evas_object_smart_smart_get(obj);
+       sc = evas_smart_class_get(smart);
+       eed->base.api = (const Edje_Smart_Api *)sc;
+
+       evas_object_smart_data_set(obj, eed);
+     }
+
+   _edje_edit_parent_sc->base.add(obj);
+}
+
+static void
+_edje_edit_smart_del(Evas_Object *obj)
+{
+   Edje_Edit *eed;
+
+   eed = evas_object_smart_data_get(obj);
+   _edje_edit_parent_sc->base.del(obj);
+}
+
+static Eina_Bool
+_edje_edit_smart_file_set(Evas_Object *obj, const char *file, const char *group)
+{
+   Edje_Edit *eed;
+
+   eed = evas_object_smart_data_get(obj);
+   /* Nothing custom here yet, so we just call the parent function.
+    * TODO and maybes:
+    *  * The whole point of this thing is keep track of stuff such as
+    *    strings to free and who knows what, so we need to take care
+    *    of those if the file/group changes.
+    *  * Maybe have the possibility to open just files, not always with
+    *    a group given.
+    *  * A way to skip the cache? Could help avoid some issues when editing
+    *    a group being used by the application in some other way, or multiple
+    *    opens of the same file.
+    *  * Here we probably want to allow opening groups with broken references
+    *    (GROUP parts or BOX/TABLE items pointing to non-existant/renamed
+    *    groups).
+    */
+   return _edje_edit_parent_sc->file_set(obj, file, group);
+}
+
+EAPI Evas_Object *
+edje_edit_object_add(Evas *e)
+{
+   return evas_object_smart_add(e, _edje_edit_smart_class_new());
+}
+/* End of Edje_Edit smart stuff */
+
+
+
+
+
+static Edje_Part_Description *
+_edje_part_description_find_byname(Edje_Edit *eed, const char *part, const char *state, double value)
+{
+   Edje_Real_Part *rp;
+   Edje_Part_Description *pd;
+
+   if (!eed || !part || !state) return NULL;
+
+   rp = _edje_real_part_get((Edje *)eed, part);
+   if (!rp) return NULL;
+
+   pd = _edje_part_description_find((Edje *)eed, rp, state, value);
+
+   return pd;
+}
+
+static int
+_edje_image_id_find(Evas_Object *obj, const char *image_name)
+{
+   Edje_Image_Directory_Entry *i;
+   Eina_List *l;
+
+   GET_ED_OR_RETURN(-1);
+
+   if (!ed->file) return -1;
+   if (!ed->file->image_dir) return -1;
+
+   //printf("SEARCH IMAGE %s\n", image_name);
+
+   EINA_LIST_FOREACH(ed->file->image_dir->entries, l, i)
+     {
+       if (strcmp(image_name, i->entry) == 0)
+         {
+            //printf("   Found id: %d \n", i->id);
+            return i->id;
+         }
+     }
+
+   return -1;
+}
+
+static const char *
+_edje_image_name_find(Evas_Object *obj, int image_id)
+{
+   Edje_Image_Directory_Entry *i;
+   Eina_List *l;
+
+   GET_ED_OR_RETURN(NULL);
+
+   if (!ed->file) return NULL;
+   if (!ed->file->image_dir) return NULL;
+
+   //printf("SEARCH IMAGE ID %d\n", image_id);
+
+   EINA_LIST_FOREACH(ed->file->image_dir->entries, l, i)
+     if (image_id == i->id)
+       return i->entry;
+
+   return NULL;
+}
+
+static void
+_edje_real_part_free(Edje_Real_Part *rp)
+{
+   if (!rp) return;
+
+   if (rp->object)
+     {
+       _edje_callbacks_del(rp->object, rp->edje);
+       evas_object_del(rp->object);
+     }
+
+   if (rp->swallowed_object)
+     {
+       evas_object_smart_member_del(rp->swallowed_object);
+       evas_object_event_callback_del(rp->swallowed_object,
+                                      EVAS_CALLBACK_FREE,
+                                      _edje_object_part_swallow_free_cb);
+       evas_object_clip_unset(rp->swallowed_object);
+       evas_object_data_del(rp->swallowed_object, "\377 edje.swallowing_part");
+       if (rp->part->mouse_events)
+         _edje_callbacks_del(rp->swallowed_object, rp->edje);
+
+       if (rp->part->type == EDJE_PART_TYPE_GROUP ||
+           rp->part->type == EDJE_PART_TYPE_EXTERNAL)
+         evas_object_del(rp->swallowed_object);
+
+       rp->swallowed_object = NULL;
+     }
+
+   if (rp->text.text) eina_stringshare_del(rp->text.text);
+   if (rp->text.font) eina_stringshare_del(rp->text.font);
+   if (rp->text.cache.in_str) eina_stringshare_del(rp->text.cache.in_str);
+   if (rp->text.cache.out_str) eina_stringshare_del(rp->text.cache.out_str);
+
+   if (rp->custom)
+     _edje_collection_free_part_description_free(rp->custom->description, 0);
+
+   free(rp->drag);
+   eina_mempool_free(_edje_real_part_state_mp, rp->param2);
+   eina_mempool_free(_edje_real_part_state_mp, rp->custom);
+
+   _edje_unref(rp->edje);
+   eina_mempool_free(_edje_real_part_mp, rp);
+}
+
+static Eina_Bool
+_edje_import_font_file(Edje *ed, const char *path, const char *entry)
+{
+   void *fdata = NULL;
+   long fsize = 0;
+
+   /* Read font data from file */
+   {
+      FILE *f = fopen(path, "rb");
+      if (!f)
+       {
+          ERR("Unable to open font file \"%s\"", path);
+          return EINA_FALSE;
+       }
+
+      fseek(f, 0, SEEK_END);
+      fsize = ftell(f);
+      rewind(f);
+      fdata = malloc(fsize);
+      if (!fdata)
+         {
+           ERR("Unable to alloc font file \"%s\"", path);
+           fclose(f);
+           return EINA_FALSE;
+         }
+      if (fread(fdata, fsize, 1, f) != 1)
+        {
+           ERR("Unable to read all of font file \"%s\"", path);
+           return EINA_FALSE;
+        }
+      fclose(f);
+   }
+
+   /* Write font to edje file */
+   {
+      /* open the eet file */
+      Eet_File *eetf = eet_open(ed->path, EET_FILE_MODE_READ_WRITE);
+      if (!eetf)
+       {
+          ERR("Unable to open \"%s\" for writing output", ed->path);
+          free(fdata);
+          return EINA_FALSE;
+       }
+
+      if (eet_write(eetf, entry, fdata, fsize, 1) <= 0)
+        {
+           ERR("Unable to write font part \"%s\" as \"%s\" part entry",
+              path, entry);
+           eet_close(eetf);
+           free(fdata);
+           return EINA_FALSE;
+        }
+
+      free(fdata);
+
+      /* write the edje_file */
+      if (!_edje_edit_edje_file_save(eetf, ed->file))
+       {
+          eet_delete(eetf, entry);
+          eet_close(eetf);
+          return EINA_FALSE;
+       }
+
+      eet_close(eetf);
+   }
+
+   return EINA_TRUE;
+}
+
+
+static Eina_Bool
+_edje_import_image_file(Edje *ed, const char *path, int id)
+{
+   char entry[PATH_MAX];
+   Evas_Object *im;
+   Eet_File *eetf;
+   void *im_data;
+   int  im_w, im_h;
+   int  im_alpha;
+   int bytes;
+
+   /* Try to load the file */
+   im = evas_object_image_add(ed->evas);
+   if (!im) return EINA_FALSE;
+
+   evas_object_image_file_set(im, path, NULL);
+   if (evas_object_image_load_error_get(im) != EVAS_LOAD_ERROR_NONE)
+     {
+        ERR("Edje_Edit: unable to load image \"%s\"."
+           "Missing PNG or JPEG loader modules for Evas or "
+           "file does not exist, or is not readable.", path);
+        evas_object_del(im);
+       im = NULL;
+       return EINA_FALSE;
+     }
+
+   /* Write the loaded image to the edje file */
+
+   evas_object_image_size_get(im, &im_w, &im_h);
+   im_alpha = evas_object_image_alpha_get(im);
+   im_data = evas_object_image_data_get(im, 0);
+   if ((!im_data) || !(im_w > 0) || !(im_h > 0))
+     {
+       evas_object_del(im);
+       return EINA_FALSE;
+     }
+
+   /* open the eet file */
+   eetf = eet_open(ed->path, EET_FILE_MODE_READ_WRITE);
+   if (!eetf)
+     {
+       ERR("Unable to open \"%s\" for writing output", ed->path);
+       evas_object_del(im);
+       return EINA_FALSE;
+     }
+
+   snprintf(entry, sizeof(entry), "images/%i", id);
+
+   /* write the image data */
+   bytes = eet_data_image_write(eetf, entry,
+                               im_data, im_w, im_h,
+                               im_alpha,
+                               0, 100, 1);
+   if (bytes <= 0)
+     {
+       ERR("Unable to write image part \"%s\" part entry to %s",
+           entry, ed->path);
+       eet_close(eetf);
+       evas_object_del(im);
+       return EINA_FALSE;
+     }
+
+   evas_object_del(im);
+
+   /* write the edje_file */
+   if (!_edje_edit_edje_file_save(eetf, ed->file))
+     {
+       eet_delete(eetf, entry);
+       eet_close(eetf);
+       return EINA_FALSE;
+     }
+
+   eet_close(eetf);
+   return EINA_TRUE;
+}
+
+static int
+_edje_part_id_find(Edje *ed, const char *part)
+{
+   int id;
+
+   for (id = 0; id < ed->table_parts_size; id++)
+     {
+       Edje_Real_Part *rp = ed->table_parts[id];
+
+       if (!strcmp(rp->part->name, part))
+         return id;
+     }
+   return -1;
+}
+
+static void
+_edje_part_id_set(Edje *ed, Edje_Real_Part *rp, int new_id)
+{
+   /* This function change the id of a given real_part.
+    * All the depedency will be updated too.
+    * Also the table_parts is updated, and the current *rp in the table
+    * is lost.
+    * If new Id = -1 then all the depencies will be deleted
+    */
+   int old_id;
+   Edje_Part *part;
+   Eina_List *l, *ll, *l_next;
+   Edje_Part *p;
+   Edje_Program *epr;
+
+   part = rp->part;
+
+   if (!part) return;
+   //printf("CHANGE ID OF PART %s TO %d\n", part->name, new_id);
+
+   if (!ed || !part || new_id < -1) return;
+
+   if (part->id == new_id) return;
+
+   old_id = part->id;
+   part->id = new_id;
+
+   /* Fix all the dependecies in all parts... */
+   EINA_LIST_FOREACH(ed->collection->parts, l, p)
+     {
+       Edje_Part_Description *d;
+
+       //printf("   search id: %d in %s\n", old_id, p->name);
+       if (p->clip_to_id == old_id) p->clip_to_id = new_id;
+       if (p->dragable.confine_id == old_id) p->dragable.confine_id = new_id;
+
+       /* ...in default description */
+       d = p->default_desc;
+       //printf("      search in %s (%s)\n", p->name, d->state.name);
+       if (d->rel1.id_x == old_id) d->rel1.id_x = new_id;
+       if (d->rel1.id_y == old_id) d->rel1.id_y = new_id;
+       if (d->rel2.id_x == old_id) d->rel2.id_x = new_id;
+       if (d->rel2.id_y == old_id) d->rel2.id_y = new_id;
+       if (d->text.id_source == old_id) d->text.id_source = new_id;
+       if (d->text.id_text_source == old_id) d->text.id_text_source = new_id;
+       /* ...and in all other descriptions */
+       EINA_LIST_FOREACH(p->other_desc, ll, d)
+         {
+            //printf("      search in %s (%s)\n", p->name, d->state.name);
+            if (d->rel1.id_x == old_id) d->rel1.id_x = new_id;
+            if (d->rel1.id_y == old_id) d->rel1.id_y = new_id;
+            if (d->rel2.id_x == old_id) d->rel2.id_x = new_id;
+            if (d->rel2.id_y == old_id) d->rel2.id_y = new_id;
+            if (d->text.id_source == old_id) d->text.id_source = new_id;
+            if (d->text.id_text_source == old_id) d->text.id_text_source = new_id;
+         }
+     }
+
+   /*...and also in programs targets */
+   EINA_LIST_FOREACH(ed->collection->programs, l, epr)
+     {
+       Edje_Program_Target *pt;
+
+       if (epr->action != EDJE_ACTION_TYPE_STATE_SET)
+         continue;
+
+       EINA_LIST_FOREACH_SAFE(epr->targets, ll, l_next, pt)
+         {
+            if (pt->id == old_id)
+              {
+                 if (new_id == -1)
+                   epr->targets = eina_list_remove_list(epr->targets, ll);
+                 else
+                   pt->id = new_id;
+              }
+         }
+     }
+
+   /* Adjust table_parts */
+   if (new_id >= 0)
+     ed->table_parts[new_id] = rp;
+}
+
+static void
+_edje_parts_id_switch(Edje *ed, Edje_Real_Part *rp1, Edje_Real_Part *rp2)
+{
+   /* This function switch the id of two parts.
+    * All the depedency will be updated too.
+    * Also the table_parts is updated,
+    * The parts list isn't touched
+    */
+   int id1;
+   int id2;
+   Eina_List *l, *ll;
+   Edje_Part *p;
+   Edje_Program *epr;
+
+   //printf("SWITCH ID OF PART %d AND %d\n", rp1->part->id, rp2->part->id);
+
+   if (!ed || !rp1 || !rp2) return;
+   if (rp1 == rp2) return;
+
+   id1 = rp1->part->id;
+   id2 = rp2->part->id;
+
+   /* Switch ids */
+   rp1->part->id = id2;
+   rp2->part->id = id1;
+
+   /* adjust table_parts */
+   ed->table_parts[id1] = rp2;
+   ed->table_parts[id2] = rp1;
+
+   // Fix all the dependecies in all parts...
+   EINA_LIST_FOREACH(ed->collection->parts, l, p)
+     {
+       Eina_List *ll;
+       Edje_Part_Description *d;
+
+       //printf("   search id: %d in %s\n", old_id, p->name);
+       if (p->clip_to_id == id1) p->clip_to_id = id2;
+       else if (p->clip_to_id == id2) p->clip_to_id = id1;
+       if (p->dragable.confine_id == id1) p->dragable.confine_id = id2;
+       else if (p->dragable.confine_id == id2) p->dragable.confine_id = id1;
+
+       // ...in default description
+       d = p->default_desc;
+       // printf("      search in %s (%s)\n", p->name, d->state.name);
+       if (d->rel1.id_x == id1) d->rel1.id_x = id2;
+       else if (d->rel1.id_x == id2) d->rel1.id_x = id1;
+       if (d->rel1.id_y == id1) d->rel1.id_y = id2;
+       else if (d->rel1.id_y == id2) d->rel1.id_y = id1;
+       if (d->rel2.id_x == id1) d->rel2.id_x = id2;
+       else if (d->rel2.id_x == id2) d->rel2.id_x = id1;
+       if (d->rel2.id_y == id1) d->rel2.id_y = id2;
+       else if (d->rel2.id_y == id2) d->rel2.id_y = id1;
+       if (d->text.id_source == id1) d->text.id_source = id2;
+       else if (d->text.id_source == id2) d->text.id_source = id1;
+       if (d->text.id_text_source == id1) d->text.id_text_source = id2;
+       else if (d->text.id_text_source == id2) d->text.id_text_source = id2;
+       // ...and in all other descriptions
+       EINA_LIST_FOREACH(p->other_desc, ll, d)
+         {
+            //printf("      search in %s (%s)\n", p->name, d->state.name);
+            if (d->rel1.id_x == id1) d->rel1.id_x = id2;
+            else if (d->rel1.id_x == id2) d->rel1.id_x = id1;
+            if (d->rel1.id_y == id1) d->rel1.id_y = id2;
+            else if (d->rel1.id_y == id2) d->rel1.id_y = id1;
+            if (d->rel2.id_x == id1) d->rel2.id_x = id2;
+            else if (d->rel2.id_x == id2) d->rel2.id_x = id1;
+            if (d->rel2.id_y == id1) d->rel2.id_y = id2;
+            else if (d->rel2.id_y == id2) d->rel2.id_y = id1;
+            if (d->text.id_source == id1) d->text.id_source = id2;
+            else if (d->text.id_source == id2) d->text.id_source = id1;
+            if (d->text.id_text_source == id1) d->text.id_text_source = id2;
+            else if (d->text.id_text_source == id2) d->text.id_text_source = id2;
+         }
+     }
+   //...and also in programs targets
+   EINA_LIST_FOREACH(ed->collection->programs, l, epr)
+     {
+        Edje_Program_Target *pt;
+
+       if (epr->action != EDJE_ACTION_TYPE_STATE_SET)
+         continue;
+
+       EINA_LIST_FOREACH(epr->targets, ll, pt)
+         {
+            if (pt->id == id1) pt->id = id2;
+            else if (pt->id == id2) pt->id = id1;
+         }
+     }
+   //TODO Real part dependencies are ok?
+}
+
+static void
+_edje_fix_parts_id(Edje *ed)
+{
+   /* We use this to clear the id hole leaved when a part is removed.
+    * After the execution of this function all parts will have a right
+    * (uniqe & ordered) id. The table_parts is also updated.
+    */
+   Eina_List *l;
+   Edje_Part *p;
+   int correct_id;
+   int count;
+
+   //printf("FIXING PARTS ID \n");
+
+   //TODO order the list first to be more robust
+
+   /* Give a correct id to all the parts */
+   correct_id = 0;
+   EINA_LIST_FOREACH(ed->collection->parts, l, p)
+     {
+       //printf(" [%d]Checking part: %s id: %d\n", correct_id, p->name, p->id);
+       if (p->id != correct_id)
+         _edje_part_id_set(ed, ed->table_parts[p->id], correct_id);
+
+       correct_id++;
+     }
+
+   /* If we have removed some parts realloc table_parts */
+   count = eina_list_count(ed->collection->parts);
+   if (count != ed->table_parts_size)
+     {
+       ed->table_parts = realloc(ed->table_parts, sizeof(Edje_Real_Part *) * count);
+       ed->table_parts_size = count;
+     }
+
+   //printf("\n");
+}
+
+static void
+_edje_if_string_free(Edje *ed, const char *str)
+{
+   Eet_Dictionary *dict;
+
+   if (!ed || !str) return;
+
+   dict = eet_dictionary_get(ed->file->ef);
+   if (eet_dictionary_string_check(dict, str)) return;
+   eina_stringshare_del(str);
+   str = NULL;
+}
+
+static Edje_Spectrum_Directory_Entry *
+_edje_edit_spectrum_entry_get(Edje *ed, const char* spectra)
+{
+   Edje_Spectrum_Directory_Entry *s;
+   Eina_List *l;
+
+   if (!ed->file || !spectra || !ed->file->spectrum_dir)
+      return NULL;
+
+   EINA_LIST_FOREACH(ed->file->spectrum_dir->entries, l, s)
+     if (!strcmp(s->entry, spectra))
+       return s;
+
+   return NULL;
+}
+
+static Edje_Spectrum_Directory_Entry *
+_edje_edit_spectrum_entry_get_by_id(Edje *ed, int spectra_id)
+{
+   Edje_Spectrum_Directory_Entry *s;
+   Eina_List *l;
+
+   if (!ed->file || !ed->file->spectrum_dir)
+      return NULL;
+
+   EINA_LIST_FOREACH(ed->file->spectrum_dir->entries, l, s)
+     if (s->id == spectra_id)
+       return s;
+
+   return NULL;
+}
+
+static Edje_Style *
+_edje_edit_style_get(Edje *ed, const char *name)
+{
+   Eina_List *l;
+   Edje_Style *s;
+
+   if (!ed || !ed->file || !ed->file->styles || !name)
+      return NULL;
+
+   EINA_LIST_FOREACH(ed->file->styles, l, s)
+      if (s->name && !strcmp(s->name, name))
+         return s;
+
+   return NULL;
+}
+
+static Edje_Style_Tag *
+_edje_edit_style_tag_get(Edje *ed, const char *style, const char *name)
+{
+   Eina_List *l;
+   Edje_Style *s;
+   Edje_Style_Tag *t;
+
+   if (!ed || !ed->file || !ed->file->styles || !name)
+      return NULL;
+
+   s = _edje_edit_style_get(ed, style);
+
+   EINA_LIST_FOREACH(s->tags, l, t)
+      if (t->key && !strcmp(t->key, name))
+         return t;
+
+   return NULL;
+}
+
+static Edje_External_Directory_Entry *
+_edje_edit_external_get(Edje *ed, const char *name)
+{
+   Eina_List *l;
+   Edje_External_Directory_Entry *e;
+
+   if (!ed || !ed->file || !ed->file->external_dir || !name)
+     return NULL;
+
+   EINA_LIST_FOREACH(ed->file->external_dir->entries, l, e)
+      if (e->entry && !strcmp(e->entry, name))
+       return e;
+
+   return NULL;
+}
+
+void
+_edje_edit_group_references_update(Evas_Object *obj, const char *old_group_name, const char *new_group_name)
+{
+
+   Eina_List *gl, *pll, *pl;
+   Edje_Part_Collection *pc;
+   Edje_Part_Collection_Directory_Entry *pce;
+   char *part_name;
+   const char *source, *old;
+   Edje_Part_Type type;
+   Evas_Object *part_obj;
+
+   GET_ED_OR_RETURN();
+
+   pc = ed->collection;
+
+   part_obj = edje_edit_object_add(ed->evas);
+
+   old = eina_stringshare_add(old_group_name);
+
+   EINA_LIST_FOREACH(ed->file->collection_dir->entries, gl, pce)
+     {
+       edje_object_file_set(part_obj, ed->file->path, pce->entry);
+
+       pl = edje_edit_parts_list_get(part_obj);
+
+       EINA_LIST_FOREACH(pl, pll, part_name)
+         {
+            source = edje_edit_part_source_get(part_obj, part_name);
+            type = edje_edit_part_type_get(part_obj, part_name);
+
+            if (type ==  EDJE_PART_TYPE_GROUP && source == old)
+              edje_edit_part_source_set(part_obj, part_name, new_group_name);
+
+            if (source)
+              eina_stringshare_del(source);
+         }
+     }
+   eina_stringshare_del(old);
+
+   evas_object_del(part_obj);
+}
+
+/*****************/
+/*  GENERAL API  */
+/*****************/
+
+EAPI void
+edje_edit_string_list_free(Eina_List *lst)
+{
+   //printf("FREE LIST: \n");
+   while (lst)
+     {
+        if (eina_list_data_get(lst)) eina_stringshare_del(eina_list_data_get(lst));
+       //printf("FREE: %s\n", eina_list_data_get(lst));
+       lst = eina_list_remove(lst, eina_list_data_get(lst));
+     }
+}
+
+EAPI void
+edje_edit_string_free(const char *str)
+{
+   if (str) eina_stringshare_del(str);
+}
+
+EAPI const char*
+edje_edit_compiler_get(Evas_Object *obj)
+{
+   GET_ED_OR_RETURN(0);
+   return eina_stringshare_add(ed->file->compiler);
+}
+
+/****************/
+/*  GROUPS API  */
+/****************/
+
+/**
+ * @brief Add an edje (empty) group to an edje object's group set.
+ *
+ * @param obj The pointer to edje object.
+ * @param name The name of the group.
+ *
+ * @return 1 If it could allocate memory to the part group added
+ * or zero if not.
+ *
+ * This function adds, at run time, one more group, which will reside
+ * in memory, to the group set found in the .edj file which @a obj was
+ * loaded with. This group can be manipulated by other API functions,
+ * like @c edje_edit_part_add(), for example. If desired, the new
+ * group can be actually commited the respective .edj by use of @c
+ * edje_edit_save().
+ *
+ */
+EAPI Eina_Bool
+edje_edit_group_add(Evas_Object *obj, const char *name)
+{
+   Edje_Part_Collection_Directory_Entry *de;
+   Edje_Part_Collection_Directory_Entry *d;
+   Edje_Part_Collection *pc;
+   Eina_List *l;
+   int id;
+   int search;
+   //Code *cd;
+
+   GET_ED_OR_RETURN(0);
+
+   //printf("ADD GROUP: %s \n", name);
+
+   /* check if a group with the same name already exists */
+   EINA_LIST_FOREACH(ed->file->collection_dir->entries, l, d)
+     if (!strcmp(d->entry, name))
+       return 0;
+
+   /* Create structs */
+   de = _alloc(sizeof(Edje_Part_Collection_Directory_Entry));
+   if (!de) return 0;
+
+   pc = _alloc(sizeof(Edje_Part_Collection));
+   if (!pc)
+     {
+       free(de);
+       return 0;
+     }
+
+   /* Search first free id */
+   id = -1;
+   search = 0;
+   while (id == -1)
+     {
+       Eina_Bool found = 0;
+
+       EINA_LIST_FOREACH(ed->file->collection_dir->entries, l, d)
+         {
+            // printf("search if %d is free [id %d]\n", search, d->id);
+            if (search == d->id)
+              {
+                 found = 1;
+                 break;
+              }
+         }
+       if (!found)
+         id = search;
+       else
+         search++;
+     }
+
+   /* Init Edje_Part_Collection_Directory_Entry */
+   //printf(" new id: %d\n", id);
+   de->id = id;
+   de->entry = eina_stringshare_add(name);
+   ed->file->collection_dir->entries = eina_list_append(ed->file->collection_dir->entries, de);
+
+   /* Init Edje_Part_Collection */
+   pc->id = id;
+   pc->references = 0;
+   pc->programs = NULL;
+   pc->parts = NULL;
+   pc->data = NULL;
+   pc->script = NULL;
+   pc->part = eina_stringshare_add(name);
+
+   //cd = _alloc(sizeof(Code));
+   //codes = eina_list_append(codes, cd);
+
+   ed->file->collection_cache = eina_list_prepend(ed->file->collection_cache, pc);
+   _edje_cache_coll_clean(ed->file);
+
+   return 1;
+}
+
+/**
+ * @brief Delete the specified group from the edje file.
+ *
+ * @param obj The pointer to the edje object.
+ * @param group_name Group to delete.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE on failure.
+ *
+ * This function deletes the given group from the file @a obj is set to. This
+ * operation can't be undone as all references to the group are removed from
+ * the file.
+ * This function may fail if the group to be deleted is currently in use.
+ *
+ */
+EAPI Eina_Bool
+edje_edit_group_del(Evas_Object *obj, const char *group_name)
+{
+   char buf[32];
+   Eina_List *l;
+   Edje_Part_Collection *g;
+   Eet_File *eetf;
+   Edje_Part_Collection_Directory_Entry *e;
+
+   GET_ED_OR_RETURN(EINA_FALSE);
+
+   /* if (eina_hash_find(ed->file->collection_hash, group_name)) */
+   /*   return EINA_FALSE; */
+
+   if (strcmp(ed->group, group_name) == 0) return EINA_FALSE;
+
+   _edje_edit_group_references_update(obj, group_name, NULL);
+
+   EINA_LIST_FOREACH(ed->file->collection_dir->entries, l, e)
+     {
+       if (!strcmp(e->entry, group_name))
+         {
+            if (e->id == ed->collection->id) return EINA_FALSE;
+            ed->file->collection_dir->entries =
+              eina_list_remove_list(ed->file->collection_dir->entries, l);
+            break;
+         }
+       e = NULL;
+     }
+   if (!e) return EINA_FALSE;
+
+   EINA_LIST_FOREACH(ed->file->collection_cache, l, g)
+     {
+       if (g->id == e->id)
+         {
+            ed->file->collection_cache =
+              eina_list_remove_list(ed->file->collection_cache, l);
+            break;
+         }
+       g = NULL;
+     }
+
+   /* Remove collection/id from eet file */
+   eetf = eet_open(ed->file->path, EET_FILE_MODE_READ_WRITE);
+   if (!eetf)
+     {
+       ERR("Edje_Edit: Error. unable to open \"%s\" "
+           "for writing output", ed->file->path);
+       return EINA_FALSE;
+     }
+   snprintf(buf, sizeof(buf), "collections/%d", e->id);
+   eet_delete(eetf, buf);
+   eet_close(eetf);
+
+   /* Free Group */
+   if (g) _edje_collection_free(ed->file, g);
+
+   _edje_if_string_free(ed, e->entry);
+   free(e);
+
+   /* we need to save everything to make sure the file won't have broken
+    * references the next time is loaded */
+   edje_edit_save_all(obj);
+
+   return EINA_TRUE;
+}
+
+EAPI Eina_Bool
+edje_edit_group_exist(Evas_Object *obj, const char *group)
+{
+   Eina_List *l;
+   Edje_Part_Collection_Directory_Entry *e;
+
+   GET_ED_OR_RETURN(0);
+
+   EINA_LIST_FOREACH(ed->file->collection_dir->entries, l, e)
+     if (e->entry && !strcmp(e->entry, group))
+       return 1;
+   return 0;
+}
+
+EAPI Eina_Bool
+edje_edit_group_name_set(Evas_Object *obj, const char *new_name)
+{
+   Eina_List *l;
+   Edje_Part_Collection *pc;
+   Edje_Part_Collection_Directory_Entry *pce;
+
+   GET_ED_OR_RETURN(0);
+
+   if (!new_name) return 0;
+
+   pc = ed->collection;
+
+   if (!strcmp(pc->part, new_name)) return 1;
+
+   if (edje_edit_group_exist(obj, new_name)) return 0;
+
+   _edje_edit_group_references_update(obj, pc->part, new_name);
+
+   //printf("Set name of current group: %s [id: %d][new name: %s]\n",
+       // pc->part, pc->id, new_name);
+
+   //if (pc->part && ed->file->free_strings) eina_stringshare_del(pc->part); TODO FIXME
+   pc->part = eina_stringshare_add(new_name);
+
+   EINA_LIST_FOREACH(ed->file->collection_dir->entries, l, pce)
+     {
+       if (pc->id == pce->id)
+         {
+            eina_hash_del(ed->file->collection_hash,
+                          pce->entry, NULL);
+            if (!ed->file->collection_hash)
+              ed->file->collection_hash = eina_hash_string_superfast_new(NULL);
+            eina_hash_add(ed->file->collection_hash,
+                          new_name, pc);
+
+            //if (pce->entry &&  //TODO Also this cause segv
+            //    !eet_dictionary_string_check(eet_dictionary_get(ed->file->ef), pce->entry))
+            //   eina_stringshare_del(pce->entry);
+            pce->entry = eina_stringshare_add(new_name);
+
+            return 1;
+         }
+     }
+   return 0;
+}
+
+EAPI int
+edje_edit_group_min_w_get(Evas_Object *obj)
+{
+   //printf("Get min_w of group\n");
+   GET_ED_OR_RETURN(-1);
+   if (!ed->collection) return -1;
+   return ed->collection->prop.min.w;
+}
+
+EAPI void
+edje_edit_group_min_w_set(Evas_Object *obj, int w)
+{
+   //printf("Set min_w of group [new w: %d]\n", w);
+   GET_ED_OR_RETURN();
+   ed->collection->prop.min.w = w;
+}
+
+EAPI int
+edje_edit_group_min_h_get(Evas_Object *obj)
+{
+   //printf("Get min_h of group\n");
+   GET_ED_OR_RETURN(-1);
+   if (!ed->collection) return -1;
+   return ed->collection->prop.min.h;
+}
+
+EAPI void
+edje_edit_group_min_h_set(Evas_Object *obj, int h)
+{
+   //printf("Set min_h of group [new h: %d]\n", h);
+   GET_ED_OR_RETURN();
+   ed->collection->prop.min.h = h;
+}
+
+EAPI int
+edje_edit_group_max_w_get(Evas_Object *obj)
+{
+   //printf("Get max_w of group\n");
+   GET_ED_OR_RETURN(-1);
+   if (!ed->collection) return -1;
+   return ed->collection->prop.max.w;
+}
+
+EAPI void
+edje_edit_group_max_w_set(Evas_Object *obj, int w)
+{
+   //printf("Set max_w of group: [new w: %d]\n", w);
+   GET_ED_OR_RETURN();
+   ed->collection->prop.max.w = w;
+}
+
+EAPI int
+edje_edit_group_max_h_get(Evas_Object *obj)
+{
+   //printf("Get max_h of group\n");
+   GET_ED_OR_RETURN(-1);
+   if (!ed->collection) return -1;
+   return ed->collection->prop.max.h;
+}
+
+EAPI void
+edje_edit_group_max_h_set(Evas_Object *obj, int h)
+{
+   //printf("Set max_h of group: [new h: %d]\n", h);
+   GET_ED_OR_RETURN();
+   ed->collection->prop.max.h = h;
+}
+
+/***************/
+/*  DATA API   */
+/***************/
+
+EAPI Eina_List *
+edje_edit_group_data_list_get(Evas_Object * obj)
+{
+   Eina_List *datas;
+   Eina_List *l;
+   Edje_Data *d;
+
+   GET_ED_OR_RETURN(NULL);
+
+   if (!ed->file || !ed->collection)
+     return NULL;
+
+   datas = NULL;
+   EINA_LIST_FOREACH(ed->collection->data, l, d)
+     datas = eina_list_append(datas, eina_stringshare_add(d->key));
+
+   return datas;
+}
+
+EAPI Eina_List *
+edje_edit_data_list_get(Evas_Object * obj)
+{
+   Eina_List *datas = NULL;
+   Eina_List *l;
+   Edje_Data *d;
+
+   GET_ED_OR_RETURN(NULL);
+
+   if (!ed->file || !ed->file->data)
+     return NULL;
+
+   datas = NULL;
+   EINA_LIST_FOREACH(ed->file->data, l, d)
+     datas = eina_list_append(datas, eina_stringshare_add(d->key));
+
+   return datas;
+}
+
+EAPI Eina_Bool
+edje_edit_group_data_add(Evas_Object *obj, const char *key, const char *value)
+{
+   Edje_Data *new;
+   Edje_Data *d;
+   Eina_List *l;
+   int len;
+
+   GET_ED_OR_RETURN(EINA_FALSE);
+
+   if (!key || !ed->file || !ed->collection)
+     return EINA_FALSE;
+
+   len = strlen(key);
+   EINA_LIST_FOREACH(ed->collection->data, l, d)
+     if ((d->key) && (!strncmp(d->key, key, len)))
+       return EINA_FALSE;
+
+   new = _alloc(sizeof(Edje_Data));
+   if (!new) return EINA_FALSE;
+
+   new->key = (char*)eina_stringshare_add(key);
+   if (value) new->value = (char*)eina_stringshare_add(value);
+   else new->value = NULL;
+
+   ed->collection->data = eina_list_append(ed->collection->data, new);
+
+   return EINA_TRUE;
+}
+
+EAPI Eina_Bool
+edje_edit_data_add(Evas_Object *obj, const char *itemname, const char *value)
+{
+   Eina_List *l;
+   Edje_Data *d;
+   Edje_Data *dd;
+
+   GET_ED_OR_RETURN(0);
+
+   if (!itemname || !ed->file)
+     return 0;
+
+   EINA_LIST_FOREACH(ed->file->data, l, dd)
+     if (strcmp(dd->key, itemname) == 0)
+       return 0;
+
+   d = _alloc(sizeof(Edje_Data));
+   if (!d) return 0;
+
+   d->key = (char*)eina_stringshare_add(itemname);
+   if (value) d->value = (char*)eina_stringshare_add(value);
+   else d->value = NULL;
+
+   ed->file->data = eina_list_append(ed->file->data, d);
+
+   return 1;
+}
+
+EAPI Eina_Bool
+edje_edit_group_data_del(Evas_Object *obj, const char *key)
+{
+   Eina_List *l;
+   Edje_Data *d;
+   int len;
+
+   GET_ED_OR_RETURN(EINA_FALSE);
+
+   if (!key || !ed->file || !ed->collection)
+     return EINA_FALSE;
+
+   len = strlen(key);
+   EINA_LIST_FOREACH(ed->collection->data, l, d)
+     {
+       if (strncmp(d->key, key, len) == 0)
+          {
+             _edje_if_string_free(ed, d->key);
+             _edje_if_string_free(ed, d->value);
+             ed->collection->data = eina_list_remove(ed->collection->data, d);
+             free(d);
+             return EINA_TRUE;
+          }
+     }
+
+   return EINA_FALSE;
+}
+
+EAPI Eina_Bool
+edje_edit_data_del(Evas_Object *obj, const char *itemname)
+{
+   Eina_List *l;
+   Edje_Data *d;
+
+   GET_ED_OR_RETURN(0);
+
+   if (!itemname || !ed->file || !ed->file->data)
+     return 0;
+
+   EINA_LIST_FOREACH(ed->file->data, l, d)
+     {
+       if (strcmp(d->key, itemname) == 0)
+          {
+             _edje_if_string_free(ed, d->key);
+             _edje_if_string_free(ed, d->value);
+             ed->file->data = eina_list_remove(ed->file->data, d);
+             free(d);
+             return 1;
+          }
+     }
+   return 0;
+}
+
+EAPI const char *
+edje_edit_group_data_value_get(Evas_Object * obj, char *key)
+{
+   Eina_List *l;
+   Edje_Data *d;
+   int len;
+
+   GET_ED_OR_RETURN(NULL);
+
+   if (!key || !ed->file || !ed->collection)
+     return NULL;
+
+   len = strlen(key);
+   EINA_LIST_FOREACH(ed->collection->data, l, d)
+     if (strncmp(d->key, key, len) == 0)
+       return eina_stringshare_add(d->value);
+
+   return NULL;
+}
+
+EAPI const char *
+edje_edit_data_value_get(Evas_Object * obj, char *itemname)
+{
+   Eina_List *l;
+   Edje_Data *d;
+
+   GET_ED_OR_RETURN(NULL);
+
+   if (!itemname || !ed->file || !ed->file->data)
+     return NULL;
+
+   EINA_LIST_FOREACH(ed->file->data, l, d)
+     if (strcmp(d->key, itemname) == 0)
+       return eina_stringshare_add(d->value);
+
+   return NULL;
+}
+
+EAPI Eina_Bool
+edje_edit_group_data_value_set(Evas_Object *obj, const char *key, const char *value)
+{
+   Eina_List *l;
+   Edje_Data *d;
+   int len;
+
+   GET_ED_OR_RETURN(EINA_FALSE);
+
+   if (!key || !value || !ed->file || !ed->collection)
+     return EINA_FALSE;
+
+   len = strlen(key);
+   EINA_LIST_FOREACH(ed->collection->data, l, d)
+     if (strncmp(d->key, key, len) == 0)
+       {
+         _edje_if_string_free(ed, d->value);
+         d->value = (char*)eina_stringshare_add(value);
+         return EINA_TRUE;
+       }
+
+   return EINA_FALSE;
+}
+
+EAPI Eina_Bool
+edje_edit_data_value_set(Evas_Object *obj, const char *itemname, const char *value)
+{
+   Eina_List *l;
+   Edje_Data *d;
+
+   GET_ED_OR_RETURN(0);
+
+   if (!itemname || !value || !ed->file || !ed->file->data)
+     return 0;
+
+   EINA_LIST_FOREACH(ed->file->data, l, d)
+     if (strcmp(d->key, itemname) == 0)
+       {
+        _edje_if_string_free(ed, d->value);
+        d->value = (char*)eina_stringshare_add(value);
+        return 1;
+       }
+
+   return 0;
+}
+
+EAPI Eina_Bool
+edje_edit_group_data_name_set(Evas_Object *obj, const char *key,  const char *new_key)
+{
+   Eina_List *l;
+   Edje_Data *d;
+   int len;
+
+   GET_ED_OR_RETURN(EINA_FALSE);
+
+   if (!key || !new_key || !ed->file || !ed->collection) {
+      return EINA_FALSE;
+   }
+
+   len = strlen(key);
+   EINA_LIST_FOREACH(ed->collection->data, l, d) {
+      if (strncmp(d->key, key, len) == 0)
+       {
+          _edje_if_string_free(ed, d->key);
+          d->key = (char*)eina_stringshare_add(new_key);
+          return EINA_TRUE;
+       }
+   }
+
+   return EINA_FALSE;
+}
+
+EAPI Eina_Bool
+edje_edit_data_name_set(Evas_Object *obj, const char *itemname,  const char *newname)
+{
+   Eina_List *l;
+   Edje_Data *d;
+
+   GET_ED_OR_RETURN(0);
+
+   if (!itemname || !newname || !ed->file || !ed->file->data)
+     return 0;
+
+   EINA_LIST_FOREACH(ed->file->data, l, d)
+     if (strcmp(d->key, itemname) == 0)
+       {
+        _edje_if_string_free(ed, d->key);
+        d->key = (char*)eina_stringshare_add(newname);
+        return 1;
+       }
+
+   return 0;
+}
+
+/***********************/
+/*  COLOR CLASSES API  */
+/***********************/
+
+EAPI Eina_List *
+edje_edit_color_classes_list_get(Evas_Object * obj)
+{
+   Eina_List *classes = NULL;
+   Eina_List *l;
+   Edje_Color_Class *cc;
+
+   GET_ED_OR_RETURN(NULL);
+
+   if (!ed->file || !ed->file->color_classes)
+      return NULL;
+   //printf("GET CLASSES LIST %d %d\n", eina_list_count(ed->color_classes), eina_list_count(ed->file->color_classes));
+   EINA_LIST_FOREACH(ed->file->color_classes, l, cc)
+     classes = eina_list_append(classes, eina_stringshare_add(cc->name));
+
+   return classes;
+}
+
+EAPI Eina_Bool
+edje_edit_color_class_colors_get(Evas_Object *obj, const char *class_name, int *r, int *g, int *b, int *a, int *r2, int *g2, int *b2, int *a2, int *r3, int *g3, int *b3, int *a3)
+{
+   Eina_List *l;
+   Edje_Color_Class *cc;
+
+   GET_ED_OR_RETURN(0);
+
+   if (!ed->file || !ed->file->color_classes)
+      return 0;
+
+   EINA_LIST_FOREACH(ed->file->color_classes, l, cc)
+     if (!strcmp(cc->name, class_name))
+       {
+        if (r) *r = cc->r;
+        if (g) *g = cc->g;
+        if (b) *b = cc->b;
+        if (a) *a = cc->a;
+
+        if (r2) *r2 = cc->r2;
+        if (g2) *g2 = cc->g2;
+        if (b2) *b2 = cc->b2;
+        if (a2) *a2 = cc->a2;
+
+        if (r3) *r3 = cc->r3;
+        if (g3) *g3 = cc->g3;
+        if (b3) *b3 = cc->b3;
+        if (a3) *a3 = cc->a3;
+
+        return 1;
+       }
+   return 0;
+}
+
+EAPI Eina_Bool
+edje_edit_color_class_colors_set(Evas_Object *obj, const char *class_name, int r, int g, int b, int a, int r2, int g2, int b2, int a2, int r3, int g3, int b3, int a3)
+{
+   Eina_List *l;
+   Edje_Color_Class *cc;
+
+   GET_ED_OR_RETURN(0);
+
+   if (!ed->file || !ed->file->color_classes)
+      return 0;
+
+   EINA_LIST_FOREACH(ed->file->color_classes, l, cc)
+     if (!strcmp(cc->name, class_name))
+       {
+        if (r > -1) cc->r = r;
+        if (g > -1) cc->g = g;
+        if (b > -1) cc->b = b;
+        if (a > -1) cc->a = a;
+
+        if (r2 > -1) cc->r2 = r2;
+        if (g2 > -1) cc->g2 = g2;
+        if (b2 > -1) cc->b2 = b2;
+        if (a2 > -1) cc->a2 = a2;
+
+        if (r3 > -1) cc->r3 = r3;
+        if (g3 > -1) cc->g3 = g3;
+        if (b3 > -1) cc->b3 = b3;
+        if (a3 > -1) cc->a3 = a3;
+
+        return 1;
+       }
+   return 0;
+}
+
+EAPI Eina_Bool
+edje_edit_color_class_add(Evas_Object *obj, const char *name)
+{
+   Eina_List *l;
+   Edje_Color_Class *c;
+   Edje_Color_Class *cc;
+
+   GET_ED_OR_RETURN(0);
+
+   if (!name || !ed->file)
+     return 0;
+
+   EINA_LIST_FOREACH(ed->file->color_classes, l, cc)
+     if (strcmp(cc->name, name) == 0)
+       return 0;
+
+   c = _alloc(sizeof(Edje_Color_Class));
+   if (!c) return 0;
+
+   c->name = (char*)eina_stringshare_add(name);
+   c->r = c->g = c->b = c->a = 255;
+   c->r2 = c->g2 = c->b2 = c->a2 = 255;
+   c->r3 = c->g3 = c->b3 = c->a3 = 255;
+
+   ed->file->color_classes = eina_list_append(ed->file->color_classes, c);
+
+   return 1;
+}
+
+EAPI Eina_Bool
+edje_edit_color_class_del(Evas_Object *obj, const char *name)
+{
+   Eina_List *l;
+   Edje_Color_Class *cc;
+
+   GET_ED_OR_RETURN(0);
+
+   if (!name || !ed->file || !ed->file->color_classes)
+     return 0;
+
+   EINA_LIST_FOREACH(ed->file->color_classes, l, cc)
+     if (strcmp(cc->name, name) == 0)
+       {
+        _edje_if_string_free(ed, cc->name);
+        ed->file->color_classes = eina_list_remove(ed->file->color_classes, cc);
+        free(cc);
+        return 1;
+       }
+   return 0;
+}
+
+EAPI Eina_Bool
+edje_edit_color_class_name_set(Evas_Object *obj, const char *name, const char *newname)
+{
+   Eina_List *l;
+   Edje_Color_Class *cc;
+
+   GET_ED_OR_RETURN(0);
+
+   if (!ed->file || !ed->file->color_classes)
+      return 0;
+
+   EINA_LIST_FOREACH(ed->file->color_classes, l, cc)
+     if (!strcmp(cc->name, name))
+       {
+        _edje_if_string_free(ed, cc->name);
+        cc->name = (char*)eina_stringshare_add(newname);
+        return 1;
+       }
+
+   return 0;
+}
+
+
+
+/*********************/
+/*  TEXT STYLES API  */
+/*********************/
+
+EAPI Eina_List *
+edje_edit_styles_list_get(Evas_Object * obj)
+{
+   Eina_List *styles = NULL;
+   Eina_List *l;
+   Edje_Style *s;
+
+   GET_ED_OR_RETURN(NULL);
+
+   if (!ed->file || !ed->file->styles)
+      return NULL;
+   //printf("GET STYLES LIST %d\n", eina_list_count(ed->file->styles));
+   EINA_LIST_FOREACH(ed->file->styles, l, s)
+     styles = eina_list_append(styles, eina_stringshare_add(s->name));
+
+   return styles;
+}
+
+EAPI Eina_Bool
+edje_edit_style_add(Evas_Object * obj, const char* style)
+{
+   Edje_Style *s;
+   GET_ED_OR_RETURN(0);
+   //printf("ADD STYLE '%s'\n", style);
+
+   s = _edje_edit_style_get(ed, style);
+   if (s) return 0;
+
+   s = _alloc(sizeof(Edje_Style));
+   if (!s) return 0;
+   s->name = (char*)eina_stringshare_add(style);
+   s->tags = NULL;
+   s->style = NULL;
+
+   ed->file->styles = eina_list_append(ed->file->styles, s);
+   return 1;
+}
+
+EAPI void
+edje_edit_style_del(Evas_Object * obj, const char* style)
+{
+   Edje_Style *s;
+
+   GET_ED_OR_RETURN();
+   //printf("DEL STYLE '%s'\n", style);
+
+   s = _edje_edit_style_get(ed, style);
+   if (!s) return;
+
+   ed->file->styles = eina_list_remove(ed->file->styles, s);
+
+   _edje_if_string_free(ed, s->name);
+   //~ //s->style HOWTO FREE ???
+   while (s->tags)
+   {
+      Edje_Style_Tag *t;
+
+      t = s->tags->data;
+
+      s->tags = eina_list_remove(s->tags, t);
+      _edje_if_string_free(ed, t->key);
+      _edje_if_string_free(ed, t->value);
+      _edje_if_string_free(ed, t->font);
+      _edje_if_string_free(ed, t->text_class);
+      free(t);
+      t = NULL;
+   }
+   free(s);
+   s = NULL;
+   s = NULL;
+}
+
+
+EAPI Eina_List *
+edje_edit_style_tags_list_get(Evas_Object * obj, const char* style)
+{
+   Eina_List *tags = NULL;
+   Eina_List *l;
+   Edje_Style *s;
+   Edje_Style_Tag *t;
+
+   GET_ED_OR_RETURN(NULL);
+   if (!ed->file || !ed->file->styles || !style)
+      return NULL;
+
+   s = _edje_edit_style_get(ed, style);
+
+   //printf("GET STYLE TAG LIST %d\n", eina_list_count(s->tags));
+   EINA_LIST_FOREACH(s->tags, l, t)
+      tags = eina_list_append(tags, eina_stringshare_add(t->key));
+
+   return tags;
+}
+
+EAPI void
+edje_edit_style_tag_name_set(Evas_Object * obj, const char* style, const char* tag, const char*new_name)
+{
+   Edje_Style_Tag *t;
+
+   GET_ED_OR_RETURN();
+   //printf("SET TAG NAME for '%s' FOR STYLE '%s'\n", tag, style);
+
+   if (!ed->file || !ed->file->styles || !style || !tag)
+      return;
+
+   t = _edje_edit_style_tag_get(ed, style, tag);
+   if (!t) return;
+   _edje_if_string_free(ed, t->key);
+   t->key = eina_stringshare_add(new_name);
+}
+
+EAPI const char*
+edje_edit_style_tag_value_get(Evas_Object * obj, const char* style, const char* tag)
+{
+   Edje_Style_Tag *t;
+
+   GET_ED_OR_RETURN(NULL);
+   //printf("GET TAG '%s' FOR STYLE '%s'\n", tag, style);
+
+   if (!ed->file || !ed->file->styles || !style || !tag)
+      return NULL;
+
+   t = _edje_edit_style_tag_get(ed, style, tag);
+   if (t && t->value)
+      return eina_stringshare_add(t->value);
+
+   return NULL;
+}
+
+EAPI void
+edje_edit_style_tag_value_set(Evas_Object * obj, const char* style, const char* tag, const char*new_value)
+{
+   Edje_Style_Tag *t;
+
+   GET_ED_OR_RETURN();
+   //printf("SET TAG VALUE for '%s' FOR STYLE '%s'\n", tag, style);
+
+   if (!ed->file || !ed->file->styles || !style || !tag)
+      return;
+
+   t = _edje_edit_style_tag_get(ed, style, tag);
+   if (!t) return;
+   _edje_if_string_free(ed, t->value);
+   t->value = eina_stringshare_add(new_value);
+}
+
+EAPI Eina_Bool
+edje_edit_style_tag_add(Evas_Object * obj, const char* style, const char* tag_name)
+{
+   Edje_Style *s;
+   Edje_Style_Tag *t;
+
+   GET_ED_OR_RETURN(0);
+   //printf("ADD TAG '%s' IN STYLE '%s'\n", tag_name, style);
+
+   t = _edje_edit_style_tag_get(ed, style, tag_name);
+   if (t) return 0;
+   s = _edje_edit_style_get(ed, style);
+   if (!s) return 0;
+
+   t = _alloc(sizeof(Edje_Style_Tag));
+   if (!t) return 0;
+   t->key = eina_stringshare_add(tag_name);
+   t->value = NULL;
+   t->font = NULL;
+   t->text_class = NULL;
+
+   s->tags = eina_list_append(s->tags, t);
+   return 1;
+}
+
+EAPI void
+edje_edit_style_tag_del(Evas_Object * obj, const char* style, const char* tag)
+{
+   Edje_Style *s;
+   Edje_Style_Tag *t;
+
+   GET_ED_OR_RETURN();
+   //printf("DEL TAG '%s' IN STYLE '%s'\n", tag, style);
+
+   s = _edje_edit_style_get(ed, style);
+   t = _edje_edit_style_tag_get(ed, style, tag);
+
+   s->tags = eina_list_remove(s->tags, t);
+   _edje_if_string_free(ed, t->key);
+   _edje_if_string_free(ed, t->value);
+   _edje_if_string_free(ed, t->font);
+   _edje_if_string_free(ed, t->text_class);
+   free(t);
+   t = NULL;
+}
+
+/*******************/
+/*  EXTERNALS API  */
+/*******************/
+
+EAPI Eina_List *
+edje_edit_externals_list_get(Evas_Object *obj)
+{
+   Eina_List *externals = NULL;
+   Eina_List *l;
+   Edje_External_Directory_Entry *e;
+
+   GET_ED_OR_RETURN(NULL);
+
+   if (!ed->file || !ed->file->external_dir)
+      return NULL;
+   //printf("GET STYLES LIST %d\n", eina_list_count(ed->file->styles));
+   EINA_LIST_FOREACH(ed->file->external_dir->entries, l, e)
+     externals = eina_list_append(externals, eina_stringshare_add(e->entry));
+
+   return externals;
+}
+
+EAPI Eina_Bool
+edje_edit_external_add(Evas_Object *obj, const char *external)
+{
+   Edje_External_Directory_Entry *e;
+   GET_ED_OR_RETURN(EINA_FALSE);
+
+   e = _edje_edit_external_get(ed, external);
+   if (e) return EINA_FALSE;
+
+   e = _alloc(sizeof(Edje_External_Directory_Entry));
+   if (!e) return EINA_FALSE;
+   e->entry = (char*)eina_stringshare_add(external);
+
+   if (!ed->file->external_dir)
+     ed->file->external_dir = _alloc(sizeof(Edje_External_Directory));
+   ed->file->external_dir->entries = \
+     eina_list_append(ed->file->external_dir->entries, e);
+   return EINA_TRUE;
+}
+
+EAPI Eina_Bool
+edje_edit_external_del(Evas_Object *obj, const char *external)
+{
+   Edje_External_Directory_Entry *e;
+
+   GET_ED_OR_RETURN(EINA_FALSE);
+
+   e = _edje_edit_external_get(ed, external);
+   if (!e) return EINA_FALSE;
+
+   ed->file->external_dir->entries = \
+     eina_list_remove(ed->file->external_dir->entries, e);
+   if (!ed->file->external_dir->entries)
+     {
+       free(ed->file->external_dir);
+       ed->file->external_dir = NULL;
+     }
+
+   _edje_if_string_free(ed, e->entry);
+   free(e);
+
+   return EINA_TRUE;
+}
+
+/***************/
+/*  PARTS API  */
+/***************/
+
+EAPI Eina_List *
+edje_edit_parts_list_get(Evas_Object *obj)
+{
+   Eina_List *parts = NULL;
+   int i;
+
+   GET_ED_OR_RETURN(NULL);
+
+   //printf("EE: Found %d parts\n", ed->table_parts_size);
+
+   parts = NULL;
+   for (i = 0; i < ed->table_parts_size; i++)
+     {
+       Edje_Real_Part *rp;
+
+       rp = ed->table_parts[i];
+       parts = eina_list_append(parts, eina_stringshare_add(rp->part->name));
+     }
+
+   return parts;
+}
+
+EAPI Eina_Bool
+edje_edit_part_name_set(Evas_Object *obj, const char* part, const char* new_name)
+{
+   GET_RP_OR_RETURN(0);
+
+   if (!new_name) return 0;
+   if (!strcmp(part, new_name)) return 1;
+   if (_edje_real_part_get(ed, new_name)) return 0;
+
+   //printf("Set name of part: %s [new name: %s]\n", part, new_name);
+
+   _edje_if_string_free(ed, rp->part->name);
+   rp->part->name = (char *)eina_stringshare_add(new_name);
+
+   return 1;
+}
+
+Eina_Bool
+_edje_edit_real_part_add(Evas_Object *obj, const char *name, Edje_Part_Type type, const char *source)
+{
+   Edje_Part_Collection *pc;
+   Edje_Part *ep;
+   Edje_Real_Part *rp;
+
+   GET_ED_OR_RETURN(0);
+
+   //printf("ADD PART: %s [type: %d]\n", name, type);
+
+   /* Check if part already exists */
+   if (_edje_real_part_get(ed, name))
+     return EINA_FALSE;
+
+   /* Alloc Edje_Part or return */
+   ep = _alloc(sizeof(Edje_Part));
+   if (!ep) return EINA_FALSE;
+
+   /* Alloc Edje_Real_Part or return */
+   rp = _alloc(sizeof(Edje_Real_Part));
+   if (!rp)
+     {
+       free(ep);
+       return EINA_FALSE;
+     }
+
+   /* Init Edje_Part */
+   pc = ed->collection;
+   pc->parts = eina_list_append(pc->parts, ep);
+
+   ep->id = eina_list_count(pc->parts) - 1;
+   ep->type = type;
+   ep->name = eina_stringshare_add(name);
+   ep->mouse_events = 1;
+   ep->repeat_events = 0;
+   ep->ignore_flags = EVAS_EVENT_FLAG_NONE;
+   ep->pointer_mode = EVAS_OBJECT_POINTER_MODE_AUTOGRAB;
+   ep->precise_is_inside = 0;
+   ep->use_alternate_font_metrics = 0;
+   ep->clip_to_id = -1;
+   ep->dragable.confine_id = -1;
+   ep->dragable.events_id = -1;
+   if (source)
+     ep->source = eina_stringshare_add(source);
+
+   ep->default_desc = NULL;
+   ep->other_desc = NULL;
+
+   /* Init Edje_Real_Part */
+   rp->edje = ed;
+   _edje_ref(rp->edje);
+   rp->part = ep;
+
+   if (ep->type == EDJE_PART_TYPE_RECTANGLE)
+     rp->object = evas_object_rectangle_add(ed->evas);
+   else if (ep->type == EDJE_PART_TYPE_IMAGE)
+     rp->object = evas_object_image_add(ed->evas);
+   else if (ep->type == EDJE_PART_TYPE_TEXT)
+     {
+       _edje_text_part_on_add(ed, rp);
+       rp->object = evas_object_text_add(ed->evas);
+       evas_object_text_font_source_set(rp->object, ed->path);
+     }
+   else if (ep->type == EDJE_PART_TYPE_SWALLOW ||
+           ep->type == EDJE_PART_TYPE_GROUP ||
+           ep->type == EDJE_PART_TYPE_EXTERNAL)
+     {
+       rp->object = evas_object_rectangle_add(ed->evas);
+       evas_object_color_set(rp->object, 0, 0, 0, 0);
+       evas_object_pass_events_set(rp->object, 1);
+       evas_object_pointer_mode_set(rp->object, EVAS_OBJECT_POINTER_MODE_NOGRAB);
+     }
+   else if (ep->type == EDJE_PART_TYPE_TEXTBLOCK)
+     rp->object = evas_object_textblock_add(ed->evas);
+   else if (ep->type == EDJE_PART_TYPE_GRADIENT)
+     rp->object = evas_object_gradient_add(ed->evas);
+   else
+     ERR("wrong part type %i!", ep->type);
+   if (rp->object)
+     {
+       evas_object_show(rp->object);
+       evas_object_smart_member_add(rp->object, ed->obj);
+       evas_object_layer_set(rp->object, evas_object_layer_get(ed->obj));
+       if (ep->type != EDJE_PART_TYPE_SWALLOW && ep->type != EDJE_PART_TYPE_GROUP)
+         {
+            if (ep->mouse_events)
+              {
+                 _edje_callbacks_add(rp->object, ed, rp);
+                 if (ep->repeat_events)
+                   evas_object_repeat_events_set(rp->object, 1);
+
+                 if (ep->pointer_mode != EVAS_OBJECT_POINTER_MODE_AUTOGRAB)
+                   evas_object_pointer_mode_set(rp->object, ep->pointer_mode);
+              }
+            else
+              {
+                 evas_object_pass_events_set(rp->object, 1);
+                 evas_object_pointer_mode_set(rp->object,
+                                              EVAS_OBJECT_POINTER_MODE_NOGRAB);
+              }
+            if (ep->precise_is_inside)
+              evas_object_precise_is_inside_set(rp->object, 1);
+         }
+       if (ep->type == EDJE_PART_TYPE_EXTERNAL)
+         {
+            Evas_Object *child;
+            child = _edje_external_type_add(source, evas_object_evas_get(ed->obj), ed->obj, NULL, name);
+            if (child)
+              _edje_real_part_swallow(rp, child);
+         }
+       evas_object_clip_set(rp->object, ed->clipper);
+       evas_object_show(ed->clipper);
+     }
+   rp->gradient_id = -1;
+
+
+   /* Update table_parts */
+   ed->table_parts_size++;
+   ed->table_parts = realloc(ed->table_parts,
+                            sizeof(Edje_Real_Part *) * ed->table_parts_size);
+
+   ed->table_parts[ep->id % ed->table_parts_size] = rp;
+
+   /* Create default description */
+   edje_edit_state_add(obj, name, "default", 0.0);
+   edje_edit_part_selected_state_set(obj, name, "default", 0.0);
+
+   return EINA_TRUE;
+}
+
+EAPI Eina_Bool
+edje_edit_part_add(Evas_Object *obj, const char *name, Edje_Part_Type type)
+{
+   if (type == EDJE_PART_TYPE_EXTERNAL)
+     return EINA_FALSE;
+   return _edje_edit_real_part_add(obj, name, type, NULL);
+}
+
+EAPI Eina_Bool
+edje_edit_part_external_add(Evas_Object *obj, const char *name, const char *source)
+{
+   if (!source)
+     return EINA_FALSE;
+   return _edje_edit_real_part_add(obj, name, EDJE_PART_TYPE_EXTERNAL, source);
+}
+
+EAPI Eina_Bool
+edje_edit_part_del(Evas_Object *obj, const char* part)
+{
+   Edje_Part *ep;
+   Edje_Part_Collection *pc;
+   int id;
+
+   GET_RP_OR_RETURN(0);
+
+   //printf("REMOVE PART: %s\n", part);
+
+   ep = rp->part;
+   id = ep->id;
+
+   //if (ed->table_parts_size <= 1) return EINA_FALSE; //don't remove the last part
+
+   /* Unlik Edje_Real_Parts that link to the removed one */
+   int i;
+   for (i = 0; i < ed->table_parts_size; i++)
+     {
+       Edje_Real_Part *real;
+
+       if (i == id) continue; //don't check the deleted id
+       real = ed->table_parts[i % ed->table_parts_size];
+
+       if (real->text.source == rp) real->text.source = NULL;
+       if (real->text.text_source == rp) real->text.text_source = NULL;
+
+       if (real->param1.rel1_to_x == rp) real->param1.rel1_to_x = NULL;
+       if (real->param1.rel1_to_y == rp) real->param1.rel1_to_y = NULL;
+       if (real->param1.rel2_to_x == rp) real->param1.rel2_to_x = NULL;
+       if (real->param1.rel2_to_y == rp) real->param1.rel2_to_y = NULL;
+
+       if (real->param2)
+         {
+            if (real->param2->rel1_to_x == rp) real->param2->rel1_to_x = NULL;
+            if (real->param2->rel1_to_y == rp) real->param2->rel1_to_y = NULL;
+            if (real->param2->rel2_to_x == rp) real->param2->rel2_to_x = NULL;
+            if (real->param2->rel2_to_y == rp) real->param2->rel2_to_y = NULL;
+         }
+
+       if (real->custom)
+         {
+            if (real->custom->rel1_to_x == rp) real->custom->rel1_to_x = NULL;
+            if (real->custom->rel1_to_y == rp) real->custom->rel1_to_y = NULL;
+            if (real->custom->rel2_to_x == rp) real->custom->rel2_to_x = NULL;
+            if (real->custom->rel2_to_y == rp) real->custom->rel2_to_y = NULL;
+         }
+
+       if (real->clip_to == rp)
+         {
+            evas_object_clip_set(real->object, ed->clipper);
+            real->clip_to = NULL;
+         }
+       if (real->drag && real->drag->confine_to == rp)
+         real->drag->confine_to = NULL;
+     }
+
+   /* Unlink all the parts and descriptions that refer to id */
+   _edje_part_id_set(ed, rp, -1);
+
+   /* Remove part from parts list */
+   pc = ed->collection;
+   pc->parts = eina_list_remove(pc->parts, ep);
+   _edje_fix_parts_id(ed);
+
+   /* Free Edje_Part and all descriptions */
+   _edje_if_string_free(ed, ep->name);
+   if (ep->default_desc)
+     {
+       _edje_collection_free_part_description_free(ep->default_desc, 0);
+       ep->default_desc = NULL;
+     }
+   while (ep->other_desc)
+     {
+       Edje_Part_Description *desc;
+
+       desc = eina_list_data_get(ep->other_desc);
+       ep->other_desc = eina_list_remove(ep->other_desc, desc);
+       _edje_collection_free_part_description_free(desc, 0);
+     }
+   free(ep);
+
+   /* Free Edje_Real_Part */
+   _edje_real_part_free(rp);
+
+   /* if all parts are gone, hide the clipper */
+   if (ed->table_parts_size == 0)
+     evas_object_hide(ed->clipper);
+
+   edje_object_calc_force(obj);
+   return EINA_TRUE;
+}
+
+EAPI Eina_Bool
+edje_edit_part_exist(Evas_Object *obj, const char *part)
+{
+   GET_RP_OR_RETURN(0);
+   return 1;
+}
+
+EAPI const char*
+edje_edit_part_below_get(Evas_Object *obj, const char* part)
+{
+   Edje_Real_Part *prev;
+
+   GET_RP_OR_RETURN(0);
+
+   if (rp->part->id < 1) return NULL;
+
+   prev = ed->table_parts[(rp->part->id - 1) % ed->table_parts_size];
+
+   return eina_stringshare_add(prev->part->name);
+}
+
+EAPI const char*
+edje_edit_part_above_get(Evas_Object *obj, const char* part)
+{
+   Edje_Real_Part *next;
+
+   GET_RP_OR_RETURN(0);
+
+   if (rp->part->id >= ed->table_parts_size - 1) return 0;
+
+   next = ed->table_parts[(rp->part->id + 1) % ed->table_parts_size];
+
+   return eina_stringshare_add(next->part->name);
+}
+
+EAPI Eina_Bool
+edje_edit_part_restack_below(Evas_Object *obj, const char* part)
+{
+   Edje_Part_Collection *group;
+   Edje_Real_Part *prev;
+
+   GET_RP_OR_RETURN(0);
+
+   //printf("RESTACK PART: %s BELOW\n", part);
+
+   if (rp->part->id < 1) return 0;
+   group = ed->collection;
+
+   /* update parts list */
+   prev = ed->table_parts[(rp->part->id - 1) % ed->table_parts_size];
+   group->parts = eina_list_remove(group->parts, rp->part);
+   group->parts = eina_list_prepend_relative(group->parts, rp->part, prev->part);
+
+   _edje_parts_id_switch(ed, rp, prev);
+
+   evas_object_stack_below(rp->object, prev->object);
+   if (rp->swallowed_object)
+     evas_object_stack_above(rp->swallowed_object, rp->object);
+
+   return 1;
+}
+
+EAPI Eina_Bool
+edje_edit_part_restack_above(Evas_Object *obj, const char* part)
+{
+   Edje_Part_Collection *group;
+   Edje_Real_Part *next;
+
+   GET_RP_OR_RETURN(0);
+
+   //printf("RESTACK PART: %s ABOVE\n", part);
+
+   if (rp->part->id >= ed->table_parts_size - 1) return 0;
+
+   group = ed->collection;
+
+   /* update parts list */
+   next = ed->table_parts[(rp->part->id + 1) % ed->table_parts_size];
+   group->parts = eina_list_remove(group->parts, rp->part);
+   group->parts = eina_list_append_relative(group->parts, rp->part, next->part);
+
+   /* update ids */
+   _edje_parts_id_switch(ed, rp, next);
+
+   evas_object_stack_above(rp->object, next->object);
+   if (rp->swallowed_object)
+     evas_object_stack_above(rp->swallowed_object, rp->object);
+
+   return 1;
+}
+
+EAPI Edje_Part_Type
+edje_edit_part_type_get(Evas_Object *obj, const char *part)
+{
+   GET_RP_OR_RETURN(0);
+
+   return rp->part->type;
+}
+
+EAPI const char *
+edje_edit_part_selected_state_get(Evas_Object *obj, const char *part, double *value)
+{
+   GET_RP_OR_RETURN(NULL);
+
+   if (!rp->chosen_description)
+     {
+       if (value) *value = 0.0; // FIXME: Make sure edje_edit supports correctly the default having any value
+       return eina_stringshare_add("default");
+     }
+
+   if (value) *value = rp->chosen_description->state.value;
+   return eina_stringshare_add(rp->chosen_description->state.name);
+}
+
+EAPI Eina_Bool
+edje_edit_part_selected_state_set(Evas_Object *obj, const char *part, const char *state, double value)
+{
+   Edje_Part_Description *pd;
+
+   GET_RP_OR_RETURN(0);
+
+   pd = _edje_part_description_find_byname(eed, part, state, value);
+   if (!pd) return 0;
+
+   //printf("EDJE: Set state: %s %f\n", pd->state.name, pd->state.value);
+   _edje_part_description_apply(ed, rp, pd->state.name, pd->state.value, NULL, 0.0);
+
+   edje_object_calc_force(obj);
+   return 1;
+}
+
+EAPI const char *
+edje_edit_part_clip_to_get(Evas_Object *obj, const char *part)
+{
+   Edje_Real_Part *clip = NULL;
+
+   GET_RP_OR_RETURN(NULL);
+
+   //printf("Get clip_to for part: %s [to_id: %d]\n", part, rp->part->clip_to_id);
+   if (rp->part->clip_to_id < 0) return NULL;
+
+   clip = ed->table_parts[rp->part->clip_to_id % ed->table_parts_size];
+   if (!clip || !clip->part || !clip->part->name) return NULL;
+
+   return eina_stringshare_add(clip->part->name);
+}
+
+EAPI Eina_Bool
+edje_edit_part_clip_to_set(Evas_Object *obj, const char *part, const char *clip_to)
+{
+   Edje_Real_Part *clip;
+   Evas_Object *o, *oo;
+
+   GET_RP_OR_RETURN(0);
+
+   /* unset clipping */
+   if (!clip_to)
+     {
+       //printf("UnSet clip_to for part: %s\n", part);
+
+       if (rp->clip_to && rp->clip_to->object)
+         {
+            evas_object_pointer_mode_set(rp->clip_to->object,
+                                         EVAS_OBJECT_POINTER_MODE_AUTOGRAB);
+            evas_object_clip_unset(rp->object);
+         }
+
+       evas_object_clip_set(rp->object, ed->clipper);
+       if (rp->swallowed_object)
+         evas_object_clip_set(rp->swallowed_object, ed->clipper);
+
+       rp->part->clip_to_id = -1;
+       rp->clip_to = NULL;
+
+       edje_object_calc_force(obj);
+
+       return 1;
+     }
+
+   /* set clipping */
+   //printf("Set clip_to for part: %s [to: %s]\n", part, clip_to);
+   clip = _edje_real_part_get(ed, clip_to);
+   if (!clip || !clip->part) return 0;
+   o = clip->object;
+   while ((oo = evas_object_clip_get(o)))
+     {
+       if (o == rp->object)
+         return 0;
+       o = oo;
+     }
+
+   rp->part->clip_to_id = clip->part->id;
+   rp->clip_to = clip;
+
+   evas_object_pass_events_set(rp->clip_to->object, 1);
+   evas_object_pointer_mode_set(rp->clip_to->object, EVAS_OBJECT_POINTER_MODE_NOGRAB);
+   evas_object_clip_set(rp->object, rp->clip_to->object);
+   if (rp->swallowed_object)
+     evas_object_clip_set(rp->swallowed_object, rp->clip_to->object);
+
+   edje_object_calc_force(obj);
+
+   return 1;
+}
+
+EAPI Eina_Bool
+edje_edit_part_mouse_events_get(Evas_Object *obj, const char *part)
+{
+   GET_RP_OR_RETURN(0);
+   //printf("Get mouse_events for part: %s [%d]\n", part, rp->part->mouse_events);
+   return rp->part->mouse_events;
+}
+
+EAPI void
+edje_edit_part_mouse_events_set(Evas_Object *obj, const char *part, Eina_Bool mouse_events)
+{
+   GET_RP_OR_RETURN();
+
+   if (!rp->object) return;
+
+   //printf("Set mouse_events for part: %s [%d]\n", part, mouse_events);
+
+   rp->part->mouse_events = mouse_events ? 1 : 0;
+
+   if (mouse_events)
+     {
+       evas_object_pass_events_set(rp->object, 0);
+       _edje_callbacks_add(rp->object, ed, rp);
+     }
+   else
+     {
+       evas_object_pass_events_set(rp->object, 1);
+       _edje_callbacks_del(rp->object, ed);
+     }
+}
+
+EAPI Eina_Bool
+edje_edit_part_repeat_events_get(Evas_Object *obj, const char *part)
+{
+   GET_RP_OR_RETURN(0);
+
+   //printf("Get repeat_events for part: %s [%d]\n", part, rp->part->repeat_events);
+   return rp->part->repeat_events;
+}
+
+EAPI void
+edje_edit_part_repeat_events_set(Evas_Object *obj, const char *part, Eina_Bool repeat_events)
+{
+   GET_RP_OR_RETURN();
+
+   if (!rp->object) return;
+
+   //printf("Set repeat_events for part: %s [%d]\n", part, repeat_events);
+
+   rp->part->repeat_events = repeat_events ? 1 : 0;
+
+   if (repeat_events)
+     evas_object_repeat_events_set(rp->object, 1);
+   else
+     evas_object_repeat_events_set(rp->object, 0);
+}
+
+EAPI Evas_Event_Flags
+edje_edit_part_ignore_flags_get(Evas_Object *obj, const char *part)
+{
+   GET_RP_OR_RETURN(0);
+
+   return rp->part->ignore_flags;
+}
+
+EAPI void
+edje_edit_part_ignore_flags_set(Evas_Object *obj, const char *part, Evas_Event_Flags ignore_flags)
+{
+   GET_RP_OR_RETURN();
+
+   if (!rp->object) return;
+   //printf("Set ignore_flags for part: %s [%#x]\n", part, ignore_flags);
+
+   rp->part->ignore_flags = ignore_flags;
+}
+
+EAPI const char *
+edje_edit_part_source_get(Evas_Object *obj, const char *part)
+{
+   //Edje_Real_Part *clip = NULL;
+
+   GET_RP_OR_RETURN(NULL);
+
+   //printf("Get source for part: %s\n", part);
+   if (!rp->part->source) return NULL;
+
+   return eina_stringshare_add(rp->part->source);
+}
+
+EAPI Eina_Bool
+edje_edit_part_source_set(Evas_Object *obj, const char *part, const char *source)
+{
+   GET_RP_OR_RETURN(0);
+
+   Evas_Object *child_obj;
+   //printf("Set source for part: %s [source: %s]\n", part, source);
+
+   if (rp->part->type == EDJE_PART_TYPE_EXTERNAL)
+     return 0;
+
+   _edje_if_string_free(ed, rp->part->source);
+
+   if (rp->swallowed_object)
+     {
+       _edje_real_part_swallow_clear(rp);
+       evas_object_del(rp->swallowed_object);
+       rp->swallowed_object = NULL;
+     }
+   if (source)
+     {
+       rp->part->source = eina_stringshare_add(source);
+       child_obj = edje_object_add(ed->evas);
+       edje_object_file_set(child_obj, ed->file->path, source);
+       _edje_real_part_swallow(rp, child_obj);
+     }
+   else
+     rp->part->source = NULL;
+   return 1;
+}
+
+EAPI int
+edje_edit_part_drag_x_get(Evas_Object *obj, const char *part)
+{
+   GET_RP_OR_RETURN(0);
+   //printf("Get dragX for part: %s\n", part);
+   return rp->part->dragable.x;
+}
+
+EAPI void
+edje_edit_part_drag_x_set(Evas_Object *obj, const char *part, int drag)
+{
+   GET_RP_OR_RETURN();
+   //printf("Set dragX for part: %s\n", part);
+   rp->part->dragable.x = drag;
+
+   if (!drag && !rp->part->dragable.y)
+     {
+       free(rp->drag);
+       rp->drag = NULL;
+       return ;
+     }
+
+   if (rp->drag) return;
+
+   rp->drag = _alloc(sizeof (Edje_Real_Part_Drag));
+   if (!rp->drag) return;
+
+   rp->drag->step.x = rp->part->dragable.step_x;
+   rp->drag->step.y = rp->part->dragable.step_y;
+}
+
+EAPI int
+edje_edit_part_drag_y_get(Evas_Object *obj, const char *part)
+{
+   GET_RP_OR_RETURN(0);
+   //printf("Get dragY for part: %s\n", part);
+   return rp->part->dragable.y;
+}
+
+EAPI void
+edje_edit_part_drag_y_set(Evas_Object *obj, const char *part, int drag)
+{
+   GET_RP_OR_RETURN();
+   //printf("Set dragY for part: %s\n", part);
+   rp->part->dragable.y = drag;
+
+   if (!drag && !rp->part->dragable.x)
+     {
+       free(rp->drag);
+       rp->drag = NULL;
+       return ;
+     }
+
+   if (rp->drag) return;
+
+   rp->drag = _alloc(sizeof (Edje_Real_Part_Drag));
+   if (!rp->drag) return;
+
+   rp->drag->step.x = rp->part->dragable.step_x;
+   rp->drag->step.y = rp->part->dragable.step_y;
+}
+
+EAPI int
+edje_edit_part_drag_step_x_get(Evas_Object *obj, const char *part)
+{
+   GET_RP_OR_RETURN(0);
+   //printf("Get dragX_STEP for part: %s\n", part);
+   return rp->part->dragable.step_x;
+}
+
+EAPI void
+edje_edit_part_drag_step_x_set(Evas_Object *obj, const char *part, int step)
+{
+   GET_RP_OR_RETURN();
+   //printf("Set dragX_STEP for part: %s\n", part);
+   rp->part->dragable.step_x = step;
+}
+
+EAPI int
+edje_edit_part_drag_step_y_get(Evas_Object *obj, const char *part)
+{
+   GET_RP_OR_RETURN(0);
+   //printf("Get dragY_STEP for part: %s\n", part);
+   return rp->part->dragable.step_y;
+}
+
+EAPI void
+edje_edit_part_drag_step_y_set(Evas_Object *obj, const char *part, int step)
+{
+   GET_RP_OR_RETURN();
+   //printf("Set dragY_STEP for part: %s\n", part);
+   rp->part->dragable.step_y = step;
+}
+
+EAPI int
+edje_edit_part_drag_count_x_get(Evas_Object *obj, const char *part)
+{
+   GET_RP_OR_RETURN(0);
+   //printf("Get dragX_COUNT for part: %s\n", part);
+   return rp->part->dragable.count_x;
+}
+
+EAPI void
+edje_edit_part_drag_count_x_set(Evas_Object *obj, const char *part, int count)
+{
+   GET_RP_OR_RETURN();
+   //printf("Set dragX_COUNT for part: %s\n", part);
+   rp->part->dragable.count_x = count;
+}
+
+EAPI int
+edje_edit_part_drag_count_y_get(Evas_Object *obj, const char *part)
+{
+   GET_RP_OR_RETURN(0);
+   //printf("Get dragY_COUNT for part: %s\n", part);
+   return rp->part->dragable.count_y;
+}
+
+EAPI void
+edje_edit_part_drag_count_y_set(Evas_Object *obj, const char *part, int count)
+{
+   GET_RP_OR_RETURN();
+   //printf("Set dragY_COUNT for part: %s\n", part);
+   rp->part->dragable.count_y = count;
+}
+
+EAPI const char*
+edje_edit_part_drag_confine_get(Evas_Object *obj, const char *part)
+{
+   Edje_Real_Part *confine;
+   //printf("******Get drag confine\n");
+   GET_RP_OR_RETURN(NULL);
+
+   if (rp->part->dragable.confine_id < 0)
+      return NULL;
+
+   confine = ed->table_parts[rp->part->dragable.confine_id];
+   return eina_stringshare_add(confine->part->name);
+}
+
+EAPI void
+edje_edit_part_drag_confine_set(Evas_Object *obj, const char *part, const char *confine)
+{
+   Edje_Real_Part *confine_part;
+   //printf("******Set drag confine to: %s\n", confine);
+   GET_RP_OR_RETURN();
+
+   if (!confine)
+     {
+      rp->part->dragable.confine_id = -1;
+      return;
+     }
+
+   confine_part = _edje_real_part_get(ed, confine);
+   rp->part->dragable.confine_id = confine_part->part->id;
+}
+
+EAPI const char*
+edje_edit_part_drag_event_get(Evas_Object *obj, const char *part)
+{
+   Edje_Real_Part *events;
+   //printf("******Get drag event part\n");
+   GET_RP_OR_RETURN(NULL);
+
+   if (rp->part->dragable.events_id < 0)
+      return NULL;
+
+   events = ed->table_parts[rp->part->dragable.events_id];
+   return eina_stringshare_add(events->part->name);
+}
+
+EAPI void
+edje_edit_part_drag_event_set(Evas_Object *obj, const char *part, const char *event)
+{
+   Edje_Real_Part *event_part;
+   //printf("******Set drag event to: %s\n", event);
+   GET_RP_OR_RETURN();
+
+   if (!event)
+     {
+      rp->part->dragable.events_id = -1;
+      return;
+     }
+
+   event_part = _edje_real_part_get(ed, event);
+   rp->part->dragable.events_id = event_part->part->id;
+}
+/*********************/
+/*  PART STATES API  */
+/*********************/
+EAPI Eina_List *
+edje_edit_part_states_list_get(Evas_Object *obj, const char *part)
+{
+   char state_name[PATH_MAX];
+   Eina_List *states = NULL;
+   Eina_List *l;
+   Edje_Part_Description *state;
+
+   GET_RP_OR_RETURN(NULL);
+
+   //Is there a better place to put this? maybe edje_edit_init() ?
+#ifdef HAVE_LOCALE_H
+   setlocale(LC_NUMERIC, "C");
+#endif
+
+   states = NULL;
+
+   //append default state
+   state = rp->part->default_desc;
+   snprintf(state_name, PATH_MAX,
+            "%s %.2f", state->state.name, state->state.value);
+   states = eina_list_append(states, eina_stringshare_add(state_name));
+   //printf("NEW STATE def: %s\n", state->state.name);
+
+   //append other states
+   EINA_LIST_FOREACH(rp->part->other_desc, l, state)
+     {
+       snprintf(state_name, sizeof(state_name),
+                "%s %.2f", state->state.name, state->state.value);
+       states = eina_list_append(states, eina_stringshare_add(state_name));
+       //printf("NEW STATE: %s\n", state_name);
+     }
+   return states;
+}
+
+EAPI Eina_Bool
+edje_edit_state_name_set(Evas_Object *obj, const char *part, const char *state, double value, const char *new_name, double new_value)
+{
+   int part_id;
+   int i;
+
+   GET_PD_OR_RETURN(0);
+   //printf("Set name of state: %s in part: %s [new name: %s]\n",
+     //     part, state, new_name);
+
+   if (!new_name) return EINA_FALSE;
+
+   /* update programs */
+   /* update the 'state' field in all programs. update only if program has
+      a single target */
+   part_id = _edje_part_id_find(ed, part);
+   for (i = 0; i < ed->table_programs_size; i++)
+     {
+       Edje_Program *epr = ed->table_programs[i];
+
+       if (eina_list_count(epr->targets) == 1)
+         {
+            Edje_Program_Target *t = eina_list_data_get(epr->targets);
+
+            if (t->id == part_id &&
+                !strcmp(epr->state, pd->state.name) &&
+                pd->state.value == epr->value)
+              {
+                 _edje_if_string_free(ed, epr->state);
+                 epr->state = eina_stringshare_add(new_name);
+                 epr->value = value;
+              }
+         }
+     }
+
+   /* set name */
+   _edje_if_string_free(ed, pd->state.name);
+   pd->state.name = (char *)eina_stringshare_add(new_name);
+   /* set value */
+   pd->state.value = new_value;
+
+   return EINA_TRUE;
+}
+
+EAPI void
+edje_edit_state_del(Evas_Object *obj, const char *part, const char *state, double value)
+{
+   Edje_Part_Description *pd;
+
+   GET_RP_OR_RETURN();
+
+   pd = _edje_part_description_find_byname(eed, part, state, value);
+   if (!pd) return;
+
+   /* Don't allow to delete default state, for now at least; */
+   if (pd == rp->part->default_desc)
+     return;
+
+   /* And if we are deleting the current state, go back to default first */
+   if (pd == rp->chosen_description)
+     _edje_part_description_apply(ed, rp, "default", 0.0, NULL, 0.0);
+
+   rp->part->other_desc = eina_list_remove(rp->part->other_desc, pd);
+
+   _edje_collection_free_part_description_free(pd, 0);
+}
+
+EAPI void
+edje_edit_state_add(Evas_Object *obj, const char *part, const char *name, double value)
+{
+   Edje_Part_Description *pd;
+
+   GET_RP_OR_RETURN();
+
+   //printf("ADD STATE: %s TO PART: %s\n", name , part);
+
+   pd = _alloc(sizeof(Edje_Part_Description));
+   if (!pd) return;
+
+   if (!rp->part->default_desc)
+     rp->part->default_desc = pd;
+   else
+     rp->part->other_desc = eina_list_append(rp->part->other_desc, pd);
+
+   pd->state.name = eina_stringshare_add(name);
+   pd->state.value = value;
+   pd->visible = 1;
+   pd->align.x = 0.5;
+   pd->align.y = 0.5;
+   pd->min.w = 0;
+   pd->min.h = 0;
+   pd->fixed.w = 0;
+   pd->fixed.h = 0;
+   pd->max.w = -1;
+   pd->max.h = -1;
+   pd->rel1.relative_x = 0.0;
+   pd->rel1.relative_y = 0.0;
+   pd->rel1.offset_x = 0;
+   pd->rel1.offset_y = 0;
+   pd->rel1.id_x = -1;
+   pd->rel1.id_y = -1;
+   pd->rel2.relative_x = 1.0;
+   pd->rel2.relative_y = 1.0;
+   pd->rel2.offset_x = -1;
+   pd->rel2.offset_y = -1;
+   pd->rel2.id_x = -1;
+   pd->rel2.id_y = -1;
+   pd->image.id = -1;
+   pd->fill.smooth = 1;
+   pd->fill.pos_rel_x = 0.0;
+   pd->fill.pos_abs_x = 0;
+   pd->fill.rel_x = 1.0;
+   pd->fill.abs_x = 0;
+   pd->fill.pos_rel_y = 0.0;
+   pd->fill.pos_abs_y = 0;
+   pd->fill.rel_y = 1.0;
+   pd->fill.abs_y = 0;
+   pd->fill.angle = 0;
+   pd->fill.spread = 0;
+   pd->fill.type = EDJE_FILL_TYPE_SCALE;
+   pd->color_class = NULL;
+   pd->color.r = 255;
+   pd->color.g = 255;
+   pd->color.b = 255;
+   pd->color.a = 255;
+   pd->color2.r = 0;
+   pd->color2.g = 0;
+   pd->color2.b = 0;
+   pd->color2.a = 255;
+   pd->color3.r = 0;
+   pd->color3.g = 0;
+   pd->color3.b = 0;
+   pd->color3.a = 128;
+   pd->text.align.x = 0.5;
+   pd->text.align.y = 0.5;
+   pd->text.id_source = -1;
+   pd->text.id_text_source = -1;
+   pd->gradient.rel1.relative_x = 0;
+   pd->gradient.rel1.relative_y = 0;
+   pd->gradient.rel1.offset_x = 0;
+   pd->gradient.rel1.offset_y = 0;
+   pd->gradient.rel2.relative_x = 1;
+   pd->gradient.rel2.relative_y = 1;
+   pd->gradient.rel2.offset_x = -1;
+   pd->gradient.rel2.offset_y = -1;
+   pd->gradient.use_rel = 1;
+
+   if ((rp->part->type == EDJE_PART_TYPE_EXTERNAL) && (rp->part->source))
+     {
+       Edje_External_Param_Info *pi;
+
+       pi = (Edje_External_Param_Info *)edje_external_param_info_get(rp->part->source);
+       while (pi && pi->name)
+         {
+            Edje_External_Param *p;
+            p = _alloc(sizeof(Edje_External_Param));
+            /* error checking.. meh */
+            p->name = eina_stringshare_add(pi->name);
+            p->type = pi->type;
+            switch(p->type)
+              {
+               case EDJE_EXTERNAL_PARAM_TYPE_INT:
+               case EDJE_EXTERNAL_PARAM_TYPE_BOOL:
+                  if (pi->info.i.def != EDJE_EXTERNAL_INT_UNSET)
+                    p->i = pi->info.i.def;
+                  break;
+               case EDJE_EXTERNAL_PARAM_TYPE_DOUBLE:
+                  if (pi->info.d.def != EDJE_EXTERNAL_DOUBLE_UNSET)
+                    p->d = pi->info.d.def;
+                  break;
+               case EDJE_EXTERNAL_PARAM_TYPE_CHOICE:
+                  if (pi->info.c.def)
+                    p->s = eina_stringshare_add(pi->info.c.def);
+                  break;
+               case EDJE_EXTERNAL_PARAM_TYPE_STRING:
+                  if (pi->info.s.def)
+                    p->s = eina_stringshare_add(pi->info.s.def);
+                  break;
+               default:
+                  ERR("unknown external parameter type '%d'", p->type);
+              }
+            pd->external_params = eina_list_append(pd->external_params, p);
+            pi++;
+         }
+       if (pd->external_params)
+         rp->param1.external_params = _edje_external_params_parse(rp->swallowed_object, pd->external_params);
+     }
+}
+
+EAPI Eina_Bool
+edje_edit_state_exist(Evas_Object *obj, const char *part, const char *state, double value)
+{
+   GET_PD_OR_RETURN(0);
+   return 1;
+}
+
+EAPI Eina_Bool
+edje_edit_state_copy(Evas_Object *obj, const char *part, const char *from, double val_from, const char *to, double val_to)
+{
+   Edje_Part_Description *pdfrom, *pdto;
+   Edje_Part_Image_Id *i;
+   Edje_External_Param *p;
+   Eina_List *l;
+   GET_RP_OR_RETURN(0);
+
+   pdfrom = _edje_part_description_find_byname(eed, part, from, val_from);
+   if (!pdfrom)
+     return 0;
+
+   pdto = _edje_part_description_find_byname(eed, part, to, val_to);
+   if (!pdto)
+     {
+       pdto = _alloc(sizeof(Edje_Part_Description));
+       if (!pdto)
+         return 0;
+       /* No need to check for default desc, at this point it must exist */
+       rp->part->other_desc = eina_list_append(rp->part->other_desc, pdto);
+       pdto->state.name = eina_stringshare_add(to);
+       pdto->state.value = val_to;
+     }
+
+#define PD_COPY(_x) pdto->_x = pdfrom->_x
+#define PD_STRING_COPY(_x) _edje_if_string_free(ed, pdto->_x); \
+                          pdto->_x = (char *)eina_stringshare_add(pdfrom->_x)
+   PD_COPY(align.x);
+   PD_COPY(align.y);
+   PD_COPY(fixed.w);
+   PD_COPY(fixed.h);
+   PD_COPY(min.w);
+   PD_COPY(min.h);
+   PD_COPY(max.w);
+   PD_COPY(max.h);
+   PD_COPY(aspect.min);
+   PD_COPY(aspect.max);
+   PD_COPY(aspect.prefer);
+   PD_COPY(rel1.relative_x);
+   PD_COPY(rel1.relative_y);
+   PD_COPY(rel1.offset_x);
+   PD_COPY(rel1.offset_y);
+   PD_COPY(rel1.id_x);
+   PD_COPY(rel1.id_y);
+   PD_COPY(rel2.relative_x);
+   PD_COPY(rel2.relative_y);
+   PD_COPY(rel2.offset_x);
+   PD_COPY(rel2.offset_y);
+   PD_COPY(rel2.id_x);
+   PD_COPY(rel2.id_y);
+   PD_COPY(image.id);
+   EINA_LIST_FREE(pdto->image.tween_list, i)
+      free(i);
+   EINA_LIST_FOREACH(pdfrom->image.tween_list, l, i)
+     {
+       Edje_Part_Image_Id *new_i;
+       new_i = _alloc(sizeof(Edje_Part_Image_Id));
+       /* error checking? What to do if failed? Rollback, abort? */
+       new_i->id = i->id;
+       pdto->image.tween_list = eina_list_append(pdto->image.tween_list, new_i);
+     }
+   PD_STRING_COPY(gradient.type);
+   PD_STRING_COPY(gradient.params);
+   PD_COPY(gradient.id);
+   PD_COPY(gradient.use_rel);
+   PD_COPY(gradient.rel1.relative_x);
+   PD_COPY(gradient.rel1.relative_y);
+   PD_COPY(gradient.rel1.offset_x);
+   PD_COPY(gradient.rel1.offset_y);
+   PD_COPY(gradient.rel2.relative_x);
+   PD_COPY(gradient.rel2.relative_y);
+   PD_COPY(gradient.rel2.offset_x);
+   PD_COPY(gradient.rel2.offset_y);
+   PD_COPY(border.l);
+   PD_COPY(border.r);
+   PD_COPY(border.t);
+   PD_COPY(border.b);
+   PD_COPY(border.no_fill);
+   PD_COPY(fill.pos_rel_x);
+   PD_COPY(fill.rel_x);
+   PD_COPY(fill.pos_rel_y);
+   PD_COPY(fill.rel_y);
+   PD_COPY(fill.pos_abs_x);
+   PD_COPY(fill.abs_x);
+   PD_COPY(fill.pos_abs_y);
+   PD_COPY(fill.abs_y);
+   PD_COPY(fill.angle);
+   PD_COPY(fill.spread);
+   PD_COPY(fill.smooth);
+   PD_COPY(fill.type);
+   PD_STRING_COPY(color_class);
+   PD_STRING_COPY(text.text);
+   PD_STRING_COPY(text.text_class);
+   PD_STRING_COPY(text.style);
+   PD_STRING_COPY(text.font);
+   PD_STRING_COPY(text.repch);
+   PD_COPY(text.align.x);
+   PD_COPY(text.align.y);
+   PD_COPY(text.elipsis);
+   PD_COPY(text.size);
+   PD_COPY(text.id_source);
+   PD_COPY(text.id_text_source);
+   PD_COPY(text.fit_x);
+   PD_COPY(text.fit_y);
+   PD_COPY(text.min_x);
+   PD_COPY(text.min_y);
+   PD_COPY(text.max_x);
+   PD_COPY(text.max_y);
+   PD_STRING_COPY(box.layout);
+   PD_STRING_COPY(box.alt_layout);
+   PD_COPY(box.align.x);
+   PD_COPY(box.align.y);
+   PD_COPY(box.padding.x);
+   PD_COPY(box.padding.y);
+   PD_COPY(box.min.h);
+   PD_COPY(box.min.v);
+   PD_COPY(table.homogeneous);
+   PD_COPY(table.align.x);
+   PD_COPY(table.align.y);
+   PD_COPY(table.padding.x);
+   PD_COPY(table.padding.y);
+   PD_COPY(color.r);
+   PD_COPY(color.g);
+   PD_COPY(color.b);
+   PD_COPY(color.a);
+   PD_COPY(color2.r);
+   PD_COPY(color2.g);
+   PD_COPY(color2.b);
+   PD_COPY(color2.a);
+   PD_COPY(color3.r);
+   PD_COPY(color3.g);
+   PD_COPY(color3.b);
+   PD_COPY(color3.a);
+   /* XXX: optimize this, most likely we don't need to remove and add */
+   EINA_LIST_FREE(pdto->external_params, p)
+     {
+       _edje_if_string_free(ed, p->name);
+       if (p->s)
+         _edje_if_string_free(ed, p->s);
+       free(p);
+     }
+   EINA_LIST_FOREACH(pdfrom->external_params, l, p)
+     {
+       Edje_External_Param *new_p;
+       new_p = _alloc(sizeof(Edje_External_Param));
+       new_p->name = eina_stringshare_add(p->name);
+       new_p->type = p->type;
+       switch (p->type)
+         {
+          case EDJE_EXTERNAL_PARAM_TYPE_INT:
+             new_p->i = p->i;
+             break;
+          case EDJE_EXTERNAL_PARAM_TYPE_DOUBLE:
+             new_p->d = p->d;
+             break;
+          case EDJE_EXTERNAL_PARAM_TYPE_CHOICE:
+          case EDJE_EXTERNAL_PARAM_TYPE_STRING:
+             new_p->s = eina_stringshare_add(p->s);
+             break;
+          default:
+             break;
+         }
+       pdto->external_params = eina_list_append(pdto->external_params, new_p);
+     }
+   PD_COPY(visible);
+#undef PD_STRING_COPY
+#undef PD_COPY
+
+   return 1;
+}
+
+//relative
+EAPI double
+edje_edit_state_rel1_relative_x_get(Evas_Object *obj, const char *part, const char *state, double value)
+{
+   GET_PD_OR_RETURN(0);
+   //printf("Get rel1 rel of part: %s state: %s [%f]\n", part, state, pd->rel1.relative_x);
+   return TO_DOUBLE(pd->rel1.relative_x);
+}
+
+EAPI double
+edje_edit_state_rel1_relative_y_get(Evas_Object *obj, const char *part, const char *state, double value)
+{
+   GET_PD_OR_RETURN(0);
+   //printf("Get rel1 rel of part: %s state: %s\n", part, state);
+   return TO_DOUBLE(pd->rel1.relative_y);
+}
+
+EAPI double
+edje_edit_state_rel2_relative_x_get(Evas_Object *obj, const char *part, const char *state, double value)
+{
+   GET_PD_OR_RETURN(0);
+   //printf("Get rel2 rel of part: %s state: %s\n", part, state);
+   return TO_DOUBLE(pd->rel2.relative_x);
+}
+
+EAPI double
+edje_edit_state_rel2_relative_y_get(Evas_Object *obj, const char *part, const char *state, double value)
+{
+   GET_PD_OR_RETURN(0);
+   //printf("Get rel2 rel of part: %s state: %s\n", part, state);
+   return TO_DOUBLE(pd->rel2.relative_y);
+}
+
+EAPI void
+edje_edit_state_rel1_relative_x_set(Evas_Object *obj, const char *part, const char *state, double value, double x)
+{
+   GET_PD_OR_RETURN();
+   //printf("Set rel1x of part: %s state: %s to: %f\n", part, state, x);
+   //TODO check boudaries
+   pd->rel1.relative_x = FROM_DOUBLE(x);
+   edje_object_calc_force(obj);
+}
+
+EAPI void
+edje_edit_state_rel1_relative_y_set(Evas_Object *obj, const char *part, const char *state, double value, double y)
+{
+   GET_PD_OR_RETURN();
+   //printf("Set rel1y of part: %s state: %s to: %f\n", part, state, y);
+   //TODO check boudaries
+   pd->rel1.relative_y = FROM_DOUBLE(y);
+   edje_object_calc_force(obj);
+}
+
+EAPI void
+edje_edit_state_rel2_relative_x_set(Evas_Object *obj, const char *part, const char *state, double value, double x)
+{
+   GET_PD_OR_RETURN();
+   //printf("Set rel2x of part: %s state: %s to: %f\n", part, state, x);
+   //TODO check boudaries
+   pd->rel2.relative_x = FROM_DOUBLE(x);
+   edje_object_calc_force(obj);
+}
+
+EAPI void
+edje_edit_state_rel2_relative_y_set(Evas_Object *obj, const char *part, const char *state, double value, double y)
+{
+   GET_PD_OR_RETURN();
+   //printf("Set rel2y of part: %s state: %s to: %f\n", part, state, y);
+   pd = _edje_part_description_find_byname(eed, part, state, value);
+   //TODO check boudaries
+   pd->rel2.relative_y = FROM_DOUBLE(y);
+   edje_object_calc_force(obj);
+}
+
+//offset
+EAPI int
+edje_edit_state_rel1_offset_x_get(Evas_Object *obj, const char *part, const char *state, double value)
+{
+   GET_PD_OR_RETURN(0);
+   //printf("Get rel1 offset of part: %s state: %s\n", part, state);
+   return pd->rel1.offset_x;
+}
+
+EAPI int
+edje_edit_state_rel1_offset_y_get(Evas_Object *obj, const char *part, const char *state, double value)
+{
+   GET_PD_OR_RETURN(0);
+   //printf("Get rel1 offset of part: %s state: %s\n", part, state);
+   return pd->rel1.offset_y;
+}
+
+EAPI int
+edje_edit_state_rel2_offset_x_get(Evas_Object *obj, const char *part, const char *state, double value)
+{
+   GET_PD_OR_RETURN(0);
+   //printf("Get rel2 offset of part: %s state: %s\n", part, state);
+   return pd->rel2.offset_x;
+}
+
+EAPI int
+edje_edit_state_rel2_offset_y_get(Evas_Object *obj, const char *part, const char *state, double value)
+{
+   GET_PD_OR_RETURN(0);
+   //printf("Get rel2 offset of part: %s state: %s\n", part, state);
+   return pd->rel2.offset_y;
+}
+
+EAPI void
+edje_edit_state_rel1_offset_x_set(Evas_Object *obj, const char *part, const char *state, double value, double x)
+{
+   GET_PD_OR_RETURN();
+   //printf("Set rel1x offset of part: %s state: %s to: %f\n", part, state, x);
+   //TODO check boudaries
+   pd->rel1.offset_x = TO_INT(FROM_DOUBLE(x));
+   edje_object_calc_force(obj);
+}
+
+EAPI void
+edje_edit_state_rel1_offset_y_set(Evas_Object *obj, const char *part, const char *state, double value, double y)
+{
+   GET_PD_OR_RETURN();
+   //printf("Set rel1y offset of part: %s state: %s to: %f\n", part, state, y);
+   //TODO check boudaries
+   pd->rel1.offset_y = TO_INT(FROM_DOUBLE(y));
+   edje_object_calc_force(obj);
+}
+
+EAPI void
+edje_edit_state_rel2_offset_x_set(Evas_Object *obj, const char *part, const char *state, double value, double x)
+{
+   GET_PD_OR_RETURN();
+   //printf("Set rel2x offset of part: %s state: %s to: %f\n", part, state, x);
+   //TODO check boudaries
+   pd->rel2.offset_x = TO_INT(FROM_DOUBLE(x));
+   edje_object_calc_force(obj);
+}
+
+EAPI void
+edje_edit_state_rel2_offset_y_set(Evas_Object *obj, const char *part, const char *state, double value, double y)
+{
+   GET_PD_OR_RETURN();
+   //printf("Set rel2y offset of part: %s state: %s to: %f\n", part, state, y);
+   //TODO check boudaries
+   pd->rel2.offset_y = TO_INT(FROM_DOUBLE(y));
+   edje_object_calc_force(obj);
+}
+
+//relative to
+EAPI const char *
+edje_edit_state_rel1_to_x_get(Evas_Object *obj, const char *part, const char *state, double value)
+{
+   Edje_Real_Part *rel;
+
+   GET_PD_OR_RETURN(NULL);
+
+   //printf("Get rel1x TO of part: %s state: %s\n", part, state);
+
+   if (pd->rel1.id_x == -1) return NULL;
+
+   rel = ed->table_parts[pd->rel1.id_x % ed->table_parts_size];
+
+   if (rel->part->name)
+     return eina_stringshare_add(rel->part->name);
+   else
+     return NULL;
+}
+
+EAPI const char *
+edje_edit_state_rel1_to_y_get(Evas_Object *obj, const char *part, const char *state, double value)
+{
+   Edje_Real_Part *rel;
+
+   GET_PD_OR_RETURN(NULL);
+
+   //printf("Get rel1y TO of part: %s state: %s\n", part, state);
+
+   if (pd->rel1.id_y == -1) return NULL;
+
+   rel = ed->table_parts[pd->rel1.id_y % ed->table_parts_size];
+
+   if (rel->part->name)
+     return eina_stringshare_add(rel->part->name);
+   else
+     return NULL;
+}
+
+EAPI const char *
+edje_edit_state_rel2_to_x_get(Evas_Object *obj, const char *part, const char *state, double value)
+{
+   Edje_Real_Part *rel;
+
+   GET_PD_OR_RETURN(NULL);
+
+   //printf("Get rel2x TO of part: %s state: %s\n", part, state);
+
+   if (pd->rel2.id_x == -1) return NULL;
+
+   rel = ed->table_parts[pd->rel2.id_x % ed->table_parts_size];
+
+   if (rel->part->name)
+     return eina_stringshare_add(rel->part->name);
+   else
+     return NULL;
+}
+
+EAPI const char *
+edje_edit_state_rel2_to_y_get(Evas_Object *obj, const char *part, const char *state, double value)
+{
+   Edje_Real_Part *rel;
+
+   GET_PD_OR_RETURN(NULL);
+
+   //printf("Get rel2y TO of part: %s state: %s\n", part, state);
+
+   if (pd->rel2.id_y == -1) return NULL;
+
+   rel = ed->table_parts[pd->rel2.id_y % ed->table_parts_size];
+
+   if (rel->part->name)
+     return eina_stringshare_add(rel->part->name);
+   else
+     return NULL;
+}
+
+EAPI void
+//note after this call edje_edit_part_selected_state_set() to update !! need to fix this
+edje_edit_state_rel1_to_x_set(Evas_Object *obj, const char *part, const char *state, double value, const char *rel_to)
+{
+   Edje_Real_Part *relp;
+
+   GET_PD_OR_RETURN();
+
+   //printf("Set rel1 to x on state: %s (to part: )\n", state);
+
+   if (rel_to)
+     {
+       relp = _edje_real_part_get(ed, rel_to);
+       if (!relp) return;
+       pd->rel1.id_x = relp->part->id;
+     }
+   else
+     pd->rel1.id_x = -1;
+
+   //_edje_part_description_apply(ed, rp, pd->state.name, pd->state.value, "state", 0.1); //Why segfault??
+   // edje_object_calc_force(obj);//don't work for redraw
+}
+
+EAPI void
+//note after this call edje_edit_part_selected_state_set() to update !! need to fix this
+edje_edit_state_rel1_to_y_set(Evas_Object *obj, const char *part, const char *state, double value, const char *rel_to)
+{
+   Edje_Real_Part *relp;
+
+   GET_PD_OR_RETURN();
+
+   //printf("Set rel1 to y on state: %s (to part: %s)\n", state, rel_to);
+
+   if (rel_to)
+     {
+       relp = _edje_real_part_get(ed, rel_to);
+       if (!relp) return;
+       pd->rel1.id_y = relp->part->id;
+     }
+   else
+     pd->rel1.id_y = -1;
+
+   //_edje_part_description_apply(ed, rp, pd->state.name, pd->state.value, "state", 0.1); //Why segfault??
+   // edje_object_calc_force(obj);//don't work for redraw
+}
+
+EAPI void
+//note after this call edje_edit_part_selected_state_set() to update !! need to fix this
+edje_edit_state_rel2_to_x_set(Evas_Object *obj, const char *part, const char *state, double value, const char *rel_to)
+{
+   Edje_Real_Part *relp;
+
+   GET_PD_OR_RETURN();
+
+   //printf("Set rel2 to x on state: %s (to part: )\n", state);
+
+   if (rel_to)
+     {
+       relp = _edje_real_part_get(ed, rel_to);
+       if (!relp) return;
+       pd->rel2.id_x = relp->part->id;
+     }
+   else
+     pd->rel2.id_x = -1;
+
+   //_edje_part_description_apply(ed, rp, pd->state.name, pd->state.value, "state", 0.1); //Why segfault??
+   // edje_object_calc_force(obj);//don't work for redraw
+}
+
+EAPI void
+//note after this call edje_edit_part_selected_state_set() to update !! need to fix this
+edje_edit_state_rel2_to_y_set(Evas_Object *obj, const char *part, const char *state, double value, const char *rel_to)
+{
+   Edje_Real_Part *relp;
+
+   GET_PD_OR_RETURN();
+
+   //printf("Set rel2 to y on state: %s (to part: %s)\n", state, rel_to);
+
+   if (rel_to)
+     {
+       relp = _edje_real_part_get(ed, rel_to);
+       if (!relp) return;
+       pd->rel2.id_y = relp->part->id;
+     }
+   else
+      pd->rel2.id_y = -1;
+
+   //_edje_part_description_apply(ed, rp, pd->state.name, pd->state.value, "state", 0.1); //Why segfault??
+   // edje_object_calc_force(obj);//don't work for redraw
+}
+
+//colors
+EAPI void
+edje_edit_state_color_get(Evas_Object *obj, const char *part, const char *state, double value, int *r, int *g, int *b, int *a)
+{
+   GET_PD_OR_RETURN();
+
+   //printf("GET COLOR of state '%s'\n", state);
+
+   if (r) *r = pd->color.r;
+   if (g) *g = pd->color.g;
+   if (b) *b = pd->color.b;
+   if (a) *a = pd->color.a;
+}
+
+EAPI void
+edje_edit_state_color2_get(Evas_Object *obj, const char *part, const char *state, double value, int *r, int *g, int *b, int *a)
+{
+   GET_PD_OR_RETURN();
+
+   //printf("GET COLOR2 of state '%s'\n", state);
+
+   if (r) *r = pd->color2.r;
+   if (g) *g = pd->color2.g;
+   if (b) *b = pd->color2.b;
+   if (a) *a = pd->color2.a;
+}
+
+EAPI void
+edje_edit_state_color3_get(Evas_Object *obj, const char *part, const char *state, double value, int *r, int *g, int *b, int *a)
+{
+   GET_PD_OR_RETURN();
+
+   //printf("GET COLOR3 of state '%s'\n", state);
+
+   if (r) *r = pd->color3.r;
+   if (g) *g = pd->color3.g;
+   if (b) *b = pd->color3.b;
+   if (a) *a = pd->color3.a;
+}
+
+EAPI void
+edje_edit_state_color_set(Evas_Object *obj, const char *part, const char *state, double value, int r, int g, int b, int a)
+{
+   GET_PD_OR_RETURN();
+
+   //printf("SET COLOR of state '%s'\n", state);
+
+   if (r > -1 && r < 256) pd->color.r = r;
+   if (g > -1 && g < 256) pd->color.g = g;
+   if (b > -1 && b < 256) pd->color.b = b;
+   if (a > -1 && a < 256) pd->color.a = a;
+
+   edje_object_calc_force(obj);
+}
+
+EAPI void
+edje_edit_state_color2_set(Evas_Object *obj, const char *part, const char *state, double value, int r, int g, int b, int a)
+{
+   GET_PD_OR_RETURN();
+
+   //printf("SET COLOR2 of state '%s'\n", state);
+
+   if (r > -1 && r < 256) pd->color2.r = r;
+   if (g > -1 && g < 256) pd->color2.g = g;
+   if (b > -1 && b < 256) pd->color2.b = b;
+   if (a > -1 && a < 256) pd->color2.a = a;
+
+   edje_object_calc_force(obj);
+}
+
+EAPI void
+edje_edit_state_color3_set(Evas_Object *obj, const char *part, const char *state, double value, int r, int g, int b, int a)
+{
+   GET_PD_OR_RETURN();
+
+   //printf("SET COLOR3 of state '%s'\n", state);
+
+   if (r > -1 && r < 256) pd->color3.r = r;
+   if (g > -1 && g < 256) pd->color3.g = g;
+   if (b > -1 && b < 256) pd->color3.b = b;
+   if (a > -1 && a < 256) pd->color3.a = a;
+
+   edje_object_calc_force(obj);
+}
+
+//align
+EAPI double
+edje_edit_state_align_x_get(Evas_Object *obj, const char *part, const char *state, double value)
+{
+   GET_PD_OR_RETURN(0);
+
+   //printf("GET ALIGN_X of state '%s' [%f]\n", state, pd->align.x);
+
+   return TO_DOUBLE(pd->align.x);
+}
+
+EAPI double
+edje_edit_state_align_y_get(Evas_Object *obj, const char *part, const char *state, double value)
+{
+   GET_PD_OR_RETURN(0);
+
+   //printf("GET ALIGN_Y of state '%s' [%f]\n", state, pd->align.y);
+
+   return TO_DOUBLE(pd->align.y);
+}
+
+EAPI void
+edje_edit_state_align_x_set(Evas_Object *obj, const char *part, const char *state, double value, double align)
+{
+   GET_PD_OR_RETURN();
+   //printf("SET ALIGN_X of state '%s' [to: %f]\n", state, align);
+   pd->align.x = FROM_DOUBLE(align);
+}
+
+EAPI void
+edje_edit_state_align_y_set(Evas_Object *obj, const char *part, const char *state, double value, double align)
+{
+   GET_PD_OR_RETURN();
+
+   //printf("SET ALIGN_Y of state '%s' [to: %f]\n", state, align);
+   pd->align.y = FROM_DOUBLE(align);
+}
+
+//min & max
+EAPI int
+edje_edit_state_min_w_get(Evas_Object *obj, const char *part, const char *state, double value)
+{
+   GET_PD_OR_RETURN(0);
+
+   //printf("GET MIN_W of state '%s' [%d]\n", state, pd->min.w);
+   return pd->min.w;
+}
+
+EAPI void
+edje_edit_state_min_w_set(Evas_Object *obj, const char *part, const char *state, double value, int min_w)
+{
+   GET_PD_OR_RETURN();
+
+   //printf("SET MIN_W of state '%s' [to: %d]\n", state, min_w);
+   pd->min.w = min_w;
+}
+
+EAPI int
+edje_edit_state_min_h_get(Evas_Object *obj, const char *part, const char *state, double value)
+{
+   GET_PD_OR_RETURN(0);
+
+   //printf("GET MIN_H of state '%s' [%d]\n", state, pd->min.h);
+   return pd->min.h;
+}
+
+EAPI void
+edje_edit_state_min_h_set(Evas_Object *obj, const char *part, const char *state, double value, int min_h)
+{
+   GET_PD_OR_RETURN();
+
+   //printf("SET MIN_H of state '%s' [to: %d]\n", state, min_h);
+   pd->min.h = min_h;
+}
+
+EAPI int
+edje_edit_state_max_w_get(Evas_Object *obj, const char *part, const char *state, double value)
+{
+   GET_PD_OR_RETURN(0);
+
+   //printf("GET MAX_W of state '%s' [%d]\n", state, pd->max.w);
+   return pd->max.w;
+}
+
+EAPI void
+edje_edit_state_max_w_set(Evas_Object *obj, const char *part, const char *state, double value, int max_w)
+{
+   GET_PD_OR_RETURN();
+
+   //printf("SET MAX_W of state '%s' [to: %d]\n", state, max_w);
+   pd->max.w = max_w;
+}
+
+EAPI int
+edje_edit_state_max_h_get(Evas_Object *obj, const char *part, const char *state, double value)
+{
+   GET_PD_OR_RETURN(0);
+
+   //printf("GET MAX_H of state '%s' [%d]\n", state, pd->max.h);
+   return pd->max.h;
+}
+
+EAPI void
+edje_edit_state_max_h_set(Evas_Object *obj, const char *part, const char *state, double value, int max_h)
+{
+   GET_PD_OR_RETURN();
+
+   //printf("SET MAX_H of state '%s' [to: %d]\n", state, max_h);
+   pd->max.h = max_h;
+}
+
+//aspect
+EAPI double
+edje_edit_state_aspect_min_get(Evas_Object *obj, const char *part, const char *state, double value)
+{
+   GET_PD_OR_RETURN(0);
+
+   //printf("GET ASPECT_MIN of state '%s' [%f]\n", state, pd->aspect.min);
+   return TO_DOUBLE(pd->aspect.min);
+}
+
+EAPI double
+edje_edit_state_aspect_max_get(Evas_Object *obj, const char *part, const char *state, double value)
+{
+   GET_PD_OR_RETURN(0);
+
+   //printf("GET ASPECT_MAX of state '%s' [%f]\n", state, pd->aspect.max);
+   return TO_DOUBLE(pd->aspect.max);
+}
+
+EAPI void
+edje_edit_state_aspect_min_set(Evas_Object *obj, const char *part, const char *state, double value, double aspect)
+{
+   GET_PD_OR_RETURN();
+
+   //printf("SET ASPECT_MIN of state '%s' [to: %f]\n", state, aspect);
+   pd->aspect.min = FROM_DOUBLE(aspect);
+}
+
+EAPI void
+edje_edit_state_aspect_max_set(Evas_Object *obj, const char *part, const char *state, double value, double aspect)
+{
+   GET_PD_OR_RETURN();
+
+   //printf("SET ASPECT_MAX of state '%s' [to: %f]\n", state, aspect);
+   pd->aspect.max = FROM_DOUBLE(aspect);
+}
+
+EAPI unsigned char
+edje_edit_state_aspect_pref_get(Evas_Object *obj, const char *part, const char *state, double value)
+{
+   GET_PD_OR_RETURN(0);
+
+   //printf("GET ASPECT_PREF of state '%s' [%d]\n", state, pd->aspect.prefer);
+   return pd->aspect.prefer;
+}
+
+EAPI void
+edje_edit_state_aspect_pref_set(Evas_Object *obj, const char *part, const char *state, double value, unsigned char pref)
+{
+   GET_PD_OR_RETURN();
+
+   //printf("SET ASPECT_PREF of state '%s' [to: %d]\n", state, pref);
+   pd->aspect.prefer = pref;
+}
+
+//fill
+EAPI double
+edje_edit_state_fill_origin_relative_x_get(Evas_Object *obj, const char *part, const char *state, double value)
+{
+   GET_PD_OR_RETURN(0);
+   //printf("Get state fill origin of part: %s state: %s\n", part, state);
+   return TO_DOUBLE(pd->fill.pos_rel_x);
+}
+
+EAPI double
+edje_edit_state_fill_origin_relative_y_get(Evas_Object *obj, const char *part, const char *state, double value)
+{
+   GET_PD_OR_RETURN(0);
+   //printf("Get state fill origin of part: %s state: %s\n", part, state);
+   return TO_DOUBLE(pd->fill.pos_rel_y);
+}
+
+EAPI int
+edje_edit_state_fill_origin_offset_x_get(Evas_Object *obj, const char *part, const char *state, double value)
+{
+   GET_PD_OR_RETURN(0);
+   //printf("Get state fill origin offset of part: %s state: %s\n", part, state);
+   return pd->fill.pos_abs_x;
+}
+
+EAPI int
+edje_edit_state_fill_origin_offset_y_get(Evas_Object *obj, const char *part, const char *state, double value)
+{
+   GET_PD_OR_RETURN(0);
+   //printf("Get state fill origin offset of part: %s state: %s\n", part, state);
+   return pd->fill.pos_abs_y;
+}
+
+
+EAPI void
+edje_edit_state_fill_origin_relative_x_set(Evas_Object *obj, const char *part, const char *state, double value, double x)
+{
+   GET_PD_OR_RETURN();
+   //printf("Set state fill origin of part: %s state: %s to: %f\n", part, state, x);
+   pd->fill.pos_rel_x = FROM_DOUBLE(x);
+   edje_object_calc_force(obj);
+}
+
+EAPI void
+edje_edit_state_fill_origin_relative_y_set(Evas_Object *obj, const char *part, const char *state, double value, double y)
+{
+   GET_PD_OR_RETURN();
+   //printf("Set state fill origin of part: %s state: %s to: %f\n", part, state, y);
+   pd->fill.pos_rel_y = FROM_DOUBLE(y);
+   edje_object_calc_force(obj);
+}
+
+EAPI void
+edje_edit_state_fill_origin_offset_x_set(Evas_Object *obj, const char *part, const char *state, double value, double x)
+{
+   GET_PD_OR_RETURN();
+   //printf("Set state fill origin offset x of part: %s state: %s to: %f\n", part, state, x);
+   pd->fill.pos_abs_x = FROM_DOUBLE(x);
+   edje_object_calc_force(obj);
+}
+
+EAPI void
+edje_edit_state_fill_origin_offset_y_set(Evas_Object *obj, const char *part, const char *state, double value, double y)
+{
+   GET_PD_OR_RETURN();
+   //printf("Set state fill origin offset y of part: %s state: %s to: %f\n", part, state, y);
+   pd->fill.pos_abs_y = FROM_DOUBLE(y);
+   edje_object_calc_force(obj);
+}
+
+EAPI double
+edje_edit_state_fill_size_relative_x_get(Evas_Object *obj, const char *part, const char *state, double value)
+{
+   GET_PD_OR_RETURN(0.0);
+   //printf("Get state fill size of part: %s state: %s\n", part, state);
+   return TO_DOUBLE(pd->fill.rel_x);
+}
+
+EAPI double
+edje_edit_state_fill_size_relative_y_get(Evas_Object *obj, const char *part, const char *state, double value)
+{
+   GET_PD_OR_RETURN(0.0);
+   //printf("Get state fill size of part: %s state: %s\n", part, state);
+   return TO_DOUBLE(pd->fill.rel_y);
+}
+
+EAPI int
+edje_edit_state_fill_size_offset_x_get(Evas_Object *obj, const char *part, const char *state, double value)
+{
+   GET_PD_OR_RETURN(0);
+   //printf("Get state fill size offset of part: %s state: %s\n", part, state);
+   return pd->fill.abs_x;
+}
+
+EAPI int
+edje_edit_state_fill_size_offset_y_get(Evas_Object *obj, const char *part, const char *state, double value)
+{
+   GET_PD_OR_RETURN(0);
+   //printf("Get state fill size offset of part: %s state: %s\n", part, state);
+   return pd->fill.abs_y;
+}
+
+EAPI void
+edje_edit_state_fill_size_relative_x_set(Evas_Object *obj, const char *part, const char *state, double value, double x)
+{
+   GET_PD_OR_RETURN();
+   //printf("Set state fill size of part: %s state: %s to: %f\n", part, state, x);
+   pd->fill.rel_x = FROM_DOUBLE(x);
+   edje_object_calc_force(obj);
+}
+
+EAPI void
+edje_edit_state_fill_size_relative_y_set(Evas_Object *obj, const char *part, const char *state, double value, double y)
+{
+   GET_PD_OR_RETURN();
+   //printf("Set state fill size of part: %s state: %s to: %f\n", part, state, y);
+   pd->fill.rel_y = FROM_DOUBLE(y);
+   edje_object_calc_force(obj);
+}
+
+EAPI void
+edje_edit_state_fill_size_offset_x_set(Evas_Object *obj, const char *part, const char *state, double value, double x)
+{
+   GET_PD_OR_RETURN();
+   //printf("Set state fill size offset x of part: %s state: %s to: %f\n", part, state, x);
+   pd->fill.abs_x = FROM_DOUBLE(x);
+   edje_object_calc_force(obj);
+}
+
+EAPI void
+edje_edit_state_fill_size_offset_y_set(Evas_Object *obj, const char *part, const char *state, double value, double y)
+{
+   GET_PD_OR_RETURN();
+   //printf("Set state fill size offset y of part: %s state: %s to: %f\n", part, state, y);
+   pd->fill.abs_y = FROM_DOUBLE(y);
+   edje_object_calc_force(obj);
+}
+
+EAPI Eina_Bool
+edje_edit_state_visible_get(Evas_Object *obj, const char *part, const char *state, double value)
+{
+   GET_PD_OR_RETURN(0);
+   //printf("Get state visible flag of part: %s state: %s\n", part, state);
+   return pd->visible;
+}
+
+EAPI void
+edje_edit_state_visible_set(Evas_Object *obj, const char *part, const char *state, double value, Eina_Bool visible)
+{
+   GET_PD_OR_RETURN();
+   //printf("Set state visible flag of part: %s state: %s to: %d\n", part, state, visible);
+   if (visible) pd->visible = 1;
+   else         pd->visible = 0;
+   edje_object_calc_force(obj);
+}
+
+EAPI const char*
+edje_edit_state_color_class_get(Evas_Object *obj, const char *part, const char *state, double value)
+{
+   GET_PD_OR_RETURN(NULL);
+   //printf("Get ColorClass of part: %s state: %s\n", part, state);
+   return eina_stringshare_add(pd->color_class);
+}
+
+EAPI void
+edje_edit_state_color_class_set(Evas_Object *obj, const char *part, const char *state, double value, const char *color_class)
+{
+   GET_PD_OR_RETURN();
+   //printf("Set ColorClass of part: %s state: %s [to: %s]\n", part, state, color_class);
+   _edje_if_string_free(ed, pd->color_class);
+   pd->color_class = (char*)eina_stringshare_add(color_class);
+}
+
+EAPI const Eina_List *
+edje_edit_state_external_params_list_get(Evas_Object *obj, const char *part, const char *state, double value)
+{
+   GET_PD_OR_RETURN(NULL);
+   return pd->external_params;
+}
+
+EAPI Eina_Bool
+edje_edit_state_external_param_get(Evas_Object *obj, const char *part, const char *state, double value, const char *param, Edje_External_Param_Type *type, void **val)
+{
+   Eina_List *l;
+   Edje_External_Param *p;
+   GET_PD_OR_RETURN(EINA_FALSE);
+
+   EINA_LIST_FOREACH(pd->external_params, l, p)
+      if (!strcmp(p->name, param))
+       {
+          if (type) *type = p->type;
+          if (val)
+             switch (p->type)
+               {
+                case EDJE_EXTERNAL_PARAM_TYPE_INT:
+                case EDJE_EXTERNAL_PARAM_TYPE_BOOL:
+                   *val = &p->i;
+                   break;
+                case EDJE_EXTERNAL_PARAM_TYPE_DOUBLE:
+                   *val = &p->d;
+                   break;
+                case EDJE_EXTERNAL_PARAM_TYPE_CHOICE:
+                case EDJE_EXTERNAL_PARAM_TYPE_STRING:
+                   *val = (void *)p->s;
+                   break;
+                default:
+                   ERR("unknown external parameter type '%d'", p->type);
+               }
+          return EINA_TRUE;
+       }
+
+   return EINA_FALSE;
+}
+
+EAPI Eina_Bool
+edje_edit_state_external_param_int_get(Evas_Object *obj, const char *part, const char *state, double value, const char *param, int *val)
+{
+   Eina_List *l;
+   Edje_External_Param *p;
+   GET_PD_OR_RETURN(EINA_FALSE);
+
+   EINA_LIST_FOREACH(pd->external_params, l, p)
+      if (!strcmp(p->name, param))
+       {
+          if (p->type != EDJE_EXTERNAL_PARAM_TYPE_INT)
+            return EINA_FALSE;
+          if (val)
+            *val = p->i;
+          return EINA_TRUE;
+       }
+
+   return EINA_FALSE;
+}
+
+EAPI Eina_Bool
+edje_edit_state_external_param_bool_get(Evas_Object *obj, const char *part, const char *state, double value, const char *param, Eina_Bool *val)
+{
+   Eina_List *l;
+   Edje_External_Param *p;
+   GET_PD_OR_RETURN(EINA_FALSE);
+
+   EINA_LIST_FOREACH(pd->external_params, l, p)
+      if (!strcmp(p->name, param))
+       {
+          if (p->type != EDJE_EXTERNAL_PARAM_TYPE_BOOL)
+            return EINA_FALSE;
+          if (val)
+            *val = p->i;
+          return EINA_TRUE;
+       }
+
+   return EINA_FALSE;
+}
+
+EAPI Eina_Bool
+edje_edit_state_external_param_double_get(Evas_Object *obj, const char *part, const char *state, double value, const char *param, double *val)
+{
+   Eina_List *l;
+   Edje_External_Param *p;
+   GET_PD_OR_RETURN(EINA_FALSE);
+
+   EINA_LIST_FOREACH(pd->external_params, l, p)
+      if (!strcmp(p->name, param))
+       {
+          if (p->type != EDJE_EXTERNAL_PARAM_TYPE_DOUBLE)
+            return EINA_FALSE;
+          if (val)
+            *val = p->d;
+          return EINA_TRUE;
+       }
+
+   return EINA_FALSE;
+}
+
+EAPI Eina_Bool
+edje_edit_state_external_param_string_get(Evas_Object *obj, const char *part, const char *state, double value, const char *param, const char **val)
+{
+   Eina_List *l;
+   Edje_External_Param *p;
+   GET_PD_OR_RETURN(EINA_FALSE);
+
+   EINA_LIST_FOREACH(pd->external_params, l, p)
+      if (!strcmp(p->name, param))
+       {
+          if (p->type != EDJE_EXTERNAL_PARAM_TYPE_STRING)
+            return EINA_FALSE;
+          if (val)
+            *val = p->s;
+          return EINA_TRUE;
+       }
+
+   return EINA_FALSE;
+}
+
+EAPI Eina_Bool
+edje_edit_state_external_param_choice_get(Evas_Object *obj, const char *part, const char *state, double value, const char *param, const char **val)
+{
+   Eina_List *l;
+   Edje_External_Param *p;
+   GET_PD_OR_RETURN(EINA_FALSE);
+
+   EINA_LIST_FOREACH(pd->external_params, l, p)
+      if (!strcmp(p->name, param))
+       {
+          if (p->type != EDJE_EXTERNAL_PARAM_TYPE_CHOICE)
+            return EINA_FALSE;
+          if (val)
+            *val = p->s;
+          return EINA_TRUE;
+       }
+
+   return EINA_FALSE;
+}
+
+/**
+ * Arguments should have proper sized values matching their types:
+ *   - EDJE_EXTERNAL_PARAM_TYPE_INT: int
+ *   - EDJE_EXTERNAL_PARAM_TYPE_BOOL: int
+ *   - EDJE_EXTERNAL_PARAM_TYPE_DOUBLE: double
+ *   - EDJE_EXTERNAL_PARAM_TYPE_STRING: char*
+ *   - EDJE_EXTERNAL_PARAM_TYPE_CHOICE: char*
+ */
+EAPI Eina_Bool
+edje_edit_state_external_param_set(Evas_Object *obj, const char *part, const char *state, double value, const char *param, Edje_External_Param_Type type, ...)
+{
+   va_list ap;
+   Eina_List *l;
+   Edje_External_Param *p;
+   Edje_Real_Part *rp;
+   int found = 0;
+
+   GET_PD_OR_RETURN(EINA_FALSE);
+
+   rp = _edje_real_part_get(ed, part);
+
+   va_start(ap, type);
+
+   EINA_LIST_FOREACH(pd->external_params, l, p)
+      if (!strcmp(p->name, param))
+       {
+          found = 1;
+          break;
+       }
+
+   if (!found)
+     {
+       p = _alloc(sizeof(Edje_External_Param));
+       if (!p)
+         {
+            va_end(ap);
+            return EINA_FALSE;
+         }
+       p->name = eina_stringshare_add(param);
+     }
+
+   p->type = type;
+   p->i = 0;
+   p->d = 0;
+   _edje_if_string_free(ed, p->s);
+   p->s = NULL;
+
+   switch (type)
+     {
+      case EDJE_EXTERNAL_PARAM_TYPE_INT:
+      case EDJE_EXTERNAL_PARAM_TYPE_BOOL:
+        p->i = (int)va_arg(ap, int);
+        break;
+      case EDJE_EXTERNAL_PARAM_TYPE_DOUBLE:
+        p->d = (double)va_arg(ap, double);
+        break;
+      case EDJE_EXTERNAL_PARAM_TYPE_CHOICE:
+      case EDJE_EXTERNAL_PARAM_TYPE_STRING:
+        p->s = eina_stringshare_add((const char *)va_arg(ap, char *));
+        break;
+      default:
+        ERR("unknown external parameter type '%d'", type);
+     }
+
+   va_end(ap);
+
+   if (!found)
+     pd->external_params = eina_list_append(pd->external_params, p);
+
+   _edje_external_parsed_params_free(rp->swallowed_object,
+                                    rp->param1.external_params);
+   rp->param1.external_params = \
+                            _edje_external_params_parse(rp->swallowed_object,
+                                                        pd->external_params);
+
+     {
+       const char * sname;
+       double svalue;
+       sname = edje_edit_part_selected_state_get(obj, part, &svalue);
+       if (!strcmp(state, sname) && svalue == value)
+         edje_object_part_external_param_set(obj, part, p);
+       eina_stringshare_del(sname);
+     }
+
+   return EINA_TRUE;
+}
+
+EAPI Eina_Bool
+edje_edit_state_external_param_int_set(Evas_Object *obj, const char *part, const char *state, double value, const char *param, int val)
+{
+   return edje_edit_state_external_param_set(obj, part, state, value, param, EDJE_EXTERNAL_PARAM_TYPE_INT, val);
+}
+
+EAPI Eina_Bool
+edje_edit_state_external_param_bool_set(Evas_Object *obj, const char *part, const char *state, double value, const char *param, Eina_Bool val)
+{
+   return edje_edit_state_external_param_set(obj, part, state, value, param, EDJE_EXTERNAL_PARAM_TYPE_BOOL, (int)val);
+}
+
+EAPI Eina_Bool
+edje_edit_state_external_param_double_set(Evas_Object *obj, const char *part, const char *state, double value, const char *param, double val)
+{
+   return edje_edit_state_external_param_set(obj, part, state, value, param, EDJE_EXTERNAL_PARAM_TYPE_DOUBLE, val);
+}
+
+EAPI Eina_Bool
+edje_edit_state_external_param_string_set(Evas_Object *obj, const char *part, const char *state, double value, const char *param, const char *val)
+{
+   return edje_edit_state_external_param_set(obj, part, state, value, param, EDJE_EXTERNAL_PARAM_TYPE_STRING, val);
+}
+
+EAPI Eina_Bool
+edje_edit_state_external_param_choice_set(Evas_Object *obj, const char *part, const char *state, double value, const char *param, const char *val)
+{
+   return edje_edit_state_external_param_set(obj, part, state, value, param, EDJE_EXTERNAL_PARAM_TYPE_CHOICE, val);
+}
+
+/**************/
+/*  TEXT API */
+/**************/
+
+EAPI const char *
+edje_edit_state_text_get(Evas_Object *obj, const char *part, const char *state, double value)
+{
+   GET_PD_OR_RETURN(NULL);
+
+   //printf("GET TEXT of state: %s\n", state);
+
+   if (pd->text.text)
+     return eina_stringshare_add(pd->text.text);
+
+   return NULL;
+}
+
+EAPI void
+edje_edit_state_text_set(Evas_Object *obj, const char *part, const char *state, double value, const char *text)
+{
+   GET_PD_OR_RETURN();
+
+   //printf("SET TEXT of state: %s\n", state);
+
+   if (!text) return;
+
+   _edje_if_string_free(ed, pd->text.text);
+   pd->text.text = (char *)eina_stringshare_add(text);
+
+   edje_object_calc_force(obj);
+}
+
+EAPI int
+edje_edit_state_text_size_get(Evas_Object *obj, const char *part, const char *state, double value)
+{
+   GET_PD_OR_RETURN(-1);
+
+   //printf("GET TEXT_SIZE of state: %s [%d]\n", state, pd->text.size);
+   return pd->text.size;
+}
+
+EAPI void
+edje_edit_state_text_size_set(Evas_Object *obj, const char *part, const char *state, double value, int size)
+{
+   GET_PD_OR_RETURN();
+
+   //printf("SET TEXT_SIZE of state: %s [%d]\n", state, size);
+
+   if (size < 0) return;
+
+   pd->text.size = size;
+
+   edje_object_calc_force(obj);
+}
+
+EAPI double
+edje_edit_state_text_align_x_get(Evas_Object *obj, const char *part, const char *state, double value)
+{
+   GET_PD_OR_RETURN(0);
+
+   //printf("GET TEXT_ALIGN_X of state: %s [%f]\n", state, pd->text.align.x);
+   return TO_DOUBLE(pd->text.align.x);
+}
+
+EAPI void
+edje_edit_state_text_align_x_set(Evas_Object *obj, const char *part, const char *state, double value, double align)
+{
+   GET_PD_OR_RETURN();
+
+   //printf("SET TEXT_ALIGN_X of state: %s [%f]\n", state, align);
+
+   pd->text.align.x = FROM_DOUBLE(align);
+   edje_object_calc_force(obj);
+}
+
+EAPI double
+edje_edit_state_text_align_y_get(Evas_Object *obj, const char *part, const char *state, double value)
+{
+   GET_PD_OR_RETURN(0.0);
+
+   //printf("GET TEXT_ALIGN_Y of state: %s [%f]\n", state, pd->text.align.x);
+   return TO_DOUBLE(pd->text.align.y);
+}
+
+EAPI void
+edje_edit_state_text_align_y_set(Evas_Object *obj, const char *part, const char *state, double value, double align)
+{
+   GET_PD_OR_RETURN();
+
+   //printf("SET TEXT_ALIGN_Y of state: %s [%f]\n", state, align);
+
+   pd->text.align.y = FROM_DOUBLE(align);
+   edje_object_calc_force(obj);
+}
+
+EAPI double
+edje_edit_state_text_elipsis_get(Evas_Object *obj, const char *part, const char *state, double value)
+{
+   GET_PD_OR_RETURN(0.0);
+
+   //printf("GET TEXT_ELIPSIS of state: %s [%f]\n", state, pd->text.elipsis);
+   return pd->text.elipsis;
+}
+
+EAPI void
+edje_edit_state_text_elipsis_set(Evas_Object *obj, const char *part, const char *state, double value, double balance)
+{
+   GET_PD_OR_RETURN();
+
+   //printf("SET TEXT_ELIPSIS of state: %s [%f]\n", state, balance);
+
+   pd->text.elipsis = balance;
+   edje_object_calc_force(obj);
+}
+
+EAPI Eina_Bool
+edje_edit_state_text_fit_x_get(Evas_Object *obj, const char *part, const char *state, double value)
+{
+   GET_PD_OR_RETURN(0);
+   //printf("GET TEXT_FIT_VERT of state: %s \n", state);
+   return pd->text.fit_x;
+}
+
+EAPI void
+edje_edit_state_text_fit_x_set(Evas_Object *obj, const char *part, const char *state, double value, Eina_Bool fit)
+{
+   GET_PD_OR_RETURN();
+
+   //printf("SET TEXT_FIT_VERT of state: %s\n", state);
+
+   pd->text.fit_x = fit ? 1 : 0;
+   edje_object_calc_force(obj);
+}
+
+EAPI Eina_Bool
+edje_edit_state_text_fit_y_get(Evas_Object *obj, const char *part, const char *state, double value)
+{
+   GET_PD_OR_RETURN(0);
+   //printf("GET TEXT_FIT_VERT of state: %s \n", state);
+   return pd->text.fit_y;
+}
+
+EAPI void
+edje_edit_state_text_fit_y_set(Evas_Object *obj, const char *part, const char *state, double value, Eina_Bool fit)
+{
+   GET_PD_OR_RETURN();
+
+   //printf("SET TEXT_FIT_VERT of state: %s\n", state);
+
+   pd->text.fit_y = fit ? 1 : 0;
+   edje_object_calc_force(obj);
+}
+
+EAPI Eina_List *
+edje_edit_fonts_list_get(Evas_Object *obj)
+{
+   Edje_Font_Directory_Entry *f;
+   Eina_List *fonts = NULL;
+   Eina_List *l;
+
+   GET_ED_OR_RETURN(NULL);
+
+   if (!ed->file) return NULL;
+   if (!ed->file->font_dir) return NULL;
+
+   //printf("GET FONT LIST for %s\n", ed->file->path);
+
+   EINA_LIST_FOREACH(ed->file->font_dir->entries, l, f)
+     {
+       fonts = eina_list_append(fonts, f);
+       //printf("   Font: %s (%s) \n", f->entry, f->path);
+     }
+
+   return fonts;
+}
+
+EAPI Eina_Bool
+edje_edit_font_add(Evas_Object *obj, const char* path, const char* alias)
+{
+   char entry[PATH_MAX];
+   struct stat st;
+   Edje_Font_Directory_Entry *fnt;
+
+   GET_ED_OR_RETURN(EINA_FALSE);
+
+   INF("ADD FONT: %s\n", path);
+
+   if (!path) return EINA_FALSE;
+   if (stat(path, &st) || !S_ISREG(st.st_mode)) return EINA_FALSE;
+   if (!ed->file) return EINA_FALSE;
+   if (!ed->path) return EINA_FALSE;
+
+   /* Create Font_Directory if not exist */
+   if (!ed->file->font_dir)
+     {
+       ed->file->font_dir = _alloc(sizeof(Edje_Font_Directory));
+       if (!ed->file->font_dir) return EINA_FALSE;
+     }
+   if (!ed->file->font_hash)
+     {
+       ed->file->font_hash = eina_hash_string_superfast_new(NULL);
+       if (!ed->file->font_hash) return EINA_FALSE;
+     }
+
+   /* Alias */
+   if (!alias)
+     {
+       if ((alias = strrchr(path, '/'))) alias ++;
+       else alias = (char *)path;
+     }
+   snprintf(entry, sizeof(entry), "fonts/%s", alias);
+
+   /* Check if exists */
+   fnt = eina_hash_find(ed->file->font_hash, alias);
+   if (fnt)
+     return EINA_FALSE;
+
+   /* Create Edje_Font_Directory_Entry */
+   fnt = _alloc(sizeof(Edje_Font_Directory_Entry));
+   if (!fnt)
+     {
+       ERR("Unable to alloc font entry part \"%s\"", alias);
+       return EINA_FALSE;
+     }
+   fnt->entry = strdup(alias);
+   fnt->path = strdup(entry);
+
+   ed->file->font_dir->entries = eina_list_append(
+                                      ed->file->font_dir->entries,
+                                      fnt);
+   eina_hash_direct_add(ed->file->font_hash, fnt->entry, fnt);
+
+   /* Import font */
+   if (!_edje_import_font_file(ed, path, entry))
+     {
+       ed->file->font_dir->entries = eina_list_remove(
+                                            ed->file->font_dir->entries,
+                                            fnt);
+       eina_hash_del_by_key(ed->file->font_hash, alias);
+
+       free((char *)fnt->entry);
+       free((char *)fnt->path);
+       free(fnt);
+       return EINA_FALSE;
+     }
+
+   return EINA_TRUE;
+}
+
+EAPI Eina_Bool
+edje_edit_font_del(Evas_Object *obj, const char* alias)
+{
+   Edje_Font_Directory_Entry *fnt;
+
+   GET_ED_OR_RETURN(EINA_FALSE);
+
+   INF("DEL FONT: %s\n", alias);
+
+   if (!alias) return EINA_FALSE;
+   if (!ed->file) return EINA_FALSE;
+   if (!ed->path) return EINA_FALSE;
+
+   if (!ed->file->font_dir)
+     return EINA_TRUE;
+
+   fnt = eina_hash_find(ed->file->font_hash, alias);
+   if (!fnt)
+     {
+       WRN("Unable to find font entry part \"%s\"", alias);
+       return EINA_TRUE;
+     }
+
+   ed->file->font_dir->entries = eina_list_remove(
+                                      ed->file->font_dir->entries,
+                                      fnt);
+
+   if (!eina_hash_del_by_key(ed->file->font_hash, alias))
+     {
+       ERR("Unable to remove font \"%s\" of fonts hash", alias);
+
+       ed->file->font_dir->entries = eina_list_append(
+                                         ed->file->font_dir->entries,
+                                         fnt);
+       return EINA_FALSE;
+     }
+
+   /* Erase font to edje file */
+   {
+      char entry[PATH_MAX];
+      Eet_File *eetf;
+
+      /* open the eet file */
+      eetf = eet_open(ed->path, EET_FILE_MODE_READ_WRITE);
+      if (!eetf)
+       {
+          ERR("Unable to open \"%s\" for writing output", ed->path);
+          eina_hash_direct_add(ed->file->font_hash, fnt->entry, fnt);
+          ed->file->font_dir->entries = eina_list_append(
+                                            ed->file->font_dir->entries,
+                                            fnt);
+          return EINA_FALSE;
+       }
+
+      snprintf(entry, sizeof(entry), "fonts/%s", alias);
+
+      if (eet_delete(eetf, entry) <= 0)
+        {
+           ERR("Unable to delete \"%s\" font entry", entry);
+           eet_close(eetf);
+          eina_hash_direct_add(ed->file->font_hash, fnt->entry, fnt);
+          ed->file->font_dir->entries = eina_list_append(
+                                            ed->file->font_dir->entries,
+                                            fnt);
+           return EINA_FALSE;
+        }
+
+      /* write the edje_file */
+      if (!_edje_edit_edje_file_save(eetf, ed->file))
+       {
+          eet_close(eetf);
+          eina_hash_direct_add(ed->file->font_hash, fnt->entry, fnt);
+          ed->file->font_dir->entries = eina_list_append(
+                                            ed->file->font_dir->entries,
+                                            fnt);
+          return EINA_FALSE;
+       }
+      eet_close(eetf);
+   }
+
+   free((char *)fnt->entry);
+   free((char *)fnt->path);
+   free(fnt);
+
+   return EINA_TRUE;
+}
+
+EAPI const char *
+edje_edit_state_font_get(Evas_Object *obj, const char *part, const char *state, double value)
+{
+   GET_PD_OR_RETURN(NULL);
+
+   //printf("GET FONT of state: %s [%s]\n", state, pd->text.font);
+   if (!pd->text.font) return NULL;
+   return eina_stringshare_add(pd->text.font);
+}
+
+EAPI void
+edje_edit_state_font_set(Evas_Object *obj, const char *part, const char *state, double value, const char *font)
+{
+   GET_PD_OR_RETURN();
+
+   //printf("SET FONT of state: %s [%s]\n", state, font);
+
+   _edje_if_string_free(ed, pd->text.font);
+   pd->text.font = (char *)eina_stringshare_add(font);
+
+   edje_object_calc_force(obj);
+}
+
+EAPI Edje_Text_Effect
+edje_edit_part_effect_get(Evas_Object *obj, const char *part)
+{
+   GET_RP_OR_RETURN(0);
+
+   //printf("GET EFFECT of part: %s\n", part);
+   return rp->part->effect;
+}
+
+EAPI void
+edje_edit_part_effect_set(Evas_Object *obj, const char *part, Edje_Text_Effect effect)
+{
+   GET_RP_OR_RETURN();
+
+   //printf("SET EFFECT of part: %s [%d]\n", part, effect);
+   rp->part->effect = effect;
+
+   edje_object_calc_force(obj);
+}
+
+/****************/
+/*  IMAGES API  */
+/****************/
+
+EAPI Eina_List *
+edje_edit_images_list_get(Evas_Object *obj)
+{
+   Edje_Image_Directory_Entry *i;
+   Eina_List *images = NULL;
+   Eina_List *l;
+
+   GET_ED_OR_RETURN(NULL);
+
+   if (!ed->file) return NULL;
+   if (!ed->file->image_dir) return NULL;
+
+   //printf("GET IMAGES LIST for %s\n", ed->file->path);
+
+   EINA_LIST_FOREACH(ed->file->image_dir->entries, l, i)
+     {
+       images = eina_list_append(images, eina_stringshare_add(i->entry));
+       //printf("   Image: %s (type: %d param: %d id: %d) \n",
+       //       i->entry, i->source_type, i->source_param, i->id);
+     }
+
+   return images;
+}
+
+EAPI Eina_Bool
+edje_edit_image_add(Evas_Object *obj, const char* path)
+{
+   Eina_List *l;
+   Edje_Image_Directory_Entry *de;
+   int free_id = 0;
+   char *name;
+
+   GET_ED_OR_RETURN(EINA_FALSE);
+
+   if (!path) return EINA_FALSE;
+   if (!ed->file) return EINA_FALSE;
+   if (!ed->path) return EINA_FALSE;
+
+   /* Create Image_Directory if not exist */
+   if (!ed->file->image_dir)
+     {
+       ed->file->image_dir = _alloc(sizeof(Edje_Image_Directory));
+       if (!ed->file->image_dir) return EINA_FALSE;
+     }
+
+   /* Image name */
+   if ((name = strrchr(path, '/'))) name++;
+   else name = (char *)path;
+
+   /* Loop trough image directory to find if image exist */
+   EINA_LIST_FOREACH(ed->file->image_dir->entries, l, de)
+     {
+       if (!strcmp(name, de->entry))
+         return EINA_FALSE;
+       if (de->id >= free_id)
+         free_id = de->id + 1; /*TODO search for free (hole) id*/
+     }
+
+   /* Create Image Entry */
+   de = _alloc(sizeof(Edje_Image_Directory_Entry));
+   if (!de) return EINA_FALSE;
+   de->entry = strdup(name);
+   de->id = free_id;
+   de->source_type = 1;
+   de->source_param = 1;
+
+   /* Add image to Image Directory */
+   ed->file->image_dir->entries =
+        eina_list_append(ed->file->image_dir->entries, de);
+
+   /* Import image */
+   if (!_edje_import_image_file(ed, path, free_id))
+     {
+       ed->file->image_dir->entries =
+            eina_list_remove(ed->file->image_dir->entries, de);
+       free(de->entry);
+       free(de);
+       return EINA_FALSE;
+     }
+
+   return EINA_TRUE;
+}
+
+EAPI Eina_Bool
+edje_edit_image_del(Evas_Object *obj, const char* name)
+{
+   Eina_List *l;
+   Edje_Image_Directory_Entry *de;
+
+   GET_ED_OR_RETURN(EINA_FALSE);
+
+   if (!name) return EINA_FALSE;
+   if (!ed->file) return EINA_FALSE;
+   if (!ed->path) return EINA_FALSE;
+
+   /* Create Image_Directory if not exist */
+   if (!ed->file->image_dir)
+     return EINA_TRUE;
+
+   EINA_LIST_FOREACH(ed->file->image_dir->entries, l, de)
+     {
+       if (!strcmp(name, de->entry))
+         {
+           ed->file->image_dir->entries = eina_list_remove_list(
+                                            ed->file->image_dir->entries, l);
+           break;
+         }
+       de = NULL;
+     }
+
+   if (!de)
+     {
+       WRN("Unable to find image entry part \"%s\"", name);
+       return EINA_TRUE;
+     }
+
+   {
+      char entry[PATH_MAX];
+      Eet_File *eetf;
+
+      /* open the eet file */
+      eetf = eet_open(ed->path, EET_FILE_MODE_READ_WRITE);
+      if (!eetf)
+       {
+          ERR("Unable to open \"%s\" for writing output", ed->path);
+          ed->file->image_dir->entries =
+              eina_list_append(ed->file->image_dir->entries, de);
+          return EINA_FALSE;
+       }
+
+      snprintf(entry, sizeof(entry), "images/%i", de->id);
+
+      if (eet_delete(eetf, entry) <= 0)
+        {
+           ERR("Unable to delete \"%s\" font entry", entry);
+           eet_close(eetf);
+          ed->file->image_dir->entries =
+              eina_list_append(ed->file->image_dir->entries, de);
+           return EINA_FALSE;
+        }
+
+      /* write the edje_file */
+      if (!_edje_edit_edje_file_save(eetf, ed->file))
+       {
+          eet_close(eetf);
+          ed->file->image_dir->entries =
+              eina_list_append(ed->file->image_dir->entries, de);
+          return EINA_FALSE;
+       }
+
+      eet_close(eetf);
+   }
+
+   free(de->entry);
+   free(de);
+
+   return EINA_TRUE;
+}
+
+EAPI Eina_Bool
+edje_edit_image_data_add(Evas_Object *obj, const char *name, int id)
+{
+   Eina_List *l;
+   Edje_Image_Directory_Entry *de;
+   Edje_Image_Directory_Entry *i, *t;
+
+   GET_ED_OR_RETURN(0);
+
+   if (!name) return 0;
+   if (!ed->file) return 0;
+   if (!ed->path) return 0;
+
+   /* Create Image_Directory if not exist */
+   if (!ed->file->image_dir)
+     {
+       ed->file->image_dir = _alloc(sizeof(Edje_Image_Directory));
+       if (!ed->file->image_dir) return 0;
+     }
+
+   /* Loop trough image directory to find if image exist */
+   t = NULL;
+   EINA_LIST_FOREACH(ed->file->image_dir->entries, l, i)
+     {
+       if (!i) return 0;
+       if (i->id == id) t = i;
+     }
+
+   /* Create Image Entry */
+   if (!t)
+     {
+       de = _alloc(sizeof(Edje_Image_Directory_Entry));
+       if (!de) return 0;
+     }
+   else
+     {
+       de = t;
+       free(de->entry);
+     }
+   de->entry = strdup(name);
+   de->id = id;
+   de->source_type = 1;
+   de->source_param = 1;
+
+   /* Add image to Image Directory */
+   if (!t)
+     ed->file->image_dir->entries =
+       eina_list_append(ed->file->image_dir->entries, de);
+
+   return 1;
+}
+
+EAPI int
+edje_edit_image_id_get(Evas_Object *obj, const char *image_name)
+{
+   return _edje_image_id_find(obj, image_name);
+}
+
+EAPI Edje_Edit_Image_Comp
+edje_edit_image_compression_type_get(Evas_Object *obj, const char *image)
+{
+   Edje_Image_Directory_Entry *i = NULL;
+   Eina_List *l;
+
+   GET_ED_OR_RETURN(-1);
+
+   if (!ed->file) return -1;
+   if (!ed->file->image_dir) return -1;
+
+   EINA_LIST_FOREACH(ed->file->image_dir->entries, l, i)
+     {
+       if (strcmp(i->entry, image) == 0)
+         break;
+       i = NULL;
+     }
+
+   if (!i) return -1;
+
+   switch(i->source_type)
+     {
+       case EDJE_IMAGE_SOURCE_TYPE_INLINE_PERFECT:
+               if (i->source_param == 0) // RAW
+                 return EDJE_EDIT_IMAGE_COMP_RAW;
+               else // COMP
+                 return EDJE_EDIT_IMAGE_COMP_COMP;
+               break;
+       case EDJE_IMAGE_SOURCE_TYPE_INLINE_LOSSY: // LOSSY
+               return EDJE_EDIT_IMAGE_COMP_LOSSY;
+               break;
+       case EDJE_IMAGE_SOURCE_TYPE_EXTERNAL: // USER
+               return EDJE_EDIT_IMAGE_COMP_USER;
+               break;
+     }
+
+   return -1;
+}
+
+EAPI int
+edje_edit_image_compression_rate_get(Evas_Object *obj, const char *image)
+{
+   Eina_List *l;
+   Edje_Image_Directory_Entry *i;
+
+   GET_ED_OR_RETURN(-1);
+
+   // Gets the Image Entry
+   EINA_LIST_FOREACH(ed->file->image_dir->entries, l, i)
+     {
+       if (strcmp(i->entry, image) == 0) break;
+       i = NULL;
+     }
+
+   if (!i) return -1;
+   if (i->source_type != EDJE_IMAGE_SOURCE_TYPE_INLINE_LOSSY) return -2;
+
+   return i->source_param;
+}
+
+EAPI const char *
+edje_edit_state_image_get(Evas_Object *obj, const char *part, const char *state, double value)
+{
+   char *image;
+
+   GET_PD_OR_RETURN(NULL);
+
+   image = (char *)_edje_image_name_find(obj, pd->image.id);
+   if (!image) return NULL;
+
+   //printf("GET IMAGE for %s [%s]\n", state, image);
+   return eina_stringshare_add(image);
+}
+
+EAPI void
+edje_edit_state_image_set(Evas_Object *obj, const char *part, const char *state, double value, const char *image)
+{
+   int id;
+
+   GET_PD_OR_RETURN();
+
+   if (!image) return;
+
+   id = _edje_image_id_find(obj, image);
+   //printf("SET IMAGE for %s [%s]\n", state, image);
+
+   if (id > -1) pd->image.id = id;
+
+   edje_object_calc_force(obj);
+}
+
+EAPI Eina_List *
+edje_edit_state_tweens_list_get(Evas_Object *obj, const char *part, const char *state, double value)
+{
+   Edje_Part_Image_Id *i;
+   Eina_List *tweens = NULL, *l;
+   const char *name;
+
+   GET_PD_OR_RETURN(NULL);
+
+   //printf("GET TWEEN LIST for %s\n", state);
+
+   EINA_LIST_FOREACH(pd->image.tween_list, l, i)
+     {
+       name = _edje_image_name_find(obj, i->id);
+       //printf("   t: %s\n", name);
+       tweens = eina_list_append(tweens, eina_stringshare_add(name));
+     }
+
+   return tweens;
+}
+
+EAPI Eina_Bool
+edje_edit_state_tween_add(Evas_Object *obj, const char *part, const char *state, double value, const char *tween)
+{
+   Edje_Part_Image_Id *i;
+   int id;
+
+   GET_PD_OR_RETURN(0);
+
+   id = _edje_image_id_find(obj, tween);
+   if (id < 0) return 0;
+
+   /* alloc Edje_Part_Image_Id */
+   i = _alloc(sizeof(Edje_Part_Image_Id));
+   if (!i) return 0;
+   i->id = id;
+
+   /* add to tween list */
+   pd->image.tween_list = eina_list_append(pd->image.tween_list, i);
+
+   return 1;
+}
+
+EAPI Eina_Bool
+edje_edit_state_tween_del(Evas_Object *obj, const char *part, const char *state, double value, const char *tween)
+{
+   Eina_List *l;
+   Edje_Part_Image_Id *i;
+   int id;
+
+   GET_PD_OR_RETURN(0);
+
+   if (!pd->image.tween_list) return 0;
+
+   id = _edje_image_id_find(obj, tween);
+   if (id < 0) return 0;
+
+   EINA_LIST_FOREACH(pd->image.tween_list, l, i)
+     {
+       if (i->id == id)
+         {
+            pd->image.tween_list = eina_list_remove_list(pd->image.tween_list, l);
+            return 1;
+         }
+     }
+   return 0;
+}
+
+EAPI void
+edje_edit_state_image_border_get(Evas_Object *obj, const char *part, const char *state, double value, int *l, int *r, int *t, int *b)
+{
+   GET_PD_OR_RETURN();
+
+   //printf("GET IMAGE_BORDER of state '%s'\n", state);
+
+   if (l) *l = pd->border.l;
+   if (r) *r = pd->border.r;
+   if (t) *t = pd->border.t;
+   if (b) *b = pd->border.b;
+}
+
+EAPI void
+edje_edit_state_image_border_set(Evas_Object *obj, const char *part, const char *state, double value, int l, int r, int t, int b)
+{
+   GET_PD_OR_RETURN();
+
+   //printf("SET IMAGE_BORDER of state '%s'\n", state);
+
+   if (l > -1) pd->border.l = l;
+   if (r > -1) pd->border.r = r;
+   if (t > -1) pd->border.t = t;
+   if (b > -1) pd->border.b = b;
+
+   edje_object_calc_force(obj);
+}
+
+EAPI unsigned char
+edje_edit_state_image_border_fill_get(Evas_Object *obj, const char *part, const char *state, double value)
+{
+   GET_PD_OR_RETURN(0);
+   if (pd->border.no_fill == 0) return 1;
+   else if (pd->border.no_fill == 1) return 0;
+   else if (pd->border.no_fill == 2) return 2;
+   return 0;
+}
+
+EAPI void
+edje_edit_state_image_border_fill_set(Evas_Object *obj, const char *part, const char *state, double value, unsigned char fill)
+{
+   GET_PD_OR_RETURN();
+   if (fill == 0) pd->border.no_fill = 1;
+   else if (fill == 1) pd->border.no_fill = 0;
+   else if (fill == 2) pd->border.no_fill = 2;
+
+   edje_object_calc_force(obj);
+}
+
+/******************/
+/*  SPECTRUM API  */
+/******************/
+
+EAPI Eina_List *
+edje_edit_spectrum_list_get(Evas_Object *obj)
+{
+   Edje_Spectrum_Directory_Entry *s;
+   Eina_List *spectrum = NULL;
+   Eina_List *l;
+
+   GET_ED_OR_RETURN(NULL);
+
+   if (!ed->file) return NULL;
+   if (!ed->file->spectrum_dir) return NULL;
+
+   //printf("GET SPECTRUM LIST for %s\n", ed->file->path);
+
+   EINA_LIST_FOREACH(ed->file->spectrum_dir->entries, l, s)
+     {
+       //printf("SPECTRUM: %s [id: %d]\n", s->entry, s->id);
+       spectrum = eina_list_append(spectrum, eina_stringshare_add(s->entry));
+     }
+
+   return spectrum;
+}
+
+EAPI Eina_Bool
+edje_edit_spectra_add(Evas_Object *obj, const char* name)
+{
+   GET_ED_OR_RETURN(0);
+
+   //printf("SPECTRA ADD [new name:%s]\n", name);
+
+   Edje_Spectrum_Directory_Entry *s;
+
+   if (!ed->file) return 0;
+
+   if (_edje_edit_spectrum_entry_get(ed, name)) return 0;
+
+   if (!ed->file->spectrum_dir)
+     {
+       ed->file->spectrum_dir = _alloc(sizeof(Edje_Spectrum_Directory));
+       if (!ed->file->spectrum_dir) return 0;
+     }
+
+   s = _alloc(sizeof(Edje_Spectrum_Directory_Entry));
+   if (!s) return 0;
+   ed->file->spectrum_dir->entries = eina_list_append(ed->file->spectrum_dir->entries, s);
+   s->id = eina_list_count(ed->file->spectrum_dir->entries) - 1; //TODO Search for id holes
+   s->entry = (char*)eina_stringshare_add(name);
+   s->filename = NULL;
+   s->color_list = NULL;
+
+   return 1;
+}
+
+EAPI Eina_Bool
+edje_edit_spectra_del(Evas_Object *obj, const char* spectra)
+{
+   Edje_Spectrum_Directory_Entry *s;
+
+   GET_ED_OR_RETURN(0);
+
+   s = _edje_edit_spectrum_entry_get(ed, spectra);
+   if (!s) return 0;
+
+   //printf("SPECTRA DEL %s\n", spectra);
+
+   ed->file->spectrum_dir->entries = eina_list_remove(ed->file->spectrum_dir->entries, s);
+   _edje_if_string_free(ed, s->entry);
+   _edje_if_string_free(ed, s->filename);
+   while (s->color_list)
+     {
+        Edje_Spectrum_Color *color;
+        color = eina_list_data_get(s->color_list);
+        free(color);
+        s->color_list = eina_list_remove_list(s->color_list, s->color_list);
+     }
+   free(s);
+
+   return 1;
+}
+
+EAPI Eina_Bool
+edje_edit_spectra_name_set(Evas_Object *obj, const char* spectra, const char* name)
+{
+   Edje_Spectrum_Directory_Entry *s;
+
+   GET_ED_OR_RETURN(0);
+
+   //printf("SET SPECTRA NAME for spectra: %s [new name:%s]\n", spectra, name);
+
+   s = _edje_edit_spectrum_entry_get(ed, spectra);
+   if (!s) return 0;
+
+   _edje_if_string_free(ed, s->entry);
+   s->entry = (char*)eina_stringshare_add(name);
+
+   return 1;
+}
+
+EAPI int
+edje_edit_spectra_stop_num_get(Evas_Object *obj, const char* spectra)
+{
+   Edje_Spectrum_Directory_Entry *s;
+
+   GET_ED_OR_RETURN(0);
+
+   //printf("GET SPECTRA STOP NUM for spectra: %s\n", spectra);
+
+   s = _edje_edit_spectrum_entry_get(ed, spectra);
+   if (!s) return 0;
+
+   return eina_list_count(s->color_list);
+}
+
+EAPI Eina_Bool
+edje_edit_spectra_stop_num_set(Evas_Object *obj, const char* spectra, int num)
+{
+   Edje_Spectrum_Directory_Entry *s;
+   Edje_Spectrum_Color *color;
+   GET_ED_OR_RETURN(0);
+
+   //printf("SET SPECTRA STOP NUM for spectra: %s\n", spectra);
+
+   s = _edje_edit_spectrum_entry_get(ed, spectra);
+   if (!s) return 0;
+
+   if (num == eina_list_count(s->color_list)) return 1;
+
+   //destroy all colors
+   while (s->color_list)
+     {
+        color = eina_list_data_get(s->color_list);
+        free(color);
+        s->color_list = eina_list_remove_list(s->color_list, s->color_list);
+     }
+
+   //... and recreate (TODO we should optimize this function)
+   while (num)
+     {
+        color = _alloc(sizeof(Edje_Spectrum_Color));
+        if (!color) return 0;
+        s->color_list = eina_list_append(s->color_list, color);
+        color->r = 255;
+        color->g = 255;
+        color->b = 255;
+        color->a = 255;
+        color->d = 10;
+        num--;
+     }
+
+   return 1;
+}
+
+EAPI Eina_Bool
+edje_edit_spectra_stop_color_get(Evas_Object *obj, const char* spectra, int stop_number, int *r, int *g, int *b, int *a, int *d)
+{
+   Edje_Spectrum_Directory_Entry *s;
+   Edje_Spectrum_Color *color;
+   GET_ED_OR_RETURN(0);
+
+   s = _edje_edit_spectrum_entry_get(ed, spectra);
+   if (!s) return 0;
+   //printf("GET SPECTRA STOP COLOR for spectra: %s stopn: %d\n", spectra, stop_number);
+
+   color = eina_list_nth(s->color_list, stop_number);
+   if (!color) return 0;
+   if (r) *r = color->r;
+   if (g) *g = color->g;
+   if (b) *b = color->b;
+   if (a) *a = color->a;
+   if (d) *d = color->d;
+
+   return 1;
+}
+
+EAPI Eina_Bool
+edje_edit_spectra_stop_color_set(Evas_Object *obj, const char* spectra, int stop_number, int r, int g, int b, int a, int d)
+{
+   Edje_Spectrum_Directory_Entry *s;
+   Edje_Spectrum_Color *color;
+   GET_ED_OR_RETURN(0);
+
+   s = _edje_edit_spectrum_entry_get(ed, spectra);
+   if (!s) return 0;
+   //printf("SET SPECTRA STOP COLOR for spectra: %s stopn: %d\n", spectra, stop_number);
+
+   color = eina_list_nth(s->color_list, stop_number);
+   if (!color) return 0;
+   color->r = r;
+   color->g = g;
+   color->b = b;
+   color->a = a;
+   color->d = d;
+
+   edje_object_calc_force(obj);
+
+   return 1;
+}
+
+
+/******************/
+/*  GRADIENT API  */
+/******************/
+
+EAPI const char *
+edje_edit_state_gradient_type_get(Evas_Object *obj, const char *part, const char *state, double value)
+{
+   GET_PD_OR_RETURN(NULL);
+
+   if (!pd->gradient.type)
+      return NULL;
+
+//   printf("GET GRADIENT TYPE for part: %s state: %s [%s]\n", part, state, pd->gradient.type);
+
+   return eina_stringshare_add(pd->gradient.type);
+}
+
+EAPI Eina_Bool
+edje_edit_state_gradient_type_set(Evas_Object *obj, const char *part, const char *state, double value, const char *type)
+{
+   GET_PD_OR_RETURN(0);
+   if (!type) return 0;
+
+//   printf("SET GRADIENT TYPE for part: %s state: %s TO: %s\n", part, state, type);
+
+   _edje_if_string_free(ed, pd->gradient.type);
+   pd->gradient.type = (char *)eina_stringshare_add(type);
+   edje_object_calc_force(obj);
+   return 1;
+}
+
+
+EAPI Eina_Bool
+edje_edit_state_gradient_use_fill_get(Evas_Object *obj, const char *part, const char *state, double value)
+{
+   GET_PD_OR_RETURN(-1);
+
+   if (!pd->gradient.type)
+      return -1;
+
+   //~ if (!strcmp(pd->gradient.type, "linear"))
+      //~ return 0;
+   return 1;
+}
+
+EAPI const char *
+edje_edit_state_gradient_spectra_get(Evas_Object *obj, const char *part, const char *state, double value)
+{
+   Edje_Spectrum_Directory_Entry *s;
+
+   GET_PD_OR_RETURN(0);
+
+   //printf("GET GRADIENT SPECTRA for part: %s state: %s\n", part, state);
+   s = _edje_edit_spectrum_entry_get_by_id(ed, pd->gradient.id);
+   if (!s) return 0;
+
+   return eina_stringshare_add(s->entry);
+}
+
+EAPI Eina_Bool
+edje_edit_state_gradient_spectra_set(Evas_Object *obj, const char *part, const char *state, double value, const char* spectra)
+{
+   Edje_Spectrum_Directory_Entry *s;
+
+   GET_PD_OR_RETURN(0);
+
+   //printf("SET GRADIENT SPECTRA for part: %s state: %s [%s]\n", part, state, spectra);
+
+   s = _edje_edit_spectrum_entry_get(ed, spectra);
+   if (!s) return 0;
+
+   pd->gradient.id = s->id;
+   edje_object_calc_force(obj);
+
+   return 1;
+}
+
+EAPI int
+edje_edit_state_gradient_angle_get(Evas_Object *obj, const char *part, const char *state, double value)
+{
+   GET_PD_OR_RETURN(0);
+   return pd->fill.angle;
+}
+
+EAPI void
+edje_edit_state_gradient_angle_set(Evas_Object *obj, const char *part, const char *state, double value, int angle)
+{
+   GET_PD_OR_RETURN();
+   pd->fill.angle = angle;
+   edje_object_calc_force(obj);
+}
+
+EAPI double
+edje_edit_state_gradient_rel1_relative_x_get(Evas_Object *obj, const char *part, const char *state, double value)
+{
+   GET_PD_OR_RETURN(0);
+   //printf("GET GRADIENT REL1 RELX for part: %s state: %s [%f]\n", part, state, pd->gradient.rel1.relative_x);
+
+   return TO_DOUBLE(pd->gradient.rel1.relative_x);
+}
+
+EAPI double
+edje_edit_state_gradient_rel1_relative_y_get(Evas_Object *obj, const char *part, const char *state, double value)
+{
+   GET_PD_OR_RETURN(0);
+   //printf("GET GRADIENT REL1 RELY for part: %s state: %s [%f]\n", part, state, pd->gradient.rel1.relative_y);
+
+   return TO_DOUBLE(pd->gradient.rel1.relative_y);
+}
+
+EAPI double
+edje_edit_state_gradient_rel2_relative_x_get(Evas_Object *obj, const char *part, const char *state, double value)
+{
+   GET_PD_OR_RETURN(0);
+   //printf("GET GRADIENT REL2 RELX for part: %s state: %s [%f]\n", part, state, pd->gradient.rel2.relative_x);
+
+   return TO_DOUBLE(pd->gradient.rel2.relative_x);
+}
+
+EAPI double
+edje_edit_state_gradient_rel2_relative_y_get(Evas_Object *obj, const char *part, const char *state, double value)
+{
+   GET_PD_OR_RETURN(0);
+   //printf("GET GRADIENT REL2 RELY for part: %s state: %s [%f]\n", part, state, pd->gradient.rel2.relative_y);
+
+   return TO_DOUBLE(pd->gradient.rel2.relative_y);
+}
+
+EAPI Eina_Bool
+edje_edit_state_gradient_rel1_relative_x_set(Evas_Object *obj, const char *part, const char *state, double value, double val)
+{
+   GET_PD_OR_RETURN(0);
+   //printf("SET GRADIENT REL1 RELX for part: %s state: %s [TO %f]\n", part, state, val);
+
+   pd->gradient.rel1.relative_x = FROM_DOUBLE(val);
+   edje_object_calc_force(obj);
+   return 1;
+}
+
+EAPI Eina_Bool
+edje_edit_state_gradient_rel1_relative_y_set(Evas_Object *obj, const char *part, const char *state, double value, double val)
+{
+   GET_PD_OR_RETURN(0);
+   //printf("SET GRADIENT REL1 RELY for part: %s state: %s [TO %f]\n", part, state, val);
+
+   pd->gradient.rel1.relative_y = FROM_DOUBLE(val);
+   edje_object_calc_force(obj);
+   return 1;
+}
+
+EAPI Eina_Bool
+edje_edit_state_gradient_rel2_relative_x_set(Evas_Object *obj, const char *part, const char *state, double value, double val)
+{
+   GET_PD_OR_RETURN(0);
+   //printf("SET GRADIENT REL2 RELX for part: %s state: %s [TO %f]\n", part, state, val);
+
+   pd->gradient.rel2.relative_x = FROM_DOUBLE(val);
+   edje_object_calc_force(obj);
+   return 1;
+}
+
+EAPI Eina_Bool
+edje_edit_state_gradient_rel2_relative_y_set(Evas_Object *obj, const char *part, const char *state, double value, double val)
+{
+   GET_PD_OR_RETURN(0);
+   //printf("SET GRADIENT REL2 RELY for part: %s state: %s [TO %f]\n", part, state, val);
+
+   pd->gradient.rel2.relative_y = FROM_DOUBLE(val);
+   edje_object_calc_force(obj);
+   return 1;
+}
+
+EAPI int
+edje_edit_state_gradient_rel1_offset_x_get(Evas_Object *obj, const char *part, const char *state, double value)
+{
+   GET_PD_OR_RETURN(0);
+   //printf("GET GRADIENT REL1 OFFSETX for part: %s state: %s [%f]\n", part, state, pd->gradient.rel1.offset_x);
+   return pd->gradient.rel1.offset_x;
+}
+
+EAPI int
+edje_edit_state_gradient_rel1_offset_y_get(Evas_Object *obj, const char *part, const char *state, double value)
+{
+   GET_PD_OR_RETURN(0);
+   //printf("GET GRADIENT REL1 OFFSETY for part: %s state: %s [%f]\n", part, state, pd->gradient.rel1.offset_y);
+   return pd->gradient.rel1.offset_y;
+}
+
+EAPI int
+edje_edit_state_gradient_rel2_offset_x_get(Evas_Object *obj, const char *part, const char *state, double value)
+{
+   GET_PD_OR_RETURN(0);
+   //printf("GET GRADIENT REL2 OFFSETX for part: %s state: %s [%f]\n", part, state, pd->gradient.rel2.offset_x);
+   return pd->gradient.rel2.offset_x;
+}
+
+EAPI int
+edje_edit_state_gradient_rel2_offset_y_get(Evas_Object *obj, const char *part, const char *state, double value)
+{
+   GET_PD_OR_RETURN(0);
+   //printf("GET GRADIENT REL2 OFFSETY for part: %s state: %s [%f]\n", part, state, pd->gradient.rel2.offset_y);
+   return pd->gradient.rel2.offset_y;
+}
+
+EAPI Eina_Bool
+edje_edit_state_gradient_rel1_offset_x_set(Evas_Object *obj, const char *part, const char *state, double value, int val)
+{
+   GET_PD_OR_RETURN(0);
+   //printf("SET GRADIENT REL1 OFFSETX for part: %s state: %s [TO %d]\n", part, state, val);
+
+   pd->gradient.rel1.offset_x = val;
+   edje_object_calc_force(obj);
+   return 1;
+}
+
+EAPI Eina_Bool
+edje_edit_state_gradient_rel1_offset_y_set(Evas_Object *obj, const char *part, const char *state, double value, int val)
+{
+   GET_PD_OR_RETURN(0);
+   //printf("SET GRADIENT REL1 OFFSETY for part: %s state: %s [TO %d]\n", part, state, val);
+
+   pd->gradient.rel1.offset_y = val;
+   edje_object_calc_force(obj);
+   return 1;
+}
+
+EAPI Eina_Bool
+edje_edit_state_gradient_rel2_offset_x_set(Evas_Object *obj, const char *part, const char *state, double value, int val)
+{
+   GET_PD_OR_RETURN(0);
+   //printf("SET GRADIENT REL2 OFFSETX for part: %s state: %s [TO %d]\n", part, state, val);
+
+   pd->gradient.rel2.offset_x = val;
+   edje_object_calc_force(obj);
+   return 1;
+}
+
+EAPI Eina_Bool
+edje_edit_state_gradient_rel2_offset_y_set(Evas_Object *obj, const char *part, const char *state, double value, int val)
+{
+   GET_PD_OR_RETURN(0);
+   //printf("SET GRADIENT REL2 OFFSETY for part: %s state: %s [TO %d]\n", part, state, val);
+
+   pd->gradient.rel2.offset_y = val;
+   edje_object_calc_force(obj);
+   return 1;
+}
+
+/******************/
+/*  PROGRAMS API  */
+/******************/
+Edje_Program *
+_edje_program_get_byname(Evas_Object *obj, const char *prog_name)
+{
+   Edje_Program *epr;
+   int i;
+
+   GET_ED_OR_RETURN(NULL);
+
+   if (!prog_name) return NULL;
+
+   for (i = 0; i < ed->table_programs_size; i++)
+     {
+       epr = ed->table_programs[i];
+       if ((epr->name) && (strcmp(epr->name, prog_name) == 0))
+         return epr;
+     }
+   return NULL;
+}
+
+EAPI Eina_List *
+edje_edit_programs_list_get(Evas_Object *obj)
+{
+   Eina_List *progs = NULL;
+   int i;
+
+   GET_ED_OR_RETURN(NULL);
+
+   //printf("EE: Found %d programs\n", ed->table_programs_size);
+
+   for (i = 0; i < ed->table_programs_size; i++)
+     {
+       Edje_Program *epr;
+
+       epr = ed->table_programs[i];
+       progs = eina_list_append(progs, eina_stringshare_add(epr->name));
+     }
+
+   return progs;
+}
+
+EAPI Eina_Bool
+edje_edit_program_add(Evas_Object *obj, const char *name)
+{
+   Edje_Program *epr;
+   Edje_Part_Collection *pc;
+
+   GET_ED_OR_RETURN(0);
+
+   //printf("ADD PROGRAM [new name: %s]\n", name);
+
+   //Check if program already exists
+   if (_edje_program_get_byname(obj, name))
+     return 0;
+
+   //Alloc Edje_Program or return
+   epr = _alloc(sizeof(Edje_Program));
+   if (!epr) return 0;
+
+   //Add program to group
+   pc = ed->collection;
+   pc->programs = eina_list_append(pc->programs, epr);
+
+   //Init Edje_Program
+   epr->id = eina_list_count(pc->programs) - 1;
+   epr->name = eina_stringshare_add(name);
+   epr->signal = NULL;
+   epr->source = NULL;
+   epr->filter.part = NULL;
+   epr->filter.state = NULL;
+   epr->in.from = 0.0;
+   epr->in.range = 0.0;
+   epr->action = 0;
+   epr->state = NULL;
+   epr->value = 0.0;
+   epr->state2 = NULL;
+   epr->value2 = 0.0;
+   epr->tween.mode = 1;
+   epr->tween.time = ZERO;
+   epr->targets = NULL;
+   epr->after = NULL;
+
+
+   //Update table_programs
+   ed->table_programs_size++;
+   ed->table_programs = realloc(ed->table_programs,
+                                sizeof(Edje_Program *) * ed->table_programs_size);
+   ed->table_programs[epr->id % ed->table_programs_size] = epr;
+
+   //Update patterns
+   _edje_programs_patterns_clean(ed);
+   _edje_programs_patterns_init(ed);
+
+   return 1;
+}
+
+EAPI Eina_Bool
+edje_edit_program_del(Evas_Object *obj, const char *prog)
+{
+   Eina_List *l, *l_next, *rem;
+   Edje_Part_Collection *pc;
+   Edje_Program *p;
+   int id, i;
+   int old_id = -1;
+
+   GET_ED_OR_RETURN(EINA_FALSE);
+   GET_EPR_OR_RETURN(EINA_FALSE);
+
+   pc = ed->collection;
+
+   rem = eina_list_nth_list(pc->programs, epr->id);
+   l = eina_list_last(pc->programs);
+   if (rem != l)
+     {
+       /* If the removed program is not the last in the list/table,
+        * put the last one in its place and update references to it later */
+       p = eina_list_data_get(l);
+       pc->programs = eina_list_remove_list(pc->programs, l);
+       pc->programs = eina_list_append_relative_list(pc->programs, p, rem);
+
+       ed->table_programs[epr->id] = p;
+       old_id = p->id;
+       p->id = epr->id;
+     }
+
+   //Remove program from programs list
+   id = epr->id;
+   pc->programs = eina_list_remove(pc->programs, epr);
+
+   //Free Edje_Program
+   _edje_if_string_free(ed, epr->name);
+   _edje_if_string_free(ed, epr->signal);
+   _edje_if_string_free(ed, epr->source);
+   _edje_if_string_free(ed, epr->filter.part);
+   _edje_if_string_free(ed, epr->filter.state);
+   _edje_if_string_free(ed, epr->state);
+   _edje_if_string_free(ed, epr->state2);
+
+   while (epr->targets)
+     {
+       Edje_Program_Target *prt;
+
+       prt = eina_list_data_get(epr->targets);
+       epr->targets = eina_list_remove_list(epr->targets, epr->targets);
+       free(prt);
+     }
+   while (epr->after)
+     {
+       Edje_Program_After *pa;
+
+       pa = eina_list_data_get(epr->after);
+       epr->after = eina_list_remove_list(epr->after, epr->after);
+       free(pa);
+     }
+   free(epr);
+
+   ed->table_programs_size--;
+   ed->table_programs = realloc(ed->table_programs,
+                             sizeof(Edje_Program *) * ed->table_programs_size);
+
+   //We also update all other programs that point to old_id and id
+   for (i = 0; i < ed->table_programs_size; i++)
+     {
+       Edje_Program_After *pa;
+
+       p = ed->table_programs[i];
+
+       /* check in afters */
+       EINA_LIST_FOREACH_SAFE(p->after, l, l_next, pa)
+         {
+            if (pa->id == old_id)
+              pa->id = id;
+            else if (pa->id == id)
+              p->after = eina_list_remove_list(p->after, l);
+         }
+       /* check in targets */
+       if (p->action == EDJE_ACTION_TYPE_ACTION_STOP)
+         {
+            Edje_Program_Target *pt;
+
+            EINA_LIST_FOREACH_SAFE(p->targets, l, l_next, pt)
+              {
+                 if (pt->id == old_id)
+                   pt->id = id;
+                 else if (pt->id == id)
+                   p->targets = eina_list_remove_list(p->targets, l);
+              }
+         }
+     }
+
+   return EINA_TRUE;
+}
+
+EAPI Eina_Bool
+edje_edit_program_exist(Evas_Object *obj, const char *prog)
+{
+   GET_EPR_OR_RETURN(0);
+
+   return 1;
+}
+
+EAPI Eina_Bool
+edje_edit_program_run(Evas_Object *obj, const char *prog)
+{
+   GET_ED_OR_RETURN(0);
+   GET_EPR_OR_RETURN(0);
+
+   _edje_program_run(ed, epr, 0, "", "");
+   return 1;
+}
+
+EAPI Eina_Bool
+edje_edit_program_name_set(Evas_Object *obj, const char *prog, const char* new_name)
+{
+   GET_ED_OR_RETURN(0);
+   GET_EPR_OR_RETURN(0);
+
+   if (!new_name) return 0;
+
+   if (_edje_program_get_byname(obj, new_name)) return 0;
+
+   //printf("SET NAME for program: %s [new name: %s]\n", prog, new_name);
+
+   _edje_if_string_free(ed, epr->name);
+   epr->name = eina_stringshare_add(new_name);
+
+   return 1;
+}
+
+EAPI const char *
+edje_edit_program_source_get(Evas_Object *obj, const char *prog)
+{
+   GET_EPR_OR_RETURN(NULL);
+
+   if (!epr->source) return NULL;
+   //printf("GET SOURCE for program: %s [%s]\n", prog, epr->source);
+   return eina_stringshare_add(epr->source);
+}
+
+EAPI Eina_Bool
+edje_edit_program_source_set(Evas_Object *obj, const char *prog, const char *source)
+{
+   GET_ED_OR_RETURN(0);
+   GET_EPR_OR_RETURN(0);
+
+   if (!source) return 0;
+
+   //printf("SET SOURCE for program: %s [%s]\n", prog, source);
+
+   _edje_if_string_free(ed, epr->source);
+   epr->source = eina_stringshare_add(source);
+
+   //Update patterns
+   if (ed->patterns.programs.sources_patterns)
+      edje_match_patterns_free(ed->patterns.programs.sources_patterns);
+   ed->patterns.programs.sources_patterns = edje_match_programs_source_init(ed->collection->programs);
+
+   return 1;
+}
+
+EAPI const char *
+edje_edit_program_filter_part_get(Evas_Object *obj, const char *prog)
+{
+   GET_EPR_OR_RETURN(NULL);
+
+   if (!epr->filter.part) return NULL;
+   return eina_stringshare_add(epr->filter.part);
+}
+
+EAPI Eina_Bool
+edje_edit_program_filter_part_set(Evas_Object *obj, const char *prog, const char *filter_part)
+{
+   GET_ED_OR_RETURN(0);
+   GET_EPR_OR_RETURN(0);
+
+   if (!filter_part) return 0;
+
+   _edje_if_string_free(ed, epr->filter.part);
+   epr->filter.part = eina_stringshare_add(filter_part);
+
+   return 1;
+}
+
+EAPI const char *
+edje_edit_program_filter_state_get(Evas_Object *obj, const char *prog)
+{
+   GET_EPR_OR_RETURN(NULL);
+
+   if (!epr->filter.state) return NULL;
+   return eina_stringshare_add(epr->filter.state);
+}
+
+EAPI Eina_Bool
+edje_edit_program_filter_state_set(Evas_Object *obj, const char *prog, const char *filter_state)
+{
+   GET_ED_OR_RETURN(0);
+   GET_EPR_OR_RETURN(0);
+
+   if (!filter_state) return 0;
+
+   _edje_if_string_free(ed, epr->filter.state);
+   epr->filter.state = eina_stringshare_add(filter_state);
+
+   return 1;
+}
+
+EAPI const char *
+edje_edit_program_signal_get(Evas_Object *obj, const char *prog)
+{
+   GET_EPR_OR_RETURN(NULL);
+
+   if (!epr->signal) return NULL;
+   //printf("GET SIGNAL for program: %s [%s]\n", prog, epr->signal);
+   return eina_stringshare_add(epr->signal);
+}
+
+EAPI Eina_Bool
+edje_edit_program_signal_set(Evas_Object *obj, const char *prog, const char *signal)
+{
+   GET_ED_OR_RETURN(0);
+   GET_EPR_OR_RETURN(0);
+
+   if (!signal) return 0;
+
+   //printf("SET SIGNAL for program: %s [%s]\n", prog, signal);
+
+   _edje_if_string_free(ed, epr->signal);
+   epr->signal = eina_stringshare_add(signal);
+
+   //Update patterns
+   if (ed->patterns.programs.signals_patterns)
+      edje_match_patterns_free(ed->patterns.programs.signals_patterns);
+   ed->patterns.programs.signals_patterns = edje_match_programs_signal_init(ed->collection->programs);
+
+   return 1;
+}
+
+EAPI const char *
+edje_edit_program_state_get(Evas_Object *obj, const char *prog)
+{
+   GET_EPR_OR_RETURN(NULL);
+
+   if (!epr->state) return NULL;
+   //printf("GET STATE for program: %s [%s %.2f]\n", prog, epr->state, epr->value);
+   return eina_stringshare_add(epr->state);
+}
+
+EAPI Eina_Bool
+edje_edit_program_state_set(Evas_Object *obj, const char *prog, const char *state)
+{
+   GET_ED_OR_RETURN(0);
+   GET_EPR_OR_RETURN(0);
+
+   //printf("SET STATE for program: %s\n", prog);
+
+   _edje_if_string_free(ed, epr->state);
+   epr->state = eina_stringshare_add(state);
+
+   return 1;
+}
+
+EAPI const char *
+edje_edit_program_state2_get(Evas_Object *obj, const char *prog)
+{
+   GET_EPR_OR_RETURN(NULL);
+
+   if (!epr->state2) return NULL;
+   //printf("GET STATE2 for program: %s [%s %.2f]\n", prog, epr->state2, epr->value2);
+   return eina_stringshare_add(epr->state2);
+}
+
+EAPI Eina_Bool
+edje_edit_program_state2_set(Evas_Object *obj, const char *prog, const char *state2)
+{
+   GET_ED_OR_RETURN(0);
+   GET_EPR_OR_RETURN(0);
+
+   //printf("SET STATE2 for program: %s\n", prog);
+
+   _edje_if_string_free(ed, epr->state2);
+   epr->state2 = eina_stringshare_add(state2);
+
+   return 1;
+}
+
+EAPI double
+edje_edit_program_value_get(Evas_Object *obj, const char *prog)
+{
+   GET_EPR_OR_RETURN(-1);
+
+   //printf("GET VALUE for program: %s [%s %.2f]\n", prog, epr->state, epr->value);
+   return epr->value;
+}
+
+EAPI Eina_Bool
+edje_edit_program_value_set(Evas_Object *obj, const char *prog, double value)
+{
+   GET_EPR_OR_RETURN(0);
+
+   //printf("SET VALUE for program: %s [%.2f]\n", prog, value);
+   epr->value = value;
+   return 1;
+}
+
+EAPI double
+edje_edit_program_value2_get(Evas_Object *obj, const char *prog)
+{
+   GET_EPR_OR_RETURN(-1);
+
+   //printf("GET VALUE2 for program: %s [%s %.2f]\n", prog, epr->state2, epr->value2);
+   return epr->value2;
+}
+
+EAPI Eina_Bool
+edje_edit_program_value2_set(Evas_Object *obj, const char *prog, double value)
+{
+   GET_EPR_OR_RETURN(0);
+
+   //printf("SET VALUE for program: %s [%.2f]\n", prog, value);
+   epr->value2 = value;
+   return 1;
+}
+
+EAPI double
+edje_edit_program_in_from_get(Evas_Object *obj, const char *prog)
+{
+   GET_EPR_OR_RETURN(0);
+
+   //printf("GET IN.FROM for program: %s [%f]\n", prog, epr->in.from);
+   return epr->in.from;
+}
+
+EAPI Eina_Bool
+edje_edit_program_in_from_set(Evas_Object *obj, const char *prog, double seconds)
+{
+   GET_EPR_OR_RETURN(0);
+
+   //printf("SET IN.FROM for program: %s [%f]\n", prog, epr->in.from);
+   epr->in.from = seconds;
+   return 1;
+}
+
+EAPI double
+edje_edit_program_in_range_get(Evas_Object *obj, const char *prog)
+{
+   GET_EPR_OR_RETURN(0);
+
+   //printf("GET IN.RANGE for program: %s [%f]\n", prog, epr->in.range);
+   return epr->in.range;
+}
+
+EAPI Eina_Bool
+edje_edit_program_in_range_set(Evas_Object *obj, const char *prog, double seconds)
+{
+   GET_EPR_OR_RETURN(0);
+
+   //printf("SET IN.RANGE for program: %s [%f]\n", prog, epr->in.range);
+   epr->in.range = seconds;
+   return 1;
+}
+
+EAPI Edje_Tween_Mode
+edje_edit_program_transition_get(Evas_Object *obj, const char *prog)
+{
+   GET_EPR_OR_RETURN(-1);
+
+   //printf("GET TRANSITION for program: %s [%d]\n", prog, epr->tween.mode);
+   return epr->tween.mode;
+}
+
+EAPI Eina_Bool
+edje_edit_program_transition_set(Evas_Object *obj, const char *prog, Edje_Tween_Mode transition)
+{
+   GET_EPR_OR_RETURN(0);
+
+   //printf("GET TRANSITION for program: %s [%d]\n", prog, epr->tween.mode);
+   epr->tween.mode = transition;
+   return 1;
+}
+
+EAPI double
+edje_edit_program_transition_time_get(Evas_Object *obj, const char *prog)
+{
+   GET_EPR_OR_RETURN(-1);
+
+   //printf("GET TRANSITION_TIME for program: %s [%.4f]\n", prog, epr->tween.time);
+   return TO_DOUBLE(epr->tween.time);
+}
+
+EAPI Eina_Bool
+edje_edit_program_transition_time_set(Evas_Object *obj, const char *prog, double seconds)
+{
+   GET_EPR_OR_RETURN(0);
+
+   //printf("GET TRANSITION_TIME for program: %s [%.4f]\n", prog, epr->tween.time);
+   epr->tween.time = FROM_DOUBLE(seconds);
+   return 1;
+}
+
+EAPI Edje_Action_Type
+edje_edit_program_action_get(Evas_Object *obj, const char *prog)
+{
+   GET_EPR_OR_RETURN(-1);
+
+   //printf("GET ACTION for program: %s [%d]\n", prog, epr->action);
+   return epr->action;
+}
+
+EAPI Eina_Bool
+edje_edit_program_action_set(Evas_Object *obj, const char *prog, Edje_Action_Type action)
+{
+   GET_EPR_OR_RETURN(0);
+
+   //printf("SET ACTION for program: %s [%d]\n", prog, action);
+   if (action >= EDJE_ACTION_TYPE_LAST) return 0;
+
+   epr->action = action;
+   return 1;
+}
+
+EAPI Eina_List *
+edje_edit_program_targets_get(Evas_Object *obj, const char *prog)
+{
+   Eina_List *l, *targets = NULL;
+   Edje_Program_Target *t;
+
+   GET_ED_OR_RETURN(NULL);
+   GET_EPR_OR_RETURN(NULL);
+
+   //printf("GET TARGETS for program: %s [count: %d]\n", prog, eina_list_count(epr->targets));
+   EINA_LIST_FOREACH(epr->targets, l, t)
+     {
+       if (epr->action == EDJE_ACTION_TYPE_STATE_SET)
+         {
+            /* the target is a part */
+            Edje_Real_Part *p = NULL;
+
+            p = ed->table_parts[t->id % ed->table_parts_size];
+            if (p && p->part && p->part->name)
+              targets = eina_list_append(targets,
+                    eina_stringshare_add(p->part->name));
+         }
+       else if (epr->action == EDJE_ACTION_TYPE_ACTION_STOP)
+         {
+            /* the target is a program */
+            Edje_Program *p;
+
+            p = ed->table_programs[t->id % ed->table_programs_size];
+            if (p && p->name)
+              targets = eina_list_append(targets,
+                    eina_stringshare_add(p->name));
+         }
+     }
+   return targets;
+}
+
+EAPI Eina_Bool
+edje_edit_program_targets_clear(Evas_Object *obj, const char *prog)
+{
+   GET_EPR_OR_RETURN(0);
+
+   while (epr->targets)
+     {
+       Edje_Program_Target *prt;
+
+       prt = eina_list_data_get(epr->targets);
+       epr->targets = eina_list_remove_list(epr->targets, epr->targets);
+       free(prt);
+     }
+
+   return 1;
+}
+
+EAPI Eina_Bool
+edje_edit_program_target_add(Evas_Object *obj, const char *prog, const char *target)
+{
+   int id;
+   Edje_Program_Target *t;
+
+   GET_ED_OR_RETURN(0);
+   GET_EPR_OR_RETURN(0);
+
+   if (epr->action == EDJE_ACTION_TYPE_STATE_SET)
+     {
+       /* the target is a part */
+       Edje_Real_Part *rp;
+
+       rp = _edje_real_part_get(ed, target);
+       if (!rp) return 0;
+       id = rp->part->id;
+     }
+   else if (epr->action == EDJE_ACTION_TYPE_ACTION_STOP)
+     {
+       /* the target is a program */
+       Edje_Program *tar;
+
+       tar = _edje_program_get_byname(obj, target);
+       if (!tar) return 0;
+       id = tar->id;
+     }
+   else
+     return 0;
+
+   t = _alloc(sizeof(Edje_Program_Target));
+   if (!t) return 0;
+
+   t->id = id;
+   epr->targets = eina_list_append(epr->targets, t);
+
+   return 1;
+}
+
+EAPI Eina_Bool
+edje_edit_program_target_del(Evas_Object *obj, const char *prog, const char *target)
+{
+   int id;
+   Eina_List *l;
+   Edje_Program_Target *t;
+
+   GET_ED_OR_RETURN(EINA_FALSE);
+   GET_EPR_OR_RETURN(EINA_FALSE);
+
+   if (epr->action == EDJE_ACTION_TYPE_STATE_SET)
+     {
+       /* the target is a part */
+       Edje_Real_Part *rp;
+
+       rp = _edje_real_part_get(ed, target);
+       if (!rp) return EINA_FALSE;
+       id = rp->part->id;
+     }
+   else if (epr->action == EDJE_ACTION_TYPE_ACTION_STOP)
+     {
+       /* the target is a program */
+       Edje_Program *tar;
+
+       tar = _edje_program_get_byname(obj, target);
+       if (!tar) return EINA_FALSE;
+       id = tar->id;
+     }
+   else
+     return EINA_FALSE;
+
+   EINA_LIST_FOREACH(epr->targets, l, t)
+      if (t->id == id)
+       break;
+   epr->targets = eina_list_remove_list(epr->targets, l);
+   free(t);
+
+   return EINA_TRUE;
+}
+
+EAPI Eina_List *
+edje_edit_program_afters_get(Evas_Object *obj, const char *prog)
+{
+   Eina_List *l, *afters = NULL;
+   Edje_Program_After *a;
+
+   GET_ED_OR_RETURN(NULL);
+   GET_EPR_OR_RETURN(NULL);
+
+  // printf("GET AFTERS for program: %s [count: %d]\n", prog, eina_list_count(epr->after));
+   EINA_LIST_FOREACH(epr->after, l, a)
+     {
+       Edje_Program *p = NULL;
+
+       p = ed->table_programs[a->id % ed->table_programs_size];
+       if (p && p->name)
+         {
+            //printf("   a: %d name: %s\n", a->id, p->name);
+            afters = eina_list_append(afters, eina_stringshare_add(p->name));
+         }
+     }
+   return afters;
+}
+
+EAPI Eina_Bool
+edje_edit_program_afters_clear(Evas_Object *obj, const char *prog)
+{
+   GET_EPR_OR_RETURN(0);
+
+   while (epr->after)
+     {
+       Edje_Program_After *pa;
+
+       pa = eina_list_data_get(epr->after);
+       epr->after = eina_list_remove_list(epr->after, epr->after);
+       free(pa);
+     }
+
+   return 1;
+}
+
+EAPI Eina_Bool
+edje_edit_program_after_add(Evas_Object *obj, const char *prog, const char *after)
+{
+   Edje_Program *af;
+   Edje_Program_After *a;
+
+   GET_EPR_OR_RETURN(0);
+
+   af = _edje_program_get_byname(obj, after);
+   if (!af) return 0;
+
+   a = _alloc(sizeof(Edje_Program_After));
+   if (!a) return 0;
+
+   a->id = af->id;
+
+   epr->after = eina_list_append(epr->after, a);
+
+   return 1;
+}
+
+EAPI Eina_Bool
+edje_edit_program_after_del(Evas_Object *obj, const char *prog, const char *after)
+{
+   Edje_Program *af;
+   Edje_Program_After *a;
+   Eina_List *l;
+
+   GET_EPR_OR_RETURN(EINA_FALSE);
+
+   af = _edje_program_get_byname(obj, after);
+   if (!af) return EINA_FALSE;
+
+   EINA_LIST_FOREACH(epr->after, l, a)
+      if (a->id == af->id)
+       {
+          epr->after = eina_list_remove_list(epr->after, l);
+          break;
+       }
+
+   return EINA_TRUE;
+}
+
+/*************************/
+/*  EMBRYO SCRIPTS  API  */
+/*************************/
+EAPI const char *
+edje_edit_script_get(Evas_Object *obj)
+{
+   Embryo_Program   *script = NULL;
+
+   GET_ED_OR_RETURN(NULL);
+
+   if (!ed->collection) return NULL;
+   if (!ed->collection->script) return NULL;
+
+   script = ed->collection->script;
+
+   printf("Get Script [%p] %d\n", script, embryo_program_recursion_get(script));
+
+   return "Not yet complete...";
+}
+
+
+/***************************/
+/*  EDC SOURCE GENERATION  */
+/***************************/
+#define I0 ""
+#define I1 "   "
+#define I2 "      "
+#define I3 "         "
+#define I4 "            "
+#define I5 "               "
+#define I6 "                  "
+#define I7 "                     "
+
+#define BUF_APPEND(STR) \
+   ret &= eina_strbuf_append(buf, STR)
+
+#define BUF_APPENDF(FMT, ...) \
+   ret &= eina_strbuf_append_printf(buf, FMT, ##__VA_ARGS__)
+
+static char *types[] = {"NONE", "RECT", "TEXT", "IMAGE", "SWALLOW", "TEXTBLOCK", "GRADIENT", "GROUP", "BOX", "TABLE", "EXTERNAL"};
+static char *effects[] = {"NONE", "PLAIN", "OUTLINE", "SOFT_OUTLINE", "SHADOW", "SOFT_SHADOW", "OUTLINE_SHADOW", "OUTLINE_SOFT_SHADOW ", "FAR_SHADOW ", "FAR_SOFT_SHADOW", "GLOW"};
+static char *prefers[] = {"NONE", "VERTICAL", "HORIZONTAL", "BOTH"};
+static Eina_Bool
+_edje_generate_source_of_spectra(Edje * ed, const char *name, Eina_Strbuf *buf)
+{
+   Edje_Spectrum_Directory_Entry *d;
+   Edje_Spectrum_Color *color = NULL;
+   Eina_List *l;
+   Eina_Bool ret = EINA_TRUE;
+
+   if (!ed || !name || !buf) return EINA_FALSE;
+
+   if ((d = _edje_edit_spectrum_entry_get(ed, name)))
+     {
+       BUF_APPENDF(I1 "spectrum { name: \"%s\";\n", d->entry);
+
+       EINA_LIST_FOREACH(d->color_list, l, color)
+         if (color)
+           BUF_APPENDF(I2 "color: %d %d %d %d %d;\n", color->r, color->g,
+                       color->b, color->a, color->d);
+
+       BUF_APPEND(I1 "}\n");
+     }
+   return ret;
+}
+
+ static Eina_Bool
+_edje_generate_source_of_colorclass(Edje * ed, const char *name, Eina_Strbuf *buf)
+{
+   Eina_List *l;
+   Edje_Color_Class *cc;
+   Eina_Bool ret = EINA_TRUE;
+
+   EINA_LIST_FOREACH(ed->file->color_classes, l, cc)
+     if (!strcmp(cc->name, name))
+       {
+        BUF_APPENDF(I1 "color_class { name: \"%s\";\n", cc->name);
+        BUF_APPENDF(I2 "color: %d %d %d %d;\n", cc->r, cc->g, cc->b, cc->a);
+        BUF_APPENDF(I2 "color2: %d %d %d %d;\n", cc->r2, cc->g2, cc->b2, cc->a2);
+        BUF_APPENDF(I2 "color3: %d %d %d %d;\n", cc->r3, cc->g3, cc->b3, cc->a3);
+        BUF_APPEND(I1 "}\n");
+       }
+   return ret;
+}
+
+ static Eina_Bool
+_edje_generate_source_of_style(Edje * ed, const char *name, Eina_Strbuf *buf)
+{
+   Eina_List *l, *ll;
+   Edje_Style *s;
+   Edje_Style_Tag *t;
+   Eina_Bool ret = EINA_TRUE;
+
+   EINA_LIST_FOREACH(ed->file->styles, l, s)
+     if (!strcmp(s->name, name))
+       {
+        t = s->tags ? s->tags->data : NULL;
+        BUF_APPENDF(I1 "style { name:\"%s\";\n", s->name);
+        if (t && t->value)
+          BUF_APPENDF(I2 "base: \"%s\";\n", t->value);
+
+        EINA_LIST_FOREACH(s->tags, ll, t)
+          if (ll->prev && t && t->value)
+            BUF_APPENDF(I2 "tag: \"%s\" \"%s\";\n", t->key,
+                               t->value);
+        BUF_APPEND(I1 "}\n");
+        return ret;
+       }
+   return EINA_FALSE;
+}
+
+static Eina_Bool
+_edje_generate_source_of_program(Evas_Object *obj, const char *program, Eina_Strbuf *buf)
+{
+   Eina_List *l, *ll;
+   const char *s, *s2;
+   double db, db2;
+   char *data;
+   Eina_Bool ret = EINA_TRUE;
+
+   GET_ED_OR_RETURN(EINA_FALSE);
+
+   BUF_APPENDF(I3"program { name: \"%s\";\n", program);
+
+   /* Signal */
+   if ((s = edje_edit_program_signal_get(obj, program)))
+     {
+       BUF_APPENDF(I4"signal: \"%s\";\n", s);
+       edje_edit_string_free(s);
+     }
+
+   /* Source */
+   if ((s = edje_edit_program_source_get(obj, program)))
+     {
+       BUF_APPENDF(I4"source: \"%s\";\n", s);
+       edje_edit_string_free(s);
+     }
+
+   /* Action */
+   switch (edje_edit_program_action_get(obj, program))
+     {
+     case EDJE_ACTION_TYPE_ACTION_STOP:
+       BUF_APPEND(I4"action: ACTION_STOP;\n");
+       break;
+     case EDJE_ACTION_TYPE_STATE_SET:
+       if ((s = edje_edit_program_state_get(obj, program)))
+         {
+               BUF_APPENDF(I4"action: STATE_SET \"%s\" %.2f;\n", s,
+                       edje_edit_program_value_get(obj, program));
+               edje_edit_string_free(s);
+         }
+       break;
+     case EDJE_ACTION_TYPE_SIGNAL_EMIT:
+       s = edje_edit_program_state_get(obj, program);
+       s2 = edje_edit_program_state2_get(obj, program);
+       if (s && s2)
+         {
+               BUF_APPENDF(I4"action: SIGNAL_EMIT \"%s\" \"%s\";\n", s, s2);
+               edje_edit_string_free(s);
+               edje_edit_string_free(s2);
+         }
+       break;
+     //TODO Support Drag
+     //~ case EDJE_ACTION_TYPE_DRAG_VAL_SET:
+       //~ eina_strbuf_append(buf, I4"action: DRAG_VAL_SET TODO;\n");
+       //~ break;
+     //~ case EDJE_ACTION_TYPE_DRAG_VAL_STEP:
+       //~ eina_strbuf_append(buf, I4"action: DRAG_VAL_STEP TODO;\n");
+       //~ break;
+     //~ case EDJE_ACTION_TYPE_DRAG_VAL_PAGE:
+       //~ eina_strbuf_append(buf, I4"action: DRAG_VAL_PAGE TODO;\n");
+       //~ break;
+     default:
+       break;
+     }
+
+   /* Transition */
+   db = edje_edit_program_transition_time_get(obj, program);
+   switch (edje_edit_program_transition_get(obj, program))
+     {
+     case EDJE_TWEEN_MODE_LINEAR:
+       BUF_APPENDF(I4"transition: LINEAR %.5f;\n", db);
+       break;
+     case EDJE_TWEEN_MODE_ACCELERATE:
+       BUF_APPENDF(I4"transition: ACCELERATE %.5f;\n", db);
+       break;
+     case EDJE_TWEEN_MODE_DECELERATE:
+       BUF_APPENDF(I4"transition: DECELERATE %.5f;\n", db);
+       break;
+     case EDJE_TWEEN_MODE_SINUSOIDAL:
+       BUF_APPENDF(I4"transition: SINUSOIDAL %.5f;\n", db);
+       break;
+     default:
+       break;
+     }
+
+   /* In */
+   db = edje_edit_program_in_from_get(obj, program);
+   db2 = edje_edit_program_in_range_get(obj, program);
+   if (db || db2)
+     BUF_APPENDF(I4"in: %.5f %.5f;\n", db, db2);
+
+   /* Targets */
+   if ((ll = edje_edit_program_targets_get(obj, program)))
+     {
+       EINA_LIST_FOREACH(ll, l, data)
+         BUF_APPENDF(I4"target: \"%s\";\n", data);
+       edje_edit_string_list_free(ll);
+     }
+
+   /* Afters */
+   if ((ll = edje_edit_program_afters_get(obj, program)))
+     {
+        EINA_LIST_FOREACH(ll, l, data)
+         BUF_APPENDF(I4"after: \"%s\";\n", data);
+       edje_edit_string_list_free(ll);
+     }
+
+   // TODO Support script {}
+
+   BUF_APPEND(I3 "}\n");
+   return ret;
+}
+
+static Eina_Bool
+_edje_generate_source_of_state(Evas_Object *obj, const char *part, const char *state, double value, Eina_Strbuf *buf)
+{
+   Eina_List *l, *ll;
+   Edje_Real_Part *rp;
+   const char *str;
+   Eina_Bool ret = EINA_TRUE;
+
+   GET_PD_OR_RETURN(EINA_FALSE);
+
+   rp = _edje_real_part_get(ed, part);
+   if (!rp) return EINA_FALSE;
+
+   BUF_APPENDF(I4"description { state: \"%s\" %g;\n", pd->state.name, pd->state.value);
+   //TODO Support inherit
+
+   if (!pd->visible)
+     BUF_APPEND(I5"visible: 0;\n");
+
+   if (pd->align.x != 0.5 || pd->align.y != 0.5)
+     BUF_APPENDF(I5"align: %g %g;\n", TO_DOUBLE(pd->align.x), TO_DOUBLE(pd->align.y));
+
+   //TODO Support fixed
+
+   if (pd->min.w || pd->min.h)
+     BUF_APPENDF(I5"min: %d %d;\n", pd->min.w, pd->min.h);
+   if (pd->max.w != -1 || pd->max.h != -1)
+     BUF_APPENDF(I5"max: %d %d;\n", pd->max.w, pd->max.h);
+
+   //TODO Support step
+
+   if (pd->aspect.min || pd->aspect.max)
+      BUF_APPENDF(I5"aspect: %g %g;\n", TO_DOUBLE(pd->aspect.min), TO_DOUBLE(pd->aspect.max));
+   if (pd->aspect.prefer)
+      BUF_APPENDF(I5"aspect_preference: %s;\n", prefers[pd->aspect.prefer]);
+
+   if (pd->color_class)
+      BUF_APPENDF(I5"color_class: \"%s\";\n", pd->color_class);
+
+   if (pd->color.r != 255 || pd->color.g != 255 ||
+       pd->color.b != 255 ||  pd->color.a != 255)
+      BUF_APPENDF(I5"color: %d %d %d %d;\n",
+              pd->color.r, pd->color.g, pd->color.b, pd->color.a);
+   if (pd->color2.r != 0 || pd->color2.g != 0 ||
+        pd->color2.b != 0 ||  pd->color2.a != 255)
+      BUF_APPENDF(I5"color2: %d %d %d %d;\n",
+              pd->color2.r, pd->color2.g, pd->color2.b, pd->color2.a);
+   if (pd->color3.r != 0 || pd->color3.g != 0 ||
+        pd->color3.b != 0 ||  pd->color3.a != 128)
+      BUF_APPENDF(I5"color3: %d %d %d %d;\n",
+              pd->color3.r, pd->color3.g, pd->color3.b, pd->color3.a);
+
+   //Rel1
+   if (pd->rel1.relative_x || pd->rel1.relative_y || pd->rel1.offset_x ||
+       pd->rel1.offset_y || pd->rel1.id_x != -1 || pd->rel1.id_y != -1)
+     {
+       BUF_APPEND(I5"rel1 {\n");
+       if (pd->rel1.relative_x || pd->rel1.relative_y)
+         BUF_APPENDF(I6"relative: %g %g;\n", TO_DOUBLE(pd->rel1.relative_x), TO_DOUBLE(pd->rel1.relative_y));
+       if (pd->rel1.offset_x || pd->rel1.offset_y)
+         BUF_APPENDF(I6"offset: %d %d;\n", pd->rel1.offset_x, pd->rel1.offset_y);
+       if (pd->rel1.id_x != -1 && pd->rel1.id_x == pd->rel1.id_y)
+         BUF_APPENDF(I6"to: \"%s\";\n", ed->table_parts[pd->rel1.id_x]->part->name);
+       else
+         {
+               if (pd->rel1.id_x != -1)
+                 BUF_APPENDF(I6"to_x: \"%s\";\n", ed->table_parts[pd->rel1.id_x]->part->name);
+               if (pd->rel1.id_y != -1)
+                 BUF_APPENDF(I6"to_y: \"%s\";\n", ed->table_parts[pd->rel1.id_y]->part->name);
+         }
+       BUF_APPEND(I5"}\n");//rel1
+     }
+
+   //Rel2
+   if (pd->rel2.relative_x != 1.0 || pd->rel2.relative_y != 1.0 ||
+       pd->rel2.offset_x != -1 || pd->rel2.offset_y != -1 ||
+       pd->rel2.id_x != -1 || pd->rel2.id_y != -1)
+     {
+       BUF_APPEND(I5"rel2 {\n");
+       if (TO_DOUBLE(pd->rel2.relative_x) != 1.0 || TO_DOUBLE(pd->rel2.relative_y) != 1.0)
+         BUF_APPENDF(I6"relative: %g %g;\n", TO_DOUBLE(pd->rel2.relative_x), TO_DOUBLE(pd->rel2.relative_y));
+       if (pd->rel2.offset_x != -1 || pd->rel2.offset_y != -1)
+         BUF_APPENDF(I6"offset: %d %d;\n", pd->rel2.offset_x, pd->rel2.offset_y);
+       if (pd->rel2.id_x != -1 && pd->rel2.id_x == pd->rel2.id_y)
+         BUF_APPENDF(I6"to: \"%s\";\n", ed->table_parts[pd->rel2.id_x]->part->name);
+       else
+         {
+               if (pd->rel2.id_x != -1)
+                 BUF_APPENDF(I6"to_x: \"%s\";\n", ed->table_parts[pd->rel2.id_x]->part->name);
+               if (pd->rel2.id_y != -1)
+                 BUF_APPENDF(I6"to_y: \"%s\";\n", ed->table_parts[pd->rel2.id_y]->part->name);
+         }
+       BUF_APPEND(I5"}\n");//rel2
+     }
+
+   //Image
+   if (rp->part->type == EDJE_PART_TYPE_IMAGE)
+     {
+        char *data;
+
+       BUF_APPEND(I5"image {\n");
+       BUF_APPENDF(I6"normal: \"%s\";\n", _edje_image_name_find(obj, pd->image.id));
+
+       ll = edje_edit_state_tweens_list_get(obj, part, state, value);
+       EINA_LIST_FOREACH(ll, l, data)
+         BUF_APPENDF(I6"tween: \"%s\";\n", data);
+       edje_edit_string_list_free(ll);
+
+       if (pd->border.l || pd->border.r || pd->border.t || pd->border.b)
+         BUF_APPENDF(I6"border: %d %d %d %d;\n", pd->border.l, pd->border.r, pd->border.t, pd->border.b);
+       if (pd->border.no_fill == 1)
+         BUF_APPEND(I6"middle: NONE;\n");
+       else if (pd->border.no_fill == 0)
+         BUF_APPEND(I6"middle: DEFAULT;\n");
+       else if (pd->border.no_fill == 2)
+         BUF_APPEND(I6"middle: SOLID;\n");
+
+       BUF_APPEND(I5"}\n");//image
+     }
+
+   //Fill
+   if (rp->part->type == EDJE_PART_TYPE_IMAGE ||
+       rp->part->type == EDJE_PART_TYPE_GRADIENT)
+     {
+       BUF_APPEND(I5"fill {\n");
+       if (rp->part->type == EDJE_PART_TYPE_IMAGE && !pd->fill.smooth)
+         BUF_APPEND(I6"smooth: 0;\n");
+        //TODO Support spread
+       if (rp->part->type == EDJE_PART_TYPE_GRADIENT && pd->fill.angle)
+         BUF_APPENDF(I6"angle: %d;\n", pd->fill.angle);
+        //TODO Support type
+
+       if (pd->fill.pos_rel_x || pd->fill.pos_rel_y ||
+            pd->fill.pos_abs_x || pd->fill.pos_abs_y)
+         {
+               BUF_APPEND(I6"origin {\n");
+               if (pd->fill.pos_rel_x || pd->fill.pos_rel_y)
+                 BUF_APPENDF(I7"relative: %g %g;\n", TO_DOUBLE(pd->fill.pos_rel_x), TO_DOUBLE(pd->fill.pos_rel_y));
+               if (pd->fill.pos_abs_x || pd->fill.pos_abs_y)
+                 BUF_APPENDF(I7"offset: %d %d;\n", pd->fill.pos_abs_x, pd->fill.pos_abs_y);
+               BUF_APPEND(I6"}\n");
+          }
+
+       if (TO_DOUBLE(pd->fill.rel_x) != 1.0 || TO_DOUBLE(pd->fill.rel_y) != 1.0 ||
+            pd->fill.abs_x || pd->fill.abs_y)
+         {
+               BUF_APPEND(I6"size {\n");
+               if (pd->fill.rel_x != 1.0 || pd->fill.rel_y != 1.0)
+                 BUF_APPENDF(I7"relative: %g %g;\n", TO_DOUBLE(pd->fill.rel_x), TO_DOUBLE(pd->fill.rel_y));
+               if (pd->fill.abs_x || pd->fill.abs_y)
+                 BUF_APPENDF(I7"offset: %d %d;\n", pd->fill.abs_x, pd->fill.abs_y);
+               BUF_APPEND(I6"}\n");
+          }
+
+       BUF_APPEND(I5"}\n");
+     }
+
+   //Text
+   if (rp->part->type == EDJE_PART_TYPE_TEXT)
+     {
+       BUF_APPEND(I5"text {\n");
+       if (pd->text.text)
+         BUF_APPENDF(I6"text: \"%s\";\n", pd->text.text);
+       BUF_APPENDF(I6"font: \"%s\";\n", pd->text.font);
+       BUF_APPENDF(I6"size: %d;\n", pd->text.size);
+       if (pd->text.text_class)
+         BUF_APPENDF(I6"text_class: \"%s\";\n", pd->text.text_class);
+       if (pd->text.fit_x || pd->text.fit_y)
+         BUF_APPENDF(I6"fit: %d %d;\n", pd->text.fit_x, pd->text.fit_y);
+        //TODO Support min & max
+       if (TO_DOUBLE(pd->text.align.x) != 0.5 || TO_DOUBLE(pd->text.align.y) != 0.5)
+         BUF_APPENDF(I6"align: %g %g;\n", TO_DOUBLE(pd->text.align.x), TO_DOUBLE(pd->text.align.y));
+        //TODO Support source
+        //TODO Support text_source
+       if (pd->text.elipsis)
+         BUF_APPENDF(I6"elipsis: %g;\n", pd->text.elipsis);
+       BUF_APPEND(I5"}\n");
+     }
+
+   //Gradient
+   if (rp->part->type == EDJE_PART_TYPE_GRADIENT)
+     {
+       BUF_APPEND(I5"gradient {\n");
+       BUF_APPENDF(I6"type: \"%s\";\n", pd->gradient.type);
+       str = edje_edit_state_gradient_spectra_get(obj, part, state, value);
+       if (str)
+         {
+               BUF_APPENDF(I6"spectrum: \"%s\";\n", str);
+               edje_edit_string_free(str);
+         }
+        //TODO rel1 and 2 seems unused
+       BUF_APPEND(I5"}\n");
+     }
+
+   //External
+   if (rp->part->type == EDJE_PART_TYPE_EXTERNAL)
+     {
+       if ((ll = (Eina_List *)edje_edit_state_external_params_list_get(obj, part, state, value)))
+         {
+            Edje_External_Param *p;
+
+            BUF_APPEND(I5"params {\n");
+            EINA_LIST_FOREACH(ll, l, p)
+              {
+                 switch (p->type)
+                   {
+                    case EDJE_EXTERNAL_PARAM_TYPE_INT:
+                       BUF_APPENDF(I6"int: \"%s\" \"%d\";\n", p->name, p->i);
+                       break;
+                    case EDJE_EXTERNAL_PARAM_TYPE_DOUBLE:
+                       BUF_APPENDF(I6"double: \"%s\" \"%g\";\n", p->name, p->d);
+                       break;
+                    case EDJE_EXTERNAL_PARAM_TYPE_STRING:
+                       if (p->s)
+                         BUF_APPENDF(I6"string: \"%s\" \"%s\";\n", p->name,
+                                     p->s);
+                       break;
+                    case EDJE_EXTERNAL_PARAM_TYPE_BOOL:
+                       BUF_APPENDF(I6"bool: \"%s\" \"%d\";\n", p->name, p->i);
+                       break;
+                    case EDJE_EXTERNAL_PARAM_TYPE_CHOICE:
+                       if (p->s)
+                         BUF_APPENDF(I6"choice: \"%s\" \"%s\";\n", p->name,
+                                     p->s);
+                       break;
+                    default:
+                       break;
+                   }
+              }
+            BUF_APPEND(I5"}\n");
+         }
+     }
+
+   BUF_APPEND(I4"}\n");//description
+   return ret;
+}
+
+static Eina_Bool
+_edje_generate_source_of_part(Evas_Object *obj, const char *part, Eina_Strbuf *buf)
+{
+   const char *str;
+   Eina_List *l, *ll;
+   char *data;
+   Eina_Bool ret = EINA_TRUE;
+
+   BUF_APPENDF(I3"part { name: \"%s\";\n", part);
+   BUF_APPENDF(I4"type: %s;\n", types[edje_edit_part_type_get(obj, part)]);
+   if (!edje_edit_part_mouse_events_get(obj, part))
+      BUF_APPEND(I4"mouse_events: 0;\n");
+   if (edje_edit_part_repeat_events_get(obj, part))
+      BUF_APPEND(I4"repeat_events: 1;\n");
+   //TODO Support ignore_flags
+   //TODO Support scale
+   //TODO Support pointer_mode
+   //TODO Support precise_is_inside
+   //TODO Support use_alternate_font_metrics
+   if ((str = edje_edit_part_clip_to_get(obj, part)))
+     {
+        BUF_APPENDF(I4"clip_to: \"%s\";\n", str);
+        edje_edit_string_free(str);
+     }
+   if ((str = edje_edit_part_source_get(obj, part)))
+     {
+        BUF_APPENDF(I4"source: \"%s\";\n", str);
+        edje_edit_string_free(str);
+     }
+   if (edje_edit_part_effect_get(obj, part))
+     BUF_APPENDF(I4"effect: %s;\n",
+                effects[edje_edit_part_effect_get(obj, part)]);
+
+   //Dragable
+   if (edje_edit_part_drag_x_get(obj, part) ||
+       edje_edit_part_drag_x_get(obj, part))
+     {
+       BUF_APPEND(I4"dragable {\n");
+       BUF_APPENDF(I5"x: %d %d %d;\n",
+                                 edje_edit_part_drag_x_get(obj, part),
+                                 edje_edit_part_drag_step_x_get(obj, part),
+                                 edje_edit_part_drag_count_x_get(obj, part));
+       BUF_APPENDF(I5"y: %d %d %d;\n",
+                                 edje_edit_part_drag_y_get(obj, part),
+                                 edje_edit_part_drag_step_y_get(obj, part),
+                                 edje_edit_part_drag_count_y_get(obj, part));
+       if ((str = edje_edit_part_drag_confine_get(obj, part)))
+         {
+               BUF_APPENDF(I5"confine: \"%s\";\n", str);
+               edje_edit_string_free(str);
+         }
+       if ((str = edje_edit_part_drag_event_get(obj, part)))
+         {
+               BUF_APPENDF(I5"events: \"%s\";\n", str);
+               edje_edit_string_free(str);
+         }
+       BUF_APPEND(I4"}\n");
+     }
+
+   //Descriptions
+   ll = edje_edit_part_states_list_get(obj, part);
+   EINA_LIST_FOREACH(ll, l, data)
+     {
+       char state[512], *delim;
+       double value;
+       strncpy(state, data, sizeof(state) - 1); /* if we go over it, too bad.. the list of states may need to change to provide name and value separated */
+       delim = strchr(state, ' ');
+       *delim = '\0';
+       delim++;
+       value = strtod(delim, NULL);
+       ret &= _edje_generate_source_of_state(obj, part, state, value, buf);
+     }
+   edje_edit_string_list_free(ll);
+
+   BUF_APPEND(I3"}\n");//part
+   return ret;
+}
+
+static Eina_Bool
+_edje_generate_source_of_group(Edje *ed, const char *group, Eina_Strbuf *buf)
+{
+   Evas_Object *obj;
+   Eina_List *l, *ll;
+   int w, h;
+   char *data;
+   Eina_Bool ret = EINA_TRUE;
+
+   obj = edje_edit_object_add(ed->evas);
+   if (!edje_object_file_set(obj, ed->file->path, group)) return EINA_FALSE;
+
+   BUF_APPENDF(I1"group { name: \"%s\";\n", group);
+   //TODO Support alias:
+   w = edje_edit_group_min_w_get(obj);
+   h = edje_edit_group_min_h_get(obj);
+   if ((w > 0) || (h > 0))
+      BUF_APPENDF(I2"min: %d %d;\n", w, h);
+   w = edje_edit_group_max_w_get(obj);
+   h = edje_edit_group_max_h_get(obj);
+   if ((w > -1) || (h > -1))
+      BUF_APPENDF(I2"max: %d %d;\n", w, h);
+
+   /* Data */
+   if ((ll = edje_edit_group_data_list_get(obj)))
+     {
+       BUF_APPEND(I2"data {\n");
+
+       EINA_LIST_FOREACH(ll, l, data)
+         {
+            BUF_APPENDF(I3"item: \"%s\" \"%s\";\n", data,
+                    edje_edit_group_data_value_get(obj, data));
+         }
+
+       BUF_APPEND(I2"}\n\n");
+       edje_edit_string_list_free(ll);
+     }
+
+   if (!ret)
+     {
+        ERR("Generating EDC for Group[%s] data.", group);
+        return EINA_FALSE;
+     }
+
+   //TODO Support script
+
+   /* Parts */
+   BUF_APPEND(I2"parts {\n");
+   ll = edje_edit_parts_list_get(obj);
+   EINA_LIST_FOREACH(ll, l, data)
+     ret &= _edje_generate_source_of_part(obj, data, buf);
+   edje_edit_string_list_free(ll);
+   BUF_APPEND(I2"}\n");//parts
+
+   if (!ret)
+     {
+        ERR("Generating EDC for Group[%s] Parts.", group);
+        return EINA_FALSE;
+     }
+
+   /* Programs */
+   if ((ll = edje_edit_programs_list_get(obj)))
+     {
+       BUF_APPEND(I2 "programs {\n");
+       EINA_LIST_FOREACH(ll, l, data)
+         _edje_generate_source_of_program(obj, data, buf);
+       BUF_APPEND(I2 "}\n");
+       edje_edit_string_list_free(ll);
+     }
+   BUF_APPEND("   }\n");//group
+
+   if (!ret)
+     {
+        ERR("Generating EDC for Group[%s] Programs.", group);
+        evas_object_del(obj);
+        return EINA_FALSE;
+     }
+
+   evas_object_del(obj);
+   return ret;
+}
+
+static Eina_Strbuf*
+_edje_generate_source(Evas_Object *obj)
+{
+   Eina_Strbuf *buf;
+
+   Eina_List *l, *ll;
+   char *entry;
+   Edje_Font_Directory_Entry *fnt;
+   Eina_Bool ret = EINA_TRUE;
+
+   GET_ED_OR_RETURN(NULL);
+
+   /* Open a str buffer */
+
+   buf = eina_strbuf_new();
+   if (!buf) return NULL;
+
+   /* Write edc into file */
+   //TODO Probably we need to save the file before generation
+
+   /* Images */
+   if ((ll = edje_edit_images_list_get(obj)))
+     {
+       BUF_APPEND(I0"images {\n");
+
+       EINA_LIST_FOREACH(ll, l, entry)
+         {
+               int comp = edje_edit_image_compression_type_get(obj, entry);
+               if (comp < 0) continue;
+
+               BUF_APPENDF(I1"image: \"%s\" ", entry);
+
+               if (comp == EDJE_EDIT_IMAGE_COMP_LOSSY)
+                 BUF_APPENDF("LOSSY %d;\n",
+                         edje_edit_image_compression_rate_get(obj, entry));
+               else if (comp == EDJE_EDIT_IMAGE_COMP_RAW)
+                 BUF_APPEND("RAW;\n");
+               else if (comp == EDJE_EDIT_IMAGE_COMP_USER)
+                 BUF_APPEND("USER;\n");
+               else
+                 BUF_APPEND("COMP;\n");
+         }
+       BUF_APPEND(I0"}\n\n");
+       edje_edit_string_list_free(ll);
+
+       if (!ret)
+         {
+            ERR("Generating EDC for Images");
+            eina_strbuf_free(buf);
+            return NULL;
+         }
+     }
+
+   /* Fonts */
+   if ((ll = edje_edit_fonts_list_get(obj)))
+     {
+       BUF_APPEND(I0"fonts {\n");
+
+       EINA_LIST_FOREACH(ll, l, fnt)
+          BUF_APPENDF(I1"font: \"%s\" \"%s\";\n", fnt->file,
+                            fnt->entry);
+
+       BUF_APPEND(I0"}\n\n");
+       eina_list_free(ll);
+
+       if (!ret)
+         {
+            ERR("Generating EDC for Fonts");
+            eina_strbuf_free(buf);
+            return NULL;
+         }
+     }
+
+   /* Data */
+   if ((ll = edje_edit_data_list_get(obj)))
+     {
+       BUF_APPEND(I0 "data {\n");
+
+       EINA_LIST_FOREACH(ll, l, entry)
+          BUF_APPENDF(I1 "item: \"%s\" \"%s\";\n", entry,
+                            edje_edit_data_value_get(obj, entry));
+
+       BUF_APPEND(I0 "}\n\n");
+       edje_edit_string_list_free(ll);
+
+       if (!ret)
+         {
+            ERR("Generating EDC for Data");
+            eina_strbuf_free(buf);
+            return NULL;
+         }
+     }
+
+   /* Color Classes */
+   if ((ll = edje_edit_color_classes_list_get(obj)))
+     {
+       BUF_APPEND(I0 "color_classes {\n");
+
+       EINA_LIST_FOREACH(ll, l, entry)
+         _edje_generate_source_of_colorclass(ed, entry, buf);
+
+       BUF_APPEND(I0 "}\n\n");
+       edje_edit_string_list_free(ll);
+
+       if (!ret)
+         {
+            ERR("Generating EDC for Color Classes");
+            eina_strbuf_free(buf);
+            return NULL;
+         }
+     }
+
+   /* Spectrum */
+   if ((ll = edje_edit_spectrum_list_get(obj)))
+     {
+       BUF_APPEND(I0 "spectra {\n");
+
+       EINA_LIST_FOREACH(ll, l, entry)
+         _edje_generate_source_of_spectra(ed, entry, buf);
+
+       BUF_APPEND(I0 "}\n\n");
+       edje_edit_string_list_free(ll);
+
+       if (!ret)
+         {
+            ERR("Generating EDC for Spectrum");
+            eina_strbuf_free(buf);
+            return NULL;
+         }
+     }
+
+   /* Styles */
+   if ((ll = edje_edit_styles_list_get(obj)))
+     {
+       BUF_APPEND(I0 "styles {\n");
+       EINA_LIST_FOREACH(ll, l, entry)
+         _edje_generate_source_of_style(ed, entry, buf);
+       BUF_APPEND(I0 "}\n\n");
+       edje_edit_string_list_free(ll);
+
+       if (!ret)
+         {
+            ERR("Generating EDC for Styles");
+            eina_strbuf_free(buf);
+            return NULL;
+         }
+     }
+
+   /* Externals */
+   if ((ll = edje_edit_externals_list_get(obj)))
+     {
+       BUF_APPEND(I0 "externals {\n");
+       EINA_LIST_FOREACH(ll, l, entry)
+          BUF_APPENDF(I1 "external: \"%s\";\n", entry);
+
+       BUF_APPEND(I0 "}\n\n");
+       edje_edit_string_list_free(ll);
+
+       if (!ret)
+         {
+            ERR("Generating EDC for Externals");
+            eina_strbuf_free(buf);
+            return NULL;
+         }
+     }
+
+   /* Collections */
+   BUF_APPEND("collections {\n");
+   ll = edje_file_collection_list(ed->file->path);
+   EINA_LIST_FOREACH(ll, l, entry)
+     ret &= _edje_generate_source_of_group(ed, entry, buf);
+   BUF_APPEND("}\n\n");
+   edje_file_collection_list_free(ll);
+
+   if (!ret)
+     {
+        ERR("Generating EDC for Collections");
+       eina_strbuf_free(buf);
+       return NULL;
+     }
+
+   return buf;
+}
+
+
+
+/*********************/
+/*  SAVING ROUTINES  */
+/*********************/
+////////////////////////////////////////
+typedef struct _SrcFile               SrcFile;
+typedef struct _SrcFile_List          SrcFile_List;
+
+struct _SrcFile
+{
+   char *name;
+   const char *file;
+};
+
+struct _SrcFile_List
+{
+   Eina_List *list;
+};
+
+static Eet_Data_Descriptor *_srcfile_edd = NULL;
+static Eet_Data_Descriptor *_srcfile_list_edd = NULL;
+
+static void
+source_edd(void)
+{
+   Eet_Data_Descriptor_Class eddc;
+
+   if (_srcfile_edd) return;
+
+   eet_eina_stream_data_descriptor_class_set(&eddc, "srcfile", sizeof(SrcFile));
+   _srcfile_edd = eet_data_descriptor_stream_new(&eddc);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_srcfile_edd, SrcFile, "name", name, EET_T_INLINED_STRING);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(_srcfile_edd, SrcFile, "file", file, EET_T_INLINED_STRING);
+
+   eet_eina_stream_data_descriptor_class_set(&eddc, "srcfile_list", sizeof(SrcFile_List));
+   _srcfile_list_edd = eet_data_descriptor_stream_new(&eddc);
+   EET_DATA_DESCRIPTOR_ADD_LIST(_srcfile_list_edd, SrcFile_List, "list", list, _srcfile_edd);
+}
+/////////////////////////////////////////
+
+static Eina_Bool
+_edje_edit_edje_file_save(Eet_File *eetf, Edje_File *ef)
+{
+   /* Write Edje_File structure */
+   INF("** Writing Edje_File* ed->file");
+   if (eet_data_write(eetf, _edje_edd_edje_file, "edje_file", ef, 1) <= 0)
+     {
+       ERR("Error. unable to write \"edje_file\" entry to \"%s\"", ef->path);
+       return EINA_FALSE;
+     }
+   return EINA_TRUE;
+}
+
+static Eina_Bool
+_edje_edit_collection_save(Eet_File *eetf, Edje_Part_Collection *epc)
+{
+   char buf[256];
+
+   snprintf(buf, sizeof(buf), "collections/%i", epc->id);
+
+   if (eet_data_write(eetf, _edje_edd_edje_part_collection, buf, epc, 1) <= 0)
+     {
+       ERR("Error. unable to write \"%s\" part entry", buf);
+       return EINA_FALSE;
+     }
+   return EINA_TRUE;
+}
+
+static Eina_Bool
+_edje_edit_source_save(Eet_File *eetf, Evas_Object *obj)
+{
+   SrcFile *sf;
+   SrcFile_List *sfl;
+   Eina_Strbuf *source_file;
+   Eina_Bool ret = EINA_TRUE;
+
+   source_file = _edje_generate_source(obj);
+   if (!source_file)
+     {
+       ERR("Can't create edc source");
+       return EINA_FALSE;
+     }
+
+   //open the temp file and put the contents in SrcFile
+   sf = _alloc(sizeof(SrcFile));
+   if (!sf)
+     {
+       ERR("Unable to create source file struct");
+       ret = EINA_FALSE;
+        goto save_free_source;
+     }
+   sf->name = strdup("generated_source.edc");
+   if (!sf->name)
+     {
+       ERR("Unable to alloc filename");
+       ret = EINA_FALSE;
+        goto save_free_sf;
+     }
+
+   sf->file = eina_strbuf_string_get(source_file);
+
+   //create the needed list of source files (only one)
+   sfl = _alloc(sizeof(SrcFile_List));
+   if (!sfl)
+     {
+       ERR("Unable to create file list");
+       ret = EINA_FALSE;
+        goto save_free_filename;
+     }
+   sfl->list = NULL;
+   sfl->list = eina_list_append(sfl->list, sf);
+   if (!sfl->list)
+     {
+       ERR("Error. unable to append file in list");
+       ret = EINA_FALSE;
+        goto save_free_sfl;
+     }
+
+   // write the sources list to the eet file
+   source_edd();
+   if (eet_data_write(eetf, _srcfile_list_edd, "edje_sources", sfl, 1) <= 0)
+    {
+       ERR("Unable to write edc source");
+       ret = EINA_FALSE;
+    }
+
+   /* Clear stuff */
+   eina_list_free(sfl->list);
+save_free_sfl:
+   free(sfl);
+save_free_filename:
+   free(sf->name);
+save_free_sf:
+   free(sf);
+save_free_source:
+   eina_strbuf_free(source_file);
+   return ret;
+}
+
+Eina_Bool
+_edje_edit_internal_save(Evas_Object *obj, int current_only)
+{
+   Edje_File *ef;
+   Eet_File *eetf;
+
+   GET_ED_OR_RETURN(EINA_FALSE);
+
+   ef = ed->file;
+   if (!ef) return EINA_FALSE;
+
+   INF("***********  Saving file ******************");
+   INF("** path: %s", ef->path);
+
+   /* Open the eet file */
+   eetf = eet_open(ef->path, EET_FILE_MODE_READ_WRITE);
+   if (!eetf)
+     {
+       ERR("Error. unable to open \"%s\" for writing output",
+           ef->path);
+       return EINA_FALSE;
+     }
+
+   /* Set compiler name */
+   if (strcmp(ef->compiler, "edje_edit"))
+     {
+       _edje_if_string_free(ed, ef->compiler);
+       ef->compiler = (char *)eina_stringshare_add("edje_edit");
+     }
+
+   if (!_edje_edit_edje_file_save(eetf, ef))
+     {
+       eet_close(eetf);
+       return EINA_FALSE;
+     }
+
+   if (current_only)
+     {
+       if (ed->collection)
+         {
+            INF("** Writing Edje_Part_Collection* ed->collection "
+                  "[id: %d]", ed->collection->id);
+            if (!_edje_edit_collection_save(eetf, ed->collection))
+              {
+                 eet_close(eetf);
+                 return EINA_FALSE;
+              }
+         }
+     }
+   else
+     {
+       Eina_List *l;
+       Edje_Part_Collection *edc;
+        Eina_Iterator *it;
+
+       INF("** Writing all collections");
+
+       it = eina_hash_iterator_data_new(ef->collection_hash);
+        while (eina_iterator_next(it, (void **)&edc))
+         {
+            INF("** Writing hash Edje_Part_Collection* ed->collection "
+                  "[id: %d]", edc->id);
+            if(!_edje_edit_collection_save(eetf, edc))
+              {
+                 eet_close(eetf);
+                 return EINA_FALSE;
+              }
+         }
+       eina_iterator_free(it);
+
+       EINA_LIST_FOREACH(ef->collection_cache, l, edc)
+         {
+            INF("** Writing cache Edje_Part_Collection* ed->collection "
+                  "[id: %d]", edc->id);
+            if(!_edje_edit_collection_save(eetf, edc))
+              {
+                 eet_close(eetf);
+                 return EINA_FALSE;
+              }
+         }
+     }
+
+   if (!_edje_edit_source_save(eetf, obj))
+     {
+       eet_close(eetf);
+       return EINA_FALSE;
+     }
+
+   eet_close(eetf);
+
+   /* Update mtime */
+   {
+     struct stat st;
+     if (stat(ed->path, &st) != 0)
+       return EINA_FALSE;
+     ef->mtime = st.st_mtime;
+   }
+
+   INF("***********  Saving DONE ******************");
+   return EINA_TRUE;
+}
+
+EAPI Eina_Bool
+edje_edit_save(Evas_Object *obj)
+{
+   return _edje_edit_internal_save(obj, 1);
+}
+
+EAPI Eina_Bool
+edje_edit_save_all(Evas_Object *obj)
+{
+   return _edje_edit_internal_save(obj, 0);
+}
+
+EAPI void
+edje_edit_print_internal_status(Evas_Object *obj)
+{
+   Eina_List *l;
+   Edje_Part *p;
+   Edje_Program *epr;
+
+   GET_ED_OR_RETURN();
+
+   _edje_generate_source(obj);
+   return;
+
+   INF("\n****** CHECKIN' INTERNAL STRUCTS STATUS *********");
+
+   INF("*** Edje\n");
+   INF("    path: '%s'", ed->path);
+   INF("    group: '%s'", ed->group);
+   INF("    parent: '%s'", ed->parent);
+
+   INF("*** Parts [table:%d list:%d]", ed->table_parts_size,
+       eina_list_count(ed->collection->parts));
+   EINA_LIST_FOREACH(ed->collection->parts, l, p)
+     {
+       Edje_Real_Part *rp;
+
+       rp = ed->table_parts[p->id % ed->table_parts_size];
+       printf("    [%d]%s ", p->id, p->name);
+       if (p == rp->part)
+         printf(" OK!\n");
+       else
+         WRN(" WRONG (table[%id]->name = '%s')", p->id, rp->part->name);
+     }
+
+   INF("*** Programs [table:%d list:%d]", ed->table_programs_size,
+          eina_list_count(ed->collection->programs));
+   EINA_LIST_FOREACH(ed->collection->programs, l, epr)
+     {
+       Edje_Program *epr2;
+
+       epr2 = ed->table_programs[epr->id % ed->table_programs_size];
+       printf("     [%d]%s ", epr->id, epr->name);
+       if (epr == epr2)
+         printf(" OK!\n");
+       else
+         WRN(" WRONG (table[%id]->name = '%s')", epr->id, epr2->name);
+     }
+
+   printf("\n");
+
+   INF("******************  END  ************************\n");
+}
diff --git a/src/lib/edje_embryo.c b/src/lib/edje_embryo.c
new file mode 100644 (file)
index 0000000..14c5d7a
--- /dev/null
@@ -0,0 +1,2855 @@
+/*
+ * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <string.h>
+
+#ifdef HAVE_ALLOCA_H
+# include <alloca.h>
+#elif defined __GNUC__
+# define alloca __builtin_alloca
+#elif defined _AIX
+# define alloca __alloca
+#elif defined _MSC_VER
+# include <malloc.h>
+# define alloca _alloca
+#else
+# include <stddef.h>
+# ifdef  __cplusplus
+extern "C"
+# endif
+void *alloca (size_t);
+#endif
+
+#include "edje_private.h"
+
+/*
+ * ALREADY EXPORTED BY EMBRYO:
+ *
+ * enum Float_Round_Method {
+ *    ROUND, FLOOR, CEIL, TOZERO
+ * };
+ * enum Float_Angle_Mode {
+ *    RADIAN, DEGREES, GRADES
+ * };
+ *
+ * numargs();
+ * getarg(arg, index=0);
+ * setarg(arg, index=0, value);
+ *
+ * Float:atof(string[]);
+ * Float:fract(Float:value);
+ *       round(Float:value, Float_Round_Method:method=ROUND);
+ * Float:sqrt(Float:value);
+ * Float:pow(Float:value, Float:exponent);
+ * Float:log(Float:value, Float:base=10.0);
+ * Float:sin(Float:value, Float_Angle_Mode:mode=RADIAN);
+ * Float:cos(Float:value, Float_Angle_Mode:mode=RADIAN);
+ * Float:tan(Float:value, Float_Angle_Mode:mode=RADIAN);
+ * Float:abs(Float:value);
+ *       atoi(str[]);
+ *       fnmatch(glob[], str[]);
+ *       strcmp(str1[], str2[]);
+ *       strncmp(str1[], str2[]);
+ *       strcpy(dst[], src[]);
+ *       strncpy(dst[], src[], n);
+ *       strlen(str[]);
+ *       strcat(dst[], src[]);
+ *       strncat(dst[], src[], n);
+ *       strprep(dst[], src[]);
+ *       strnprep(dst[], src[], n);
+ *       strcut(dst[], str[], n, n2);
+ *       snprintf(dst[], dstn, fmt[], ...);
+ *       strstr(str[], ndl[]);
+ *       strchr(str[], ch[]);
+ *       strrchr(str[], ch[]);
+ *       rand();
+ * Float:randf();
+ * Float:seconds();
+ *       date(&year, &month, &day, &yearday, &weekday, &hr, &min, &Float:sec);
+ *
+ */
+
+/* EDJE...
+ *
+ * implemented so far as examples:
+ *
+ * enum Msg_Type {
+ *    MSG_NONE, MSG_STRING, MSG_INT, MSG_FLOAT, MSG_STRING_SET, MSG_INT_SET,
+ *    MSG_FLOAT_SET, MSG_STRING_INT, MSG_INT_FLOAT, MSG_STRING_INT_SET,
+ *    MSG_INT_FLOAT_SET
+ * };
+ *
+ * get_int(id)
+ * set_int(id, v)
+ * Float:get_float (id)
+ * set_float(id, Float:v)
+ * get_strlen(id)
+ * get_str(id, dst[], maxlen)
+ * set_str(id, str[])
+ * timer(Float:in, fname[], val)
+ * cancel_timer(id)
+ * anim(Float:len, fname[], val)
+ * cancel_anim(id)
+ * emit(sig[], src[])
+ * set_state(part_id, state[], Float:state_val)
+ * set_tween_state(part_id, Float:tween, state1[], Float:state1_val, state2[], Float:state2_val)
+ * run_program(program_id)
+ * Direction:get_drag_dir(part_id)
+ * get_drag(part_id, &Float:dx, &Float:&dy)
+ * set_drag(part_id, Float:dx, Float:dy)
+ * get_drag_size(part_id, &Float:dx, &Float:&dy)
+ * set_drag_size(part_id, Float:dx, Float:dy)
+ * set_text(part_id, str[])
+ * get_text(part_id, dst[], maxlen)
+ * get_min_size(w, h)
+ * get_max_size(w, h)
+ * set_color_class(class[], r, g, b, a)
+ * get_color_class(class[], &r, &g, &b, &a)
+ * set_text_class(class[], font[], Float:size)
+ * get_text_class(class[], font[], &Float:size)
+ * get_drag_step(part_id, &Float:dx, &Float:&dy)
+ * set_drag_step(part_id, Float:dx, Float:dy)
+ * get_drag_page(part_id, &Float:dx, &Float:&dy)
+ * set_drag_page(part_id, Float:dx, Float:dy)
+ * get_geometry(part_id, &Float:x, &Float:y, &Float:w, &Float:h)
+ * get_mouse(&x, &y)
+ * stop_program(program_id)
+ * stop_programs_on(part_id)
+ * set_min_size(w, h)
+ * set_max_size(w, h)
+ * send_message(Msg_Type:type, id, ...)
+ *
+ * count(id)
+ * remove(id, n)
+ *
+ * append_int(id, v)
+ * prepend_int(id, v)
+ * insert_int(id, n, v)
+ * replace_int(id, n, v)
+ * fetch_int(id, n)
+ *
+ * append_str(id, str[])
+ * prepend_str(id, str[])
+ * insert_str(id, n, str[])
+ * replace_str(id, n, str[])
+ * fetch_str(id, n, dst[], maxlen)
+ *
+ * append_float(id, Float:v)
+ * prepend_float(id, Float:v)
+ * insert_float(id, n, Float:v)
+ * replace_float(id, n, Float:v)
+ * Float:fetch_float(id, n)
+ *
+ * custom_state(part_id, state[], Float:state_val = 0.0)
+ * set_state_val(part_id, State_Param:param, ...)
+ * get_state_val(part_id, State_Param:param, ...)
+ *
+ * Supported parameters:
+ * align[Float:x, Float:y]
+ * min[w, h]
+ * max[w, h]
+ * step[x,y]
+ * aspect[Float:min, Float:max]
+ * color[r,g,b,a]
+ * color2[r,g,b,a]
+ * color3[r,g,b,a]
+ * aspect_preference
+ * rel1[relx,rely]
+ * rel1[part_id,part_id]
+ * rel1[offx,offy]
+ * rel2[relx,relyr]
+ * rel2[part_id,part_id]
+ * rel2[offx,offy]
+ * image[image_id] <- all images have an Id not name in the edje
+ * border[l,r,t,b]
+ * fill[smooth]
+ * fill[pos_relx,pos_rely,pos_offx,pos_offy]
+ * fill[sz_relx,sz_rely,sz_offx,sz_offy]
+ * color_class
+ * text[text]
+ * text[text_class]
+ * text[font]
+ * text[size]
+ * text[style]
+ * text[fit_x,fit_y]
+ * text[min_x,min_y]
+ * text[align_x,align_y]
+ * visible[on]
+ * map_on[on]
+ * map_persp[part_id]
+ * map_light[part_id]
+ * map_rot_center[part_id]
+ * map_rot_x[deg]
+ * map_rot_y[deg]
+ * map_rot_z[deg]
+ * map_back_cull[on]
+ * map_persp_on[on]
+ * persp_zplane[z]
+ * persp_focal[z]
+ *
+ * ** part_id and program_id need to be able to be "found" from strings
+ *
+ * get_drag_count(part_id, &Float:dx, &Float:&dy)
+ * set_drag_count(part_id, Float:dx, Float:dy)
+ * set_drag_confine(part_id, confine_part_id)
+ * get_size(&w, &h);
+ * resize_request(w, h)
+ * get_mouse_buttons()
+ * //set_type(part_id, Type:type)
+ * //set_effect(part_id, Effect:fx)
+ * set_mouse_events(part_id, ev)
+ * get_mouse_events(part_id)
+ * set_repeat_events(part_id, rep)
+ * get_repeat_events(part_id)
+ * set_clip(part_id, clip_part_id)
+ * get_clip(part_id)
+ *
+ * part_swallow(part_id, group_name)
+ *
+ * external_param_get_int(id, param_name[])
+ * external_param_set_int(id, param_name[], value)
+ * Float:external_param_get_float(id, param_name[])
+ * external_param_set_float(id, param_name[], Float:value)
+ * external_param_get_strlen(id, param_name[])
+ * external_param_get_str(id, param_name[], value[], value_maxlen)
+ * external_param_set_str(id, param_name[], value[])
+ * external_param_get_choice_len(id, param_name[])
+ * external_param_get_choice(id, param_name[], value[], value_maxlen)
+ * external_param_set_choice(id, param_name[], value[])
+ * external_param_get_bool(id, param_name[])
+ * external_param_set_bool(id, param_name[], value)
+ *
+ * ADD/DEL CUSTOM OBJECTS UNDER SOLE EMBRYO SCRIPT CONTROL
+ *
+ */
+
+/* get_int(id) */
+static Embryo_Cell
+_edje_embryo_fn_get_int(Embryo_Program *ep, Embryo_Cell *params)
+{
+   Edje *ed;
+
+   CHKPARAM(1);
+   ed = embryo_program_data_get(ep);
+   return (Embryo_Cell)_edje_var_int_get(ed, (int)params[1]);
+}
+
+/* set_int(id, v) */
+static Embryo_Cell
+_edje_embryo_fn_set_int(Embryo_Program *ep, Embryo_Cell *params)
+{
+   Edje *ed;
+
+   CHKPARAM(2);
+   ed = embryo_program_data_get(ep);
+   _edje_var_int_set(ed, (int)params[1], (int)params[2]);
+   return 0;
+}
+
+/* get_float(id) */
+static Embryo_Cell
+_edje_embryo_fn_get_float(Embryo_Program *ep, Embryo_Cell *params)
+{
+   Edje *ed;
+   float v;
+
+   CHKPARAM(1);
+   ed = embryo_program_data_get(ep);
+   v = (float)_edje_var_float_get(ed, params[1]);
+   return EMBRYO_FLOAT_TO_CELL(v);
+}
+
+/* set_float(id, v) */
+static Embryo_Cell
+_edje_embryo_fn_set_float(Embryo_Program *ep, Embryo_Cell *params)
+{
+   Edje *ed;
+   float v;
+
+   CHKPARAM(2);
+   ed = embryo_program_data_get(ep);
+   v = EMBRYO_CELL_TO_FLOAT(params[2]);
+   _edje_var_float_set(ed, (int)params[1], (double)v);
+   return 0;
+}
+
+/* get_str(id, dst[], maxlen) */
+static Embryo_Cell
+_edje_embryo_fn_get_str(Embryo_Program *ep, Embryo_Cell *params)
+{
+   Edje *ed;
+   char *s;
+
+   CHKPARAM(3);
+   if (params[3] < 1) return 0;
+   ed = embryo_program_data_get(ep);
+   s = (char *)_edje_var_str_get(ed, (int)params[1]);
+   if (s)
+     {
+       if (strlen(s) < params[3])
+         {
+            SETSTR(s, params[2]);
+         }
+       else
+         {
+            char *ss;
+
+            ss = alloca(strlen(s) + 1);
+            strcpy(ss, s);
+            ss[params[3] - 1] = 0;
+            SETSTR(ss, params[2]);
+         }
+     }
+   else
+     {
+       SETSTR("", params[2]);
+     }
+   return 0;
+}
+
+/* get_strlen(id) */
+static Embryo_Cell
+_edje_embryo_fn_get_strlen(Embryo_Program *ep, Embryo_Cell *params)
+{
+   Edje *ed;
+   char *s;
+
+   CHKPARAM(1);
+   ed = embryo_program_data_get(ep);
+   s = (char *)_edje_var_str_get(ed, (int)params[1]);
+   if (s)
+     {
+       return strlen(s);
+     }
+   return 0;
+}
+
+/* set_str(id, str[]) */
+static Embryo_Cell
+_edje_embryo_fn_set_str(Embryo_Program *ep, Embryo_Cell *params)
+{
+   Edje *ed;
+   char *s;
+
+   CHKPARAM(2);
+   ed = embryo_program_data_get(ep);
+   GETSTR(s, params[2]);
+   if (s)
+     {
+       _edje_var_str_set(ed, (int)params[1], s);
+     }
+   return 0;
+}
+
+/* count(id) */
+static Embryo_Cell
+_edje_embryo_fn_count(Embryo_Program *ep, Embryo_Cell *params)
+{
+   Edje *ed = embryo_program_data_get(ep);
+
+   CHKPARAM(1);
+
+   return (Embryo_Cell)_edje_var_list_count_get(ed, (int) params[1]);
+}
+
+/* remove(id, n) */
+static Embryo_Cell
+_edje_embryo_fn_remove(Embryo_Program *ep, Embryo_Cell *params)
+{
+   Edje *ed = embryo_program_data_get(ep);
+
+   CHKPARAM(2);
+
+   _edje_var_list_remove_nth(ed, (int) params[1], (int) params[2]);
+
+   return 0;
+}
+
+/* append_int(id, var) */
+static Embryo_Cell
+_edje_embryo_fn_append_int(Embryo_Program *ep, Embryo_Cell *params)
+{
+   Edje *ed = embryo_program_data_get(ep);
+
+   CHKPARAM(2);
+
+   _edje_var_list_int_append(ed, (int) params[1], (int) params[2]);
+
+   return 0;
+}
+
+/* prepend_int(id, var) */
+static Embryo_Cell
+_edje_embryo_fn_prepend_int(Embryo_Program *ep, Embryo_Cell *params)
+{
+   Edje *ed = embryo_program_data_get(ep);
+
+   CHKPARAM(2);
+
+   _edje_var_list_int_prepend(ed, (int) params[1], (int) params[2]);
+
+   return 0;
+}
+
+/* insert_int(id, pos, var) */
+static Embryo_Cell
+_edje_embryo_fn_insert_int(Embryo_Program *ep, Embryo_Cell *params)
+{
+   Edje *ed = embryo_program_data_get(ep);
+
+   CHKPARAM(3);
+
+   _edje_var_list_int_insert(ed, (int) params[1], (int) params[2],
+                             (int) params[3]);
+
+   return 0;
+}
+
+/* replace_int(id, pos, var) */
+static Embryo_Cell
+_edje_embryo_fn_replace_int(Embryo_Program *ep, Embryo_Cell *params)
+{
+   Edje *ed = embryo_program_data_get(ep);
+
+   CHKPARAM(3);
+
+   _edje_var_list_nth_int_set(ed, (int) params[1], (int) params[2],
+                              (int) params[3]);
+
+   return 0;
+}
+
+/* fetch_int(id, pos) */
+static Embryo_Cell
+_edje_embryo_fn_fetch_int(Embryo_Program *ep, Embryo_Cell *params)
+{
+   Edje *ed = embryo_program_data_get(ep);
+
+   CHKPARAM(2);
+
+   return _edje_var_list_nth_int_get(ed, (int) params[1],
+                                     (int) params[2]);
+}
+
+/* append_str(id, str[]) */
+static Embryo_Cell
+_edje_embryo_fn_append_str(Embryo_Program *ep, Embryo_Cell *params)
+{
+   Edje *ed = embryo_program_data_get(ep);
+   char *s;
+
+   CHKPARAM(2);
+
+   GETSTR(s, params[2]);
+   if (s)
+     _edje_var_list_str_append(ed, (int) params[1], s);
+
+   return 0;
+}
+
+/* prepend_str(id, str[]) */
+static Embryo_Cell
+_edje_embryo_fn_prepend_str(Embryo_Program *ep, Embryo_Cell *params)
+{
+   Edje *ed = embryo_program_data_get(ep);
+   char *s;
+
+   CHKPARAM(2);
+
+   GETSTR(s, params[2]);
+   if (s)
+     _edje_var_list_str_prepend(ed, (int) params[1], s);
+
+   return 0;
+}
+
+/* insert_str(id, pos, str[]) */
+static Embryo_Cell
+_edje_embryo_fn_insert_str(Embryo_Program *ep, Embryo_Cell *params)
+{
+   Edje *ed = embryo_program_data_get(ep);
+   char *s;
+
+   CHKPARAM(3);
+
+   GETSTR(s, params[3]);
+   if (s)
+     _edje_var_list_str_insert(ed, (int) params[1], (int) params[2], s);
+
+   return 0;
+}
+
+/* replace_str(id, pos, str[]) */
+static Embryo_Cell
+_edje_embryo_fn_replace_str(Embryo_Program *ep, Embryo_Cell *params)
+{
+   Edje *ed = embryo_program_data_get(ep);
+   char *s;
+
+   CHKPARAM(3);
+
+   GETSTR(s, params[3]);
+   if (s)
+       _edje_var_list_nth_str_set(ed, (int) params[1], (int) params[2], s);
+
+   return 0;
+}
+
+
+/* fetch_str(id, pos, dst[], maxlen) */
+static Embryo_Cell
+_edje_embryo_fn_fetch_str(Embryo_Program *ep, Embryo_Cell *params)
+{
+   Edje *ed = embryo_program_data_get(ep);
+   char *s;
+
+   CHKPARAM(4);
+
+   s = (char *) _edje_var_list_nth_str_get(ed, (int) params[1],
+                                           (int) params[2]);
+   if (s)
+     {
+       if (strlen(s) < params[4])
+         {
+            SETSTR(s, params[3]);
+         }
+       else
+         {
+            char *ss;
+
+            ss = alloca(strlen(s) + 1);
+            strcpy(ss, s);
+            ss[params[4] - 1] = 0;
+            SETSTR(ss, params[3]);
+         }
+     }
+   else
+     {
+       SETSTR("", params[3]);
+     }
+
+   return 0;
+}
+
+/* append_float(id, Float:f) */
+static Embryo_Cell
+_edje_embryo_fn_append_float(Embryo_Program *ep, Embryo_Cell *params)
+{
+   Edje *ed = embryo_program_data_get(ep);
+   float f;
+
+   CHKPARAM(2);
+
+   f = EMBRYO_CELL_TO_FLOAT(params[2]);
+   _edje_var_list_float_append(ed, (int) params[1], f);
+
+   return 0;
+}
+
+/* prepend_float(id, Float:f) */
+static Embryo_Cell
+_edje_embryo_fn_prepend_float(Embryo_Program *ep, Embryo_Cell *params)
+{
+   Edje *ed = embryo_program_data_get(ep);
+   float f;
+
+   CHKPARAM(2);
+
+   f = EMBRYO_CELL_TO_FLOAT(params[2]);
+   _edje_var_list_float_prepend(ed, (int) params[1], f);
+
+   return 0;
+}
+
+/* insert_float(id, pos, Float:f) */
+static Embryo_Cell
+_edje_embryo_fn_insert_float(Embryo_Program *ep, Embryo_Cell *params)
+{
+   Edje *ed = embryo_program_data_get(ep);
+   float f;
+
+   CHKPARAM(3);
+
+   f = EMBRYO_CELL_TO_FLOAT(params[3]);
+   _edje_var_list_float_insert(ed, (int) params[1], (int) params[2], f);
+
+   return 0;
+}
+
+/* replace_float(id, pos, Float:f) */
+static Embryo_Cell
+_edje_embryo_fn_replace_float(Embryo_Program *ep, Embryo_Cell *params)
+{
+   Edje *ed = embryo_program_data_get(ep);
+
+   CHKPARAM(3);
+
+   _edje_var_list_nth_float_set(ed, (int) params[1], (int) params[2],
+                               EMBRYO_CELL_TO_FLOAT(params[3]));
+
+   return 0;
+}
+
+/* Float:fetch_float(id, pos) */
+static Embryo_Cell
+_edje_embryo_fn_fetch_float(Embryo_Program *ep, Embryo_Cell *params)
+{
+   Edje *ed = embryo_program_data_get(ep);
+   float f;
+
+   CHKPARAM(2);
+
+   f = _edje_var_list_nth_float_get(ed, (int) params[1], (int) params[2]);
+
+   return EMBRYO_FLOAT_TO_CELL(f);
+}
+
+/* timer(Float:in, fname[], val) */
+static Embryo_Cell
+_edje_embryo_fn_timer(Embryo_Program *ep, Embryo_Cell *params)
+{
+   Edje *ed;
+   char *fname = NULL;
+   float f;
+   double in;
+   int val;
+
+   CHKPARAM(3);
+   ed = embryo_program_data_get(ep);
+   GETSTR(fname, params[2]);
+   if ((!fname)) return 0;
+   f = EMBRYO_CELL_TO_FLOAT(params[1]);
+   in = (double)f;
+   val = params[3];
+   return _edje_var_timer_add(ed, in, fname, val);
+}
+
+/* cancel_timer(id) */
+static Embryo_Cell
+_edje_embryo_fn_cancel_timer(Embryo_Program *ep, Embryo_Cell *params)
+{
+   Edje *ed;
+   int id;
+
+   CHKPARAM(1);
+   ed = embryo_program_data_get(ep);
+   id = params[1];
+   if (id <= 0) return 0;
+   _edje_var_timer_del(ed, id);
+   return 0;
+}
+
+/* anim(Float:len, fname[], val) */
+static Embryo_Cell
+_edje_embryo_fn_anim(Embryo_Program *ep, Embryo_Cell *params)
+{
+   Edje *ed;
+   char *fname = NULL;
+   float f;
+   double len;
+   int val;
+
+   CHKPARAM(3);
+   ed = embryo_program_data_get(ep);
+   GETSTR(fname, params[2]);
+   if ((!fname)) return 0;
+   f = EMBRYO_CELL_TO_FLOAT(params[1]);
+   len = (double)f;
+   val = params[3];
+   return _edje_var_anim_add(ed, len, fname, val);
+}
+
+/* cancel_anim(id) */
+static Embryo_Cell
+_edje_embryo_fn_cancel_anim(Embryo_Program *ep, Embryo_Cell *params)
+{
+   Edje *ed;
+   int id;
+
+   CHKPARAM(1);
+   ed = embryo_program_data_get(ep);
+   id = params[1];
+   if (id <= 0) return 0;
+   _edje_var_anim_del(ed, id);
+   return 0;
+}
+
+/* set_min_size(Float:w, Float:h) */
+static Embryo_Cell
+_edje_embryo_fn_set_min_size(Embryo_Program *ep, Embryo_Cell *params)
+{
+    Edje *ed;
+   float f = 0.0;
+   double w = 0.0, h = 0.0;
+
+   CHKPARAM(2);
+   ed = embryo_program_data_get(ep);
+   f = EMBRYO_CELL_TO_FLOAT(params[1]);
+   w = (double)f;
+   f = EMBRYO_CELL_TO_FLOAT(params[2]);
+   h = (double)f;
+
+   if (w < 0.0) w = 0.0;
+   if (h < 0.0) h = 0.0;
+   ed->collection->prop.min.w = w;
+   ed->collection->prop.min.h = h;
+   ed->dirty = 1;
+#ifdef EDJE_CALC_CACHE
+   ed->all_part_change = 1;
+#endif
+   _edje_recalc(ed);
+   return 0;
+}
+
+/* set_max_size(Float:w, Float:h) */
+static Embryo_Cell
+_edje_embryo_fn_set_max_size(Embryo_Program *ep, Embryo_Cell *params)
+{
+   Edje *ed;
+   float f = 0.0;
+   double w = 0.0, h = 0.0;
+
+   CHKPARAM(2);
+   ed = embryo_program_data_get(ep);
+   f = EMBRYO_CELL_TO_FLOAT(params[1]);
+   w = (double)f;
+   f = EMBRYO_CELL_TO_FLOAT(params[2]);
+   h = (double)f;
+
+   if (w < 0.0) w = 0.0;
+   if (h < 0.0) h = 0.0;
+   ed->collection->prop.max.w = w;
+   ed->collection->prop.max.h = h;
+   ed->dirty = 1;
+#ifdef EDJE_CALC_CACHE
+   ed->all_part_change = 1;
+#endif
+   _edje_recalc(ed);
+
+   return 0;
+}
+
+/* stop_program(program_id) */
+static Embryo_Cell
+_edje_embryo_fn_stop_program(Embryo_Program *ep, Embryo_Cell *params)
+{
+   Edje *ed;
+   int program_id = 0;
+   Edje_Running_Program *runp;
+   Eina_List *l;
+
+   CHKPARAM(1);
+   ed = embryo_program_data_get(ep);
+   program_id = params[1];
+   if (program_id < 0) return 0;
+
+   ed->walking_actions = 1;
+
+   EINA_LIST_FOREACH(ed->actions, l, runp)
+     if (program_id == runp->program->id)
+       _edje_program_end(ed, runp);
+
+   ed->walking_actions = 0;
+
+   return 0;
+}
+
+/* stop_programs_on(part_id) */
+static Embryo_Cell
+_edje_embryo_fn_stop_programs_on(Embryo_Program *ep, Embryo_Cell *params)
+{
+   Edje *ed;
+
+   int part_id = 0;
+   Edje_Real_Part *rp;
+
+   CHKPARAM(1);
+   ed = embryo_program_data_get(ep);
+   part_id = params[1];
+   if (part_id < 0) return 0;
+   rp = ed->table_parts[part_id % ed->table_parts_size];
+   if (rp)
+     {
+       /* there is only ever 1 program acting on a part at any time */
+       if (rp->program) _edje_program_end(ed, rp->program);
+     }
+   return 0;
+}
+
+/* get_mouse(&x, &y) */
+static Embryo_Cell
+_edje_embryo_fn_get_mouse(Embryo_Program *ep, Embryo_Cell *params)
+{
+   Edje *ed;
+   Evas_Coord x = 0, y = 0;
+
+   CHKPARAM(2);
+   ed = embryo_program_data_get(ep);
+   evas_pointer_canvas_xy_get(ed->evas, &x, &y);
+   x -= ed->x;
+   y -= ed->y;
+   SETINT((int)x, params[1]);
+   SETINT((int)y, params[2]);
+   return 0;
+}
+
+/* get_mouse_buttons() */
+static Embryo_Cell
+_edje_embryo_fn_get_mouse_buttons(Embryo_Program *ep, Embryo_Cell *params)
+{
+   Edje *ed;
+
+   CHKPARAM(0);
+   ed = embryo_program_data_get(ep);
+   return evas_pointer_button_down_mask_get(ed->evas);
+}
+
+/* emit(sig[], src[]) */
+static Embryo_Cell
+_edje_embryo_fn_emit(Embryo_Program *ep, Embryo_Cell *params)
+{
+   Edje *ed;
+   char *sig = NULL, *src = NULL;
+
+   CHKPARAM(2);
+   ed = embryo_program_data_get(ep);
+   GETSTR(sig, params[1]);
+   GETSTR(src, params[2]);
+   if ((!sig) || (!src)) return 0;
+   _edje_emit(ed, sig, src);
+   return 0;
+}
+
+/* set_state(part_id, state[], Float:state_val) */
+static Embryo_Cell
+_edje_embryo_fn_set_state(Embryo_Program *ep, Embryo_Cell *params)
+{
+   Edje *ed;
+   char *state = NULL;
+   int part_id = 0;
+   float f = 0.0;
+   double value = 0.0;
+   Edje_Real_Part *rp;
+
+   CHKPARAM(3);
+   ed = embryo_program_data_get(ep);
+   GETSTR(state, params[2]);
+   if ((!state)) return 0;
+   part_id = params[1];
+   if (part_id < 0) return 0;
+   f = EMBRYO_CELL_TO_FLOAT(params[3]);
+   value = (double)f;
+   rp = ed->table_parts[part_id % ed->table_parts_size];
+   if (rp)
+     {
+       if (rp->program) _edje_program_end(ed, rp->program);
+       _edje_part_description_apply(ed, rp, state, value, NULL, 0.0);
+       _edje_part_pos_set(ed, rp, EDJE_TWEEN_MODE_LINEAR, ZERO);
+       _edje_recalc(ed);
+     }
+   return 0;
+}
+
+/* get_state(part_id, dst[], maxlen, &Float:val) */
+static Embryo_Cell
+_edje_embryo_fn_get_state(Embryo_Program *ep, Embryo_Cell *params)
+{
+   Edje *ed;
+   int part_id = 0;
+   Edje_Real_Part *rp;
+   const char *s;
+
+   CHKPARAM(4);
+   ed = embryo_program_data_get(ep);
+   part_id = params[1];
+   if (part_id < 0) return 0;
+   rp = ed->table_parts[part_id % ed->table_parts_size];
+   if (rp->chosen_description)
+     {
+       SETFLOAT(rp->chosen_description->state.value, params[4]);
+       s = rp->chosen_description->state.name;
+       if (s)
+         {
+            if (strlen(s) < params[3])
+              {
+                 SETSTR(s, params[2]);
+              }
+            else
+              {
+                 char *ss;
+
+                 ss = alloca(strlen(s) + 1);
+                 strcpy(ss, s);
+                 ss[params[3] - 1] = 0;
+                 SETSTR(ss, params[2]);
+              }
+         }
+       else
+         {
+            SETSTR("", params[2]);
+         }
+     }
+   else
+     {
+       SETFLOAT(0.0, params[4]);
+       SETSTR("", params[2]);
+     }
+   return 0;
+}
+
+/* set_tween_state(part_id, Float:tween, state1[], Float:state1_val, state2[], Float:state2_val) */
+static Embryo_Cell
+_edje_embryo_fn_set_tween_state(Embryo_Program *ep, Embryo_Cell *params)
+{
+   Edje *ed;
+   char *state1 = NULL, *state2 = NULL;
+   int part_id = 0;
+   float f = 0.0;
+   double tween = 0.0, value1 = 0.0, value2 = 0.0;
+   Edje_Real_Part *rp;
+
+   CHKPARAM(6);
+   ed = embryo_program_data_get(ep);
+   GETSTR(state1, params[3]);
+   GETSTR(state2, params[5]);
+   if ((!state1) || (!state2)) return 0;
+   part_id = params[1];
+   if (part_id < 0) return 0;
+   f = EMBRYO_CELL_TO_FLOAT(params[2]);
+   tween = (double)f;
+   f = EMBRYO_CELL_TO_FLOAT(params[4]);
+   value1 = (double)f;
+   f = EMBRYO_CELL_TO_FLOAT(params[6]);
+   value2 = (double)f;
+   rp = ed->table_parts[part_id % ed->table_parts_size];
+   if (rp)
+     {
+       if (rp->program) _edje_program_end(ed, rp->program);
+       _edje_part_description_apply(ed, rp, state1, value1, state2, value2);
+       _edje_part_pos_set(ed, rp, EDJE_TWEEN_MODE_LINEAR, FROM_DOUBLE(tween));
+       _edje_recalc(ed);
+     }
+   return 0;
+}
+
+/* run_program(program_id) */
+static Embryo_Cell
+_edje_embryo_fn_run_program(Embryo_Program *ep, Embryo_Cell *params)
+{
+   Edje *ed;
+   int program_id = 0;
+   Edje_Program *pr;
+
+   CHKPARAM(1);
+   ed = embryo_program_data_get(ep);
+   program_id = params[1];
+   if (program_id < 0) return 0;
+   pr = ed->table_programs[program_id % ed->table_programs_size];
+   if (pr)
+     {
+       _edje_program_run(ed, pr, 0, "", "");
+     }
+   return 0;
+}
+
+/* get_drag_dir(part_id) */
+static Embryo_Cell
+_edje_embryo_fn_get_drag_dir(Embryo_Program *ep, Embryo_Cell *params)
+{
+   Edje *ed;
+   int part_id = 0;
+   Edje_Real_Part *rp;
+
+   CHKPARAM(1);
+   ed = embryo_program_data_get(ep);
+   part_id = params[1];
+   if (part_id < 0) return 0;
+   rp = ed->table_parts[part_id % ed->table_parts_size];
+   return edje_object_part_drag_dir_get(ed->obj, rp->part->name);
+}
+
+/* get_drag(part_id, &Float:dx, &Float:dy) */
+static Embryo_Cell
+_edje_embryo_fn_get_drag(Embryo_Program *ep, Embryo_Cell *params)
+{
+   Edje *ed;
+   int part_id = 0;
+   Edje_Real_Part *rp;
+   double dx = 0.0, dy = 0.0;
+
+   CHKPARAM(3);
+   ed = embryo_program_data_get(ep);
+   part_id = params[1];
+   if (part_id < 0) return 0;
+   rp = ed->table_parts[part_id % ed->table_parts_size];
+   edje_object_part_drag_value_get(ed->obj, rp->part->name, &dx, &dy);
+   SETFLOAT(dx, params[2]);
+   SETFLOAT(dy, params[3]);
+
+   return 0;
+}
+
+/* set_drag(part_id, Float:dx, Float:dy) */
+static Embryo_Cell
+_edje_embryo_fn_set_drag(Embryo_Program *ep, Embryo_Cell *params)
+{
+   Edje *ed;
+   int part_id = 0;
+   Edje_Real_Part *rp;
+
+   CHKPARAM(3);
+   ed = embryo_program_data_get(ep);
+   part_id = params[1];
+   if (part_id < 0) return 0;
+   rp = ed->table_parts[part_id % ed->table_parts_size];
+   edje_object_part_drag_value_set(ed->obj, rp->part->name,
+                                  (double)EMBRYO_CELL_TO_FLOAT(params[2]),
+                                  (double)EMBRYO_CELL_TO_FLOAT(params[3]));
+   return(0);
+}
+
+/* get_drag_size(part_id, &Float:dx, &Float:dy) */
+static Embryo_Cell
+_edje_embryo_fn_get_drag_size(Embryo_Program *ep, Embryo_Cell *params)
+{
+   Edje *ed;
+   int part_id = 0;
+   Edje_Real_Part *rp;
+   double dx = 0.0, dy = 0.0;
+
+   CHKPARAM(3);
+   ed = embryo_program_data_get(ep);
+   part_id = params[1];
+   if (part_id < 0) return 0;
+   rp = ed->table_parts[part_id % ed->table_parts_size];
+   edje_object_part_drag_size_get(ed->obj, rp->part->name, &dx, &dy);
+   SETFLOAT(dx, params[2]);
+   SETFLOAT(dy, params[3]);
+
+   return 0;
+}
+
+/* set_drag_size(part_id, Float:dx, Float:dy) */
+static Embryo_Cell
+_edje_embryo_fn_set_drag_size(Embryo_Program *ep, Embryo_Cell *params)
+{
+   Edje *ed;
+   int part_id = 0;
+   Edje_Real_Part *rp;
+
+   CHKPARAM(3);
+   ed = embryo_program_data_get(ep);
+   part_id = params[1];
+   if (part_id < 0) return 0;
+   rp = ed->table_parts[part_id % ed->table_parts_size];
+   edje_object_part_drag_size_set(ed->obj, rp->part->name,
+                                  (double)EMBRYO_CELL_TO_FLOAT(params[2]),
+                                  (double)EMBRYO_CELL_TO_FLOAT(params[3]));
+   return(0);
+}
+
+/* set_text(part_id, str[]) */
+static Embryo_Cell
+_edje_embryo_fn_set_text(Embryo_Program *ep, Embryo_Cell *params)
+{
+   Edje *ed;
+   int part_id = 0;
+   Edje_Real_Part *rp;
+   char *s;
+
+   CHKPARAM(2);
+   ed = embryo_program_data_get(ep);
+   part_id = params[1];
+   if (part_id < 0) return 0;
+   rp = ed->table_parts[part_id % ed->table_parts_size];
+   GETSTR(s, params[2]);
+   if (s){
+     edje_object_part_text_set(ed->obj, rp->part->name, s);
+   }
+   return(0);
+}
+
+/* get_text(part_id, dst[], maxlen) */
+static Embryo_Cell
+_edje_embryo_fn_get_text(Embryo_Program *ep, Embryo_Cell *params)
+{
+   Edje *ed;
+   int part_id = 0;
+   Edje_Real_Part *rp;
+   char *s;
+
+   CHKPARAM(3);
+   ed = embryo_program_data_get(ep);
+   part_id = params[1];
+   if (part_id < 0) return 0;
+   rp = ed->table_parts[part_id % ed->table_parts_size];
+   s = (char *)edje_object_part_text_get(ed->obj, rp->part->name);
+   if (s)
+     {
+       if (strlen(s) < params[3])
+         {
+            SETSTR(s, params[2]);
+         }
+       else
+         {
+            char *ss;
+
+            ss = alloca(strlen(s) + 1);
+            strcpy(ss, s);
+            ss[params[3] - 1] = 0;
+            SETSTR(ss, params[2]);
+         }
+     }
+   else
+     {
+       SETSTR("", params[2]);
+     }
+   return 0;
+}
+
+/* get_min_size(&w, &h) */
+static Embryo_Cell
+_edje_embryo_fn_get_min_size(Embryo_Program *ep, Embryo_Cell *params)
+{
+   Edje *ed;
+   Evas_Coord w = 0, h = 0;
+
+   CHKPARAM(2);
+   ed = embryo_program_data_get(ep);
+   edje_object_size_min_get(ed->obj, &w, &h);
+   SETINT(w, params[1]);
+   SETINT(h, params[2]);
+   return 0;
+}
+
+/* get_max_size(&w, &h) */
+static Embryo_Cell
+_edje_embryo_fn_get_max_size(Embryo_Program *ep, Embryo_Cell *params)
+{
+   Edje *ed;
+   Evas_Coord w = 0, h = 0;
+
+   CHKPARAM(2);
+   ed = embryo_program_data_get(ep);
+   edje_object_size_max_get(ed->obj, &w, &h);
+   SETINT(w, params[1]);
+   SETINT(h, params[2]);
+   return 0;
+
+}
+
+/* get_color_class(class[], &r, &g, &b, &a) */
+static Embryo_Cell
+_edje_embryo_fn_get_color_class(Embryo_Program *ep, Embryo_Cell *params)
+{
+   Edje *ed;
+   Edje_Color_Class *c_class;
+   char *class;
+
+   CHKPARAM(5);
+   ed = embryo_program_data_get(ep);
+   GETSTR(class, params[1]);
+   if (!class) return 0;
+   c_class = _edje_color_class_find(ed, class);
+   if (c_class == NULL) return 0;
+   SETINT(c_class->r, params[2]);
+   SETINT(c_class->g, params[3]);
+   SETINT(c_class->b, params[4]);
+   SETINT(c_class->a, params[5]);
+   return 0;
+}
+
+/* set_color_class(class[], r, g, b, a) */
+static Embryo_Cell
+_edje_embryo_fn_set_color_class(Embryo_Program *ep, Embryo_Cell *params)
+{
+   Edje *ed;
+   char *class;
+
+   CHKPARAM(5);
+   ed = embryo_program_data_get(ep);
+   GETSTR(class, params[1]);
+   if (!class) return 0;
+   edje_object_color_class_set(ed->obj, class, params[2], params[3], params[4], params[5],
+                              params[2], params[3], params[4], params[5],
+                              params[2], params[3], params[4], params[5]);
+   return 0;
+}
+
+/* set_text_class(class[], font[], Float:size) */
+static Embryo_Cell
+_edje_embryo_fn_set_text_class(Embryo_Program *ep, Embryo_Cell *params)
+{
+   Edje *ed;
+   char *class, *font;
+   Evas_Font_Size fsize;
+
+   CHKPARAM(3);
+   ed = embryo_program_data_get(ep);
+   GETSTR(class, params[1]);
+   GETSTR(font, params[2]);
+   if( !class || !font ) return 0;
+   fsize = (Evas_Font_Size) EMBRYO_CELL_TO_FLOAT(params[3]);
+   edje_object_text_class_set(ed->obj, class, font, fsize);
+   return 0;
+}
+
+/* get_text_class(class[], font[], &Float:size) */
+static Embryo_Cell
+_edje_embryo_fn_get_text_class(Embryo_Program *ep, Embryo_Cell *params)
+{
+   Edje *ed;
+   char *class;
+   Edje_Text_Class *t_class;
+
+   CHKPARAM(3);
+   ed = embryo_program_data_get(ep);
+   GETSTR(class, params[1]);
+   if (!class) return 0;
+   t_class = _edje_text_class_find(ed, class);
+   if (t_class == NULL) return 0;
+   SETSTR((char *)t_class->font, params[2]);
+   SETFLOAT(t_class->size, params[3]);
+   return 0;
+}
+
+/* get_drag_step(part_id, &Float:dx, &Float:&dy) */
+static Embryo_Cell
+_edje_embryo_fn_get_drag_step(Embryo_Program *ep, Embryo_Cell *params)
+{
+   Edje *ed;
+   int part_id = 0;
+   Edje_Real_Part *rp;
+   double dx = 0.0, dy = 0.0;
+
+   CHKPARAM(3);
+   ed = embryo_program_data_get(ep);
+   part_id = params[1];
+   if (part_id < 0) return 0;
+   rp = ed->table_parts[part_id % ed->table_parts_size];
+   edje_object_part_drag_step_get(ed->obj, rp->part->name, &dx, &dy);
+   SETFLOAT(dx, params[2]);
+   SETFLOAT(dy, params[3]);
+
+   return 0;
+}
+
+/* set_drag_step(part_id, Float:dx, Float:dy) */
+static Embryo_Cell
+_edje_embryo_fn_set_drag_step(Embryo_Program *ep, Embryo_Cell *params)
+{
+   Edje *ed;
+   int part_id = 0;
+   Edje_Real_Part *rp;
+
+   CHKPARAM(3);
+   ed = embryo_program_data_get(ep);
+   part_id = params[1];
+   if (part_id < 0) return 0;
+   rp = ed->table_parts[part_id % ed->table_parts_size];
+   edje_object_part_drag_step_set(ed->obj, rp->part->name,
+                                 (double)EMBRYO_CELL_TO_FLOAT(params[2]),
+                                 (double)EMBRYO_CELL_TO_FLOAT(params[3]));
+   return(0);
+}
+
+/* get_drag_page(part_id, &Float:dx, &Float:&dy) */
+static Embryo_Cell
+_edje_embryo_fn_get_drag_page(Embryo_Program *ep, Embryo_Cell *params)
+{
+   Edje *ed;
+   int part_id = 0;
+   Edje_Real_Part *rp;
+   double dx = 0.0, dy = 0.0;
+
+   CHKPARAM(3);
+   ed = embryo_program_data_get(ep);
+   part_id = params[1];
+   if (part_id < 0) return 0;
+   rp = ed->table_parts[part_id % ed->table_parts_size];
+   edje_object_part_drag_page_get(ed->obj, rp->part->name, &dx, &dy);
+   SETFLOAT(dx, params[2]);
+   SETFLOAT(dy, params[3]);
+
+   return 0;
+}
+
+/* get_geometry(pard_id, &x, &y, &w, &h) */
+static Embryo_Cell
+_edje_embryo_fn_get_geometry(Embryo_Program *ep, Embryo_Cell *params)
+{
+   Edje *ed;
+   int part_id = 0;
+   Edje_Real_Part *rp;
+   Evas_Coord x = 0.0, y = 0.0, w = 0.0, h = 0.0;
+
+   CHKPARAM(5);
+   ed = embryo_program_data_get(ep);
+   part_id = params[1];
+   if (part_id < 0) return 0;
+   rp = ed->table_parts[part_id % ed->table_parts_size];
+   edje_object_part_geometry_get(ed->obj, rp->part->name, &x, &y, &w, &h);
+   SETINT(x, params[2]);
+   SETINT(y, params[3]);
+   SETINT(w, params[4]);
+   SETINT(h, params[5]);
+
+   return 0;
+}
+
+/* set_drag_page(part_id, Float:dx, Float:dy) */
+static Embryo_Cell
+_edje_embryo_fn_set_drag_page(Embryo_Program *ep, Embryo_Cell *params)
+{
+   Edje *ed;
+   int part_id = 0;
+   Edje_Real_Part *rp;
+
+   CHKPARAM(3);
+   ed = embryo_program_data_get(ep);
+   part_id = params[1];
+   if (part_id < 0) return 0;
+   rp = ed->table_parts[part_id % ed->table_parts_size];
+   edje_object_part_drag_page_set(ed->obj, rp->part->name,
+                                 (double)EMBRYO_CELL_TO_FLOAT(params[2]),
+                                 (double)EMBRYO_CELL_TO_FLOAT(params[3]));
+   return(0);
+}
+
+/* send_message(Msg_Type:type, id,...); */
+static Embryo_Cell
+_edje_embryo_fn_send_message(Embryo_Program *ep, Embryo_Cell *params)
+{
+   Edje *ed;
+   Edje_Message_Type type;
+   int id, i, n;
+   Embryo_Cell *ptr;
+
+   if (params[0] < (sizeof(Embryo_Cell) * (2))) return 0;
+   ed = embryo_program_data_get(ep);
+   type = params[1];
+   id = params[2];
+   switch (type)
+     {
+      case EDJE_MESSAGE_NONE:
+       _edje_message_send(ed, EDJE_QUEUE_APP, type, id, NULL);
+       break;
+      case EDJE_MESSAGE_SIGNAL:
+       break;
+      case EDJE_MESSAGE_STRING:
+         {
+            Embryo_Cell *cptr;
+
+            cptr = embryo_data_address_get(ep, params[3]);
+            if (cptr)
+              {
+                 Edje_Message_String *emsg;
+                 int l;
+                 char *s;
+
+                 l = embryo_data_string_length_get(ep, cptr);
+                 s = alloca(l + 1);
+                 embryo_data_string_get(ep, cptr, s);
+                 emsg = alloca(sizeof(Edje_Message_String));
+                 emsg->str = s;
+                 _edje_message_send(ed, EDJE_QUEUE_APP, type, id, emsg);
+              }
+         }
+       break;
+      case EDJE_MESSAGE_INT:
+         {
+            Edje_Message_Int *emsg;
+
+            emsg = alloca(sizeof(Edje_Message_Int));
+            ptr = embryo_data_address_get(ep, params[3]);
+            emsg->val = (int)*ptr;
+            _edje_message_send(ed, EDJE_QUEUE_APP, type, id, emsg);
+         }
+       break;
+      case EDJE_MESSAGE_FLOAT:
+         {
+            Edje_Message_Float *emsg;
+            float f;
+
+            emsg = alloca(sizeof(Edje_Message_Float));
+            ptr = embryo_data_address_get(ep, params[3]);
+            f = EMBRYO_CELL_TO_FLOAT(*ptr);
+            emsg->val = (double)f;
+            _edje_message_send(ed, EDJE_QUEUE_APP, type, id, emsg);
+         }
+       break;
+      case EDJE_MESSAGE_STRING_SET:
+         {
+            Edje_Message_String_Set *emsg;
+
+            n = (params[0] / sizeof(Embryo_Cell)) + 1;
+            emsg = alloca(sizeof(Edje_Message_String_Set) + ((n - 3 - 1) * sizeof(char *)));
+            emsg->count = n - 3;
+            for (i = 3; i < n; i++)
+              {
+                 Embryo_Cell *cptr;
+
+                 cptr = embryo_data_address_get(ep, params[i]);
+                 if (cptr)
+                   {
+                      int l;
+                      char *s;
+
+                      l = embryo_data_string_length_get(ep, cptr);
+                      s = alloca(l + 1);
+                      embryo_data_string_get(ep, cptr, s);
+                      emsg->str[i - 3] = s;
+                   }
+              }
+            _edje_message_send(ed, EDJE_QUEUE_APP, type, id, emsg);
+         }
+       break;
+      case EDJE_MESSAGE_INT_SET:
+         {
+            Edje_Message_Int_Set *emsg;
+
+            n = (params[0] / sizeof(Embryo_Cell)) + 1;
+            emsg = alloca(sizeof(Edje_Message_Int_Set) + ((n - 3 - 1) * sizeof(int)));
+            emsg->count = n - 3;
+            for (i = 3; i < n; i++)
+              {
+                 ptr = embryo_data_address_get(ep, params[i]);
+                 emsg->val[i - 3] = (int)*ptr;
+              }
+            _edje_message_send(ed, EDJE_QUEUE_APP, type, id, emsg);
+         }
+       break;
+      case EDJE_MESSAGE_FLOAT_SET:
+         {
+            Edje_Message_Float_Set *emsg;
+
+            n = (params[0] / sizeof(Embryo_Cell)) + 1;
+            emsg = alloca(sizeof(Edje_Message_Float_Set) + ((n - 3 - 1) * sizeof(double)));
+            emsg->count = n - 3;
+            for (i = 3; i < n; i++)
+              {
+                 float f;
+
+                 ptr = embryo_data_address_get(ep, params[i]);
+                 f = EMBRYO_CELL_TO_FLOAT(*ptr);
+                 emsg->val[i - 3] = (double)f;
+              }
+            _edje_message_send(ed, EDJE_QUEUE_APP, type, id, emsg);
+         }
+       break;
+      case EDJE_MESSAGE_STRING_INT:
+         {
+            Edje_Message_String_Int *emsg;
+            Embryo_Cell *cptr;
+
+            cptr = embryo_data_address_get(ep, params[3]);
+            if (cptr)
+              {
+                 int l;
+                 char *s;
+
+                 l = embryo_data_string_length_get(ep, cptr);
+                 s = alloca(l + 1);
+                 embryo_data_string_get(ep, cptr, s);
+                 emsg = alloca(sizeof(Edje_Message_String_Int));
+                 emsg->str = s;
+                 ptr = embryo_data_address_get(ep, params[4]);
+                 emsg->val = (int)*ptr;
+                 _edje_message_send(ed, EDJE_QUEUE_APP, type, id, emsg);
+              }
+         }
+       break;
+      case EDJE_MESSAGE_STRING_FLOAT:
+         {
+            Edje_Message_String_Float *emsg;
+            Embryo_Cell *cptr;
+
+            cptr = embryo_data_address_get(ep, params[3]);
+            if (cptr)
+              {
+                 int l;
+                 char *s;
+                 float f;
+
+                 l = embryo_data_string_length_get(ep, cptr);
+                 s = alloca(l + 1);
+                 embryo_data_string_get(ep, cptr, s);
+                 emsg = alloca(sizeof(Edje_Message_String_Float));
+                 emsg->str = s;
+                 ptr = embryo_data_address_get(ep, params[4]);
+                 f = EMBRYO_CELL_TO_FLOAT(*ptr);
+                 emsg->val = (double)f;
+                 _edje_message_send(ed, EDJE_QUEUE_APP, type, id, emsg);
+              }
+         }
+       break;
+      case EDJE_MESSAGE_STRING_INT_SET:
+         {
+            Edje_Message_String_Int_Set *emsg;
+            Embryo_Cell *cptr;
+
+            cptr = embryo_data_address_get(ep, params[3]);
+            if (cptr)
+              {
+                 int l;
+                 char *s;
+
+                 l = embryo_data_string_length_get(ep, cptr);
+                 s = alloca(l + 1);
+                 embryo_data_string_get(ep, cptr, s);
+                 n = (params[0] / sizeof(Embryo_Cell)) + 1;
+                 emsg = alloca(sizeof(Edje_Message_String_Int_Set) + ((n - 4 - 1) * sizeof(int)));
+                 emsg->str = s;
+                 emsg->count = n - 4;
+                 for (i = 4; i < n; i++)
+                   {
+                      ptr = embryo_data_address_get(ep, params[i]);
+                      emsg->val[i - 4] = (int)*ptr;
+                   }
+                 _edje_message_send(ed, EDJE_QUEUE_APP, type, id, emsg);
+              }
+         }
+       break;
+      case EDJE_MESSAGE_STRING_FLOAT_SET:
+         {
+            Edje_Message_String_Float_Set *emsg;
+            Embryo_Cell *cptr;
+
+            cptr = embryo_data_address_get(ep, params[3]);
+            if (cptr)
+              {
+                 int l;
+                 char *s;
+
+                 l = embryo_data_string_length_get(ep, cptr);
+                 s = alloca(l + 1);
+                 embryo_data_string_get(ep, cptr, s);
+                 n = (params[0] / sizeof(Embryo_Cell)) + 1;
+                 emsg = alloca(sizeof(Edje_Message_String_Float_Set) + ((n - 4 - 1) * sizeof(double)));
+                 emsg->str = s;
+                 emsg->count = n - 4;
+                 for (i = 4; i < n; i++)
+                   {
+                      float f;
+
+                      ptr = embryo_data_address_get(ep, params[i]);
+                      f = EMBRYO_CELL_TO_FLOAT(*ptr);
+                      emsg->val[i - 4] = (double)f;
+                   }
+                 _edje_message_send(ed, EDJE_QUEUE_APP, type, id, emsg);
+              }
+         }
+       break;
+      default:
+       break;
+     }
+   return(0);
+}
+
+/* custom_state(part_id, state[], Float:state_val = 0.0) */
+static Embryo_Cell
+_edje_embryo_fn_custom_state(Embryo_Program *ep, Embryo_Cell *params)
+{
+   Edje *ed = embryo_program_data_get(ep);
+   Edje_Real_Part *rp;
+   Edje_Part_Description *parent, *d;
+   Edje_Part_Image_Id *iid;
+   Eina_List *l;
+   char *name;
+   float val;
+
+   CHKPARAM(3);
+
+   if (params[1] < 0)
+     return 0;
+
+   if (!(rp = ed->table_parts[params[1] % ed->table_parts_size]))
+     return 0;
+
+   /* check whether this part already has a "custom" state */
+   if (rp->custom)
+     return 0;
+
+   GETSTR(name, params[2]);
+   if (!name)
+     return 0;
+
+   val = EMBRYO_CELL_TO_FLOAT(params[3]);
+
+   if (!(parent = _edje_part_description_find(ed, rp, name, val)))
+     return 0;
+
+   /* now create the custom state */
+   if (!(d = calloc(1, sizeof(Edje_Part_Description))))
+     return 0;
+
+   rp->custom = eina_mempool_malloc(_edje_real_part_state_mp, sizeof (Edje_Real_Part_State));
+   if (!rp->custom)
+     {
+       free(d);
+       return 0;
+     }
+
+   *d = *parent;
+
+   d->state.name = (char *)eina_stringshare_add("custom");
+   d->state.value = 0.0;
+
+   /* make sure all the allocated memory is getting copied,
+    * not just referenced
+    */
+   d->image.tween_list = NULL;
+
+   EINA_LIST_FOREACH(parent->image.tween_list, l, iid)
+     {
+        Edje_Part_Image_Id *iid_new;
+
+       iid_new = calloc(1, sizeof(Edje_Part_Image_Id));
+       if (!iid_new) continue;
+
+       iid_new->id = iid->id;
+
+       d->image.tween_list = eina_list_append(d->image.tween_list, iid_new);
+     }
+
+#define DUP(x) x ? (char *)eina_stringshare_add(x) : NULL
+   d->color_class = DUP(d->color_class);
+   d->text.text = DUP(d->text.text);
+   d->text.text_class = DUP(d->text.text_class);
+   d->text.font = DUP(d->text.font);
+   d->text.style = DUP(d->text.style);
+#undef DUP
+
+   rp->custom->description = d;
+
+   return 0;
+}
+
+/* set_state_val(part_id, State_Param:p, ...) */
+static Embryo_Cell
+_edje_embryo_fn_set_state_val(Embryo_Program *ep, Embryo_Cell *params)
+{
+   Edje *ed = embryo_program_data_get(ep);
+   Edje_Real_Part *rp;
+   char *s;
+
+   /* we need at least 3 arguments */
+   if (params[0] < (sizeof(Embryo_Cell) * 3))
+     return 0;
+
+   if (params[1] < 0)
+     return 0;
+
+   if (!(rp = ed->table_parts[params[1] % ed->table_parts_size]))
+     return 0;
+
+   /* check whether this part has a "custom" state */
+   if (!rp->custom)
+     return 0;
+
+   switch (params[2])
+     {
+      case EDJE_STATE_PARAM_ALIGNMENT:
+        CHKPARAM(4);
+
+        GETFLOAT_T(rp->custom->description->align.x, params[3]);
+        GETFLOAT_T(rp->custom->description->align.y, params[4]);
+
+        break;
+      case EDJE_STATE_PARAM_MIN:
+        CHKPARAM(4);
+
+        GETINT(rp->custom->description->min.w, params[3]);
+        GETINT(rp->custom->description->min.h, params[4]);
+
+        break;
+      case EDJE_STATE_PARAM_MAX:
+        CHKPARAM(4);
+
+        GETINT(rp->custom->description->max.w, params[3]);
+        GETINT(rp->custom->description->max.h, params[4]);
+
+        break;
+      case EDJE_STATE_PARAM_STEP:
+        CHKPARAM(4);
+
+        GETINT(rp->custom->description->step.x, params[3]);
+        GETINT(rp->custom->description->step.y, params[4]);
+
+        break;
+      case EDJE_STATE_PARAM_ASPECT:
+        CHKPARAM(4);
+
+        GETFLOAT_T(rp->custom->description->aspect.min, params[3]);
+        GETFLOAT_T(rp->custom->description->aspect.max, params[4]);
+
+        break;
+      case EDJE_STATE_PARAM_ASPECT_PREF:
+        CHKPARAM(3);
+
+        GETINT(rp->custom->description->aspect.prefer, params[3]);
+
+        break;
+      case EDJE_STATE_PARAM_COLOR:
+        CHKPARAM(6);
+
+        GETINT(rp->custom->description->color.r, params[3]);
+        GETINT(rp->custom->description->color.g, params[4]);
+        GETINT(rp->custom->description->color.b, params[5]);
+        GETINT(rp->custom->description->color.a, params[6]);
+
+        break;
+      case EDJE_STATE_PARAM_COLOR2:
+        CHKPARAM(6);
+
+        GETINT(rp->custom->description->color2.r, params[3]);
+        GETINT(rp->custom->description->color2.g, params[4]);
+        GETINT(rp->custom->description->color2.b, params[5]);
+        GETINT(rp->custom->description->color2.a, params[6]);
+
+        break;
+      case EDJE_STATE_PARAM_COLOR3:
+        CHKPARAM(6);
+
+        GETINT(rp->custom->description->color3.r, params[3]);
+        GETINT(rp->custom->description->color3.g, params[4]);
+        GETINT(rp->custom->description->color3.b, params[5]);
+        GETINT(rp->custom->description->color3.a, params[6]);
+
+        break;
+      case EDJE_STATE_PARAM_COLOR_CLASS:
+        CHKPARAM(3);
+
+        GETSTR(s, params[3]);
+        GETSTREVAS(s, rp->custom->description->color_class);
+
+        break;
+      case EDJE_STATE_PARAM_REL1:
+        CHKPARAM(4);
+
+        GETFLOAT_T(rp->custom->description->rel1.relative_x, params[3]);
+        GETFLOAT_T(rp->custom->description->rel1.relative_y, params[4]);
+
+        break;
+      case EDJE_STATE_PARAM_REL1_TO:
+        CHKPARAM(4);
+
+        GETINT(rp->custom->description->rel1.id_x, params[3]);
+        GETINT(rp->custom->description->rel1.id_y, params[4]);
+
+        if (rp->param1.description->rel1.id_x >= 0)
+          rp->param1.rel1_to_x = ed->table_parts[rp->param1.description->rel1.id_x % ed->table_parts_size];
+        if (rp->param1.description->rel1.id_y >= 0)
+          rp->param1.rel1_to_y = ed->table_parts[rp->param1.description->rel1.id_y % ed->table_parts_size];
+
+        break;
+      case EDJE_STATE_PARAM_REL1_OFFSET:
+        CHKPARAM(4);
+
+        GETINT(rp->custom->description->rel1.offset_x, params[3]);
+        GETINT(rp->custom->description->rel1.offset_y, params[4]);
+
+        break;
+      case EDJE_STATE_PARAM_REL2:
+        CHKPARAM(4);
+
+        GETFLOAT_T(rp->custom->description->rel2.relative_x, params[3]);
+        GETFLOAT_T(rp->custom->description->rel2.relative_y, params[4]);
+
+        break;
+      case EDJE_STATE_PARAM_REL2_TO:
+        CHKPARAM(4);
+
+        GETINT(rp->custom->description->rel2.id_x, params[3]);
+        GETINT(rp->custom->description->rel2.id_y, params[4]);
+
+        if (rp->param1.description->rel2.id_x >= 0)
+          rp->param1.rel2_to_x = ed->table_parts[rp->param1.description->rel2.id_x % ed->table_parts_size];
+        if (rp->param1.description->rel2.id_y >= 0)
+          rp->param1.rel2_to_y = ed->table_parts[rp->param1.description->rel2.id_y % ed->table_parts_size];
+
+        break;
+      case EDJE_STATE_PARAM_REL2_OFFSET:
+        CHKPARAM(4);
+
+        GETINT(rp->custom->description->rel2.offset_x, params[3]);
+        GETINT(rp->custom->description->rel2.offset_y, params[4]);
+
+        break;
+      case EDJE_STATE_PARAM_IMAGE:
+        if ( (rp->part->type != EDJE_PART_TYPE_IMAGE) ) return 0;
+        CHKPARAM(3);
+
+        GETINT(rp->custom->description->image.id, params[3]);
+
+        break;
+      case EDJE_STATE_PARAM_BORDER:
+        if ( (rp->part->type != EDJE_PART_TYPE_IMAGE) ) return 0;
+        CHKPARAM(6);
+
+        GETINT(rp->custom->description->border.l, params[3]);
+        GETINT(rp->custom->description->border.r, params[4]);
+        GETINT(rp->custom->description->border.t, params[5]);
+        GETINT(rp->custom->description->border.b, params[6]);
+
+        break;
+      case EDJE_STATE_PARAM_FILL_SMOOTH:
+        if ( (rp->part->type != EDJE_PART_TYPE_IMAGE) ) return 0;
+        CHKPARAM(3);
+
+        GETINT(rp->custom->description->fill.smooth, params[3]);
+
+        break;
+      case EDJE_STATE_PARAM_FILL_POS:
+        if ( (rp->part->type != EDJE_PART_TYPE_IMAGE) ) return 0;
+        CHKPARAM(6);
+
+        GETFLOAT_T(rp->custom->description->fill.pos_rel_x, params[3]);
+        GETFLOAT_T(rp->custom->description->fill.pos_rel_y, params[4]);
+        GETINT(rp->custom->description->fill.pos_abs_x, params[5]);
+        GETINT(rp->custom->description->fill.pos_abs_y, params[6]);
+
+        break;
+      case EDJE_STATE_PARAM_FILL_SIZE:
+        if ( (rp->part->type != EDJE_PART_TYPE_IMAGE) ) return 0;
+        CHKPARAM(6);
+
+        GETFLOAT_T(rp->custom->description->fill.rel_x, params[3]);
+        GETFLOAT_T(rp->custom->description->fill.rel_y, params[4]);
+        GETINT(rp->custom->description->fill.abs_x, params[5]);
+        GETINT(rp->custom->description->fill.abs_y, params[6]);
+
+        break;
+      case EDJE_STATE_PARAM_TEXT:
+        if ( (rp->part->type != EDJE_PART_TYPE_TEXT) && \
+             (rp->part->type != EDJE_PART_TYPE_TEXTBLOCK))
+          return 0;
+        CHKPARAM(3);
+
+        GETSTR(s, params[3]);
+        GETSTREVAS(s, rp->custom->description->text.text);
+
+        break;
+      case EDJE_STATE_PARAM_TEXT_CLASS:
+        if ( (rp->part->type != EDJE_PART_TYPE_TEXT) && \
+              (rp->part->type != EDJE_PART_TYPE_TEXTBLOCK))
+          return 0;
+        CHKPARAM(3);
+
+        GETSTR(s, params[3]);
+        GETSTREVAS(s, rp->custom->description->text.text_class);
+
+        break;
+      case EDJE_STATE_PARAM_TEXT_FONT:
+        if ((rp->part->type != EDJE_PART_TYPE_TEXT)) return 0;
+        CHKPARAM(3);
+
+        GETSTR(s, params[3]);
+        GETSTREVAS(s, rp->custom->description->text.font);
+
+        break;
+      case EDJE_STATE_PARAM_TEXT_STYLE:
+        if ((rp->part->type != EDJE_PART_TYPE_TEXTBLOCK)) return 0;
+        CHKPARAM(3);
+
+        GETSTR(s, params[3]);
+        GETSTREVAS(s, rp->custom->description->text.style);
+
+        break;
+      case EDJE_STATE_PARAM_TEXT_SIZE:
+        if ((rp->part->type != EDJE_PART_TYPE_TEXT)) return 0;
+        CHKPARAM(3);
+
+        GETINT(rp->custom->description->text.size, params[3]);
+
+        break;
+      case EDJE_STATE_PARAM_TEXT_FIT:
+        if ((rp->part->type != EDJE_PART_TYPE_TEXT)) return 0;
+        CHKPARAM(4);
+
+        GETINT(rp->custom->description->text.fit_x, params[3]);
+        GETINT(rp->custom->description->text.fit_y, params[4]);
+
+        break;
+      case EDJE_STATE_PARAM_TEXT_MIN:
+        if ( (rp->part->type != EDJE_PART_TYPE_TEXT) && \
+              (rp->part->type != EDJE_PART_TYPE_TEXTBLOCK))
+          return 0;
+        CHKPARAM(4);
+
+        GETINT(rp->custom->description->text.min_x, params[3]);
+        GETINT(rp->custom->description->text.min_y, params[4]);
+
+        break;
+      case EDJE_STATE_PARAM_TEXT_MAX:
+        if ( (rp->part->type != EDJE_PART_TYPE_TEXT) && \
+              (rp->part->type != EDJE_PART_TYPE_TEXTBLOCK))
+          return 0;
+        CHKPARAM(4);
+
+        GETINT(rp->custom->description->text.max_x, params[3]);
+        GETINT(rp->custom->description->text.max_y, params[4]);
+
+        break;
+      case EDJE_STATE_PARAM_TEXT_ALIGN:
+        if ((rp->part->type != EDJE_PART_TYPE_TEXT)) return 0;
+        CHKPARAM(4);
+
+        GETFLOAT_T(rp->custom->description->text.align.x, params[3]);
+        GETFLOAT_T(rp->custom->description->text.align.y, params[4]);
+
+        break;
+      case EDJE_STATE_PARAM_VISIBLE:
+        CHKPARAM(3);
+
+        GETINT(rp->custom->description->visible, params[3]);
+
+        break;
+      case EDJE_STATE_PARAM_MAP_OM:
+        CHKPARAM(3);
+        
+        GETINT(rp->custom->description->map.on, params[3]);
+        
+        break;
+      case EDJE_STATE_PARAM_MAP_PERSP:
+        CHKPARAM(3);
+        
+        GETINT(rp->custom->description->map.id_persp, params[3]);
+        
+        break;
+      case EDJE_STATE_PARAM_MAP_LIGNT:
+        CHKPARAM(3);
+        
+        GETINT(rp->custom->description->map.id_light, params[3]);
+        
+        break;
+      case EDJE_STATE_PARAM_MAP_ROT_CENTER:
+        CHKPARAM(3);
+        
+        GETINT(rp->custom->description->map.rot.id_center, params[3]);
+        
+        break;
+      case EDJE_STATE_PARAM_MAP_ROT_X:
+        CHKPARAM(3);
+
+        GETFLOAT_T(rp->custom->description->map.rot.x, params[3]);
+
+        break;
+      case EDJE_STATE_PARAM_MAP_ROT_Y:
+        CHKPARAM(3);
+        
+        GETFLOAT_T(rp->custom->description->map.rot.y, params[3]);
+        
+        break;
+      case EDJE_STATE_PARAM_MAP_ROT_Z:
+        CHKPARAM(3);
+        
+        GETFLOAT_T(rp->custom->description->map.rot.z, params[3]);
+
+        break;
+      case EDJE_STATE_PARAM_MAP_BACK_CULL:
+        CHKPARAM(3);
+        
+        GETINT(rp->custom->description->map.backcull, params[3]);
+        
+        break;
+      case EDJE_STATE_PARAM_MAP_PERSP_ON:
+        CHKPARAM(3);
+        
+        GETINT(rp->custom->description->map.persp_on, params[3]);
+        
+        break;
+      case EDJE_STATE_PARAM_PERSP_ZPLANE:
+        CHKPARAM(3);
+        
+        GETINT(rp->custom->description->persp.zplane, params[3]);
+        
+        break;
+      case EDJE_STATE_PARAM_PERSP_FOCAL:
+        CHKPARAM(3);
+        
+        GETINT(rp->custom->description->persp.focal, params[3]);
+        
+        break;
+      default:
+        break;
+     }
+
+#ifdef EDJE_CALC_CACHE
+   rp->invalidate = 1;
+#endif
+   ed->dirty=1;
+   return 0;
+}
+
+/* get_state_val(part_id, State_Param:p, ...) */
+static Embryo_Cell
+_edje_embryo_fn_get_state_val(Embryo_Program *ep, Embryo_Cell *params)
+{
+   Edje *ed = embryo_program_data_get(ep);
+   Edje_Real_Part *rp;
+   char *s;
+
+   /* we need at least 3 arguments */
+   if (params[0] < (sizeof(Embryo_Cell) * 3))
+     return 0;
+
+   if (params[1] < 0)
+     return 0;
+
+   if (!(rp = ed->table_parts[params[1] % ed->table_parts_size]))
+     return 0;
+
+   /* check whether this part has a "custom" state */
+   if (!rp->custom)
+     return 0;
+
+   switch (params[2])
+     {
+      case EDJE_STATE_PARAM_ALIGNMENT:
+        CHKPARAM(4);
+
+        SETFLOAT_T(rp->custom->description->align.x, params[3]);
+        SETFLOAT_T(rp->custom->description->align.y, params[4]);
+
+        break;
+      case EDJE_STATE_PARAM_MIN:
+        CHKPARAM(4);
+
+        SETINT(rp->custom->description->min.w, params[3]);
+        SETINT(rp->custom->description->min.h, params[4]);
+
+        break;
+      case EDJE_STATE_PARAM_MAX:
+        CHKPARAM(4);
+
+        SETINT(rp->custom->description->max.w, params[3]);
+        SETINT(rp->custom->description->max.h, params[4]);
+
+        break;
+      case EDJE_STATE_PARAM_STEP:
+        CHKPARAM(4);
+
+        SETINT(rp->custom->description->step.x, params[3]);
+        SETINT(rp->custom->description->step.y, params[4]);
+
+        break;
+      case EDJE_STATE_PARAM_ASPECT:
+        CHKPARAM(4);
+
+        SETFLOAT_T(rp->custom->description->aspect.min, params[3]);
+        SETFLOAT_T(rp->custom->description->aspect.max, params[4]);
+
+        break;
+      case EDJE_STATE_PARAM_ASPECT_PREF:
+        CHKPARAM(3);
+
+        SETINT(rp->custom->description->aspect.prefer, params[3]);
+
+        break;
+      case EDJE_STATE_PARAM_COLOR:
+        CHKPARAM(6);
+
+        SETINT(rp->custom->description->color.r, params[3]);
+        SETINT(rp->custom->description->color.g, params[4]);
+        SETINT(rp->custom->description->color.b, params[5]);
+        SETINT(rp->custom->description->color.a, params[6]);
+
+        break;
+      case EDJE_STATE_PARAM_COLOR2:
+        CHKPARAM(6);
+
+        SETINT(rp->custom->description->color2.r, params[3]);
+        SETINT(rp->custom->description->color2.g, params[4]);
+        SETINT(rp->custom->description->color2.b, params[5]);
+        SETINT(rp->custom->description->color2.a, params[6]);
+
+        break;
+      case EDJE_STATE_PARAM_COLOR3:
+        CHKPARAM(6);
+
+        SETINT(rp->custom->description->color3.r, params[3]);
+        SETINT(rp->custom->description->color3.g, params[4]);
+        SETINT(rp->custom->description->color3.b, params[5]);
+        SETINT(rp->custom->description->color3.a, params[6]);
+
+        break;
+      case EDJE_STATE_PARAM_COLOR_CLASS:
+        CHKPARAM(4);
+
+        s = rp->custom->description->color_class;
+        SETSTRALLOCATE(s);
+
+        break;
+      case EDJE_STATE_PARAM_REL1:
+        CHKPARAM(4);
+
+        SETFLOAT_T(rp->custom->description->rel1.relative_x, params[3]);
+        SETFLOAT_T(rp->custom->description->rel1.relative_y, params[4]);
+
+        break;
+      case EDJE_STATE_PARAM_REL1_TO:
+        CHKPARAM(4);
+
+        SETINT(rp->custom->description->rel1.id_x, params[3]);
+        SETINT(rp->custom->description->rel1.id_y, params[4]);
+
+        break;
+      case EDJE_STATE_PARAM_REL1_OFFSET:
+        CHKPARAM(4);
+
+        SETINT(rp->custom->description->rel1.offset_x, params[3]);
+        SETINT(rp->custom->description->rel1.offset_y, params[4]);
+
+        break;
+      case EDJE_STATE_PARAM_REL2:
+        CHKPARAM(4);
+
+        SETFLOAT_T(rp->custom->description->rel2.relative_x, params[3]);
+        SETFLOAT_T(rp->custom->description->rel2.relative_y, params[4]);
+
+        break;
+      case EDJE_STATE_PARAM_REL2_TO:
+        CHKPARAM(4);
+
+        SETINT(rp->custom->description->rel2.id_x, params[3]);
+        SETINT(rp->custom->description->rel2.id_y, params[4]);
+
+        break;
+      case EDJE_STATE_PARAM_REL2_OFFSET:
+        CHKPARAM(4);
+
+        SETINT(rp->custom->description->rel2.offset_x, params[3]);
+        SETINT(rp->custom->description->rel2.offset_y, params[4]);
+
+        break;
+      case EDJE_STATE_PARAM_IMAGE:
+        if ( (rp->part->type != EDJE_PART_TYPE_IMAGE) ) return 0;
+        CHKPARAM(3);
+
+        SETINT(rp->custom->description->image.id, params[3]);
+
+        break;
+      case EDJE_STATE_PARAM_BORDER:
+        if ( (rp->part->type != EDJE_PART_TYPE_IMAGE) ) return 0;
+        CHKPARAM(6);
+
+        SETINT(rp->custom->description->border.l, params[3]);
+        SETINT(rp->custom->description->border.r, params[4]);
+        SETINT(rp->custom->description->border.t, params[5]);
+        SETINT(rp->custom->description->border.b, params[6]);
+
+        break;
+      case EDJE_STATE_PARAM_FILL_SMOOTH:
+        if ( (rp->part->type != EDJE_PART_TYPE_IMAGE) ) return 0;
+        CHKPARAM(3);
+
+        SETINT(rp->custom->description->fill.smooth, params[3]);
+
+        break;
+      case EDJE_STATE_PARAM_FILL_POS:
+        if ( (rp->part->type != EDJE_PART_TYPE_IMAGE) ) return 0;
+        CHKPARAM(6);
+
+        SETFLOAT_T(rp->custom->description->fill.pos_rel_x, params[3]);
+        SETFLOAT_T(rp->custom->description->fill.pos_rel_y, params[4]);
+        SETINT(rp->custom->description->fill.pos_abs_x, params[5]);
+        SETINT(rp->custom->description->fill.pos_abs_y, params[6]);
+
+        break;
+      case EDJE_STATE_PARAM_FILL_SIZE:
+        if ( (rp->part->type != EDJE_PART_TYPE_IMAGE) ) return 0;
+        CHKPARAM(6);
+
+        SETFLOAT_T(rp->custom->description->fill.rel_x, params[3]);
+        SETFLOAT_T(rp->custom->description->fill.rel_y, params[4]);
+        SETINT(rp->custom->description->fill.abs_x, params[5]);
+        SETINT(rp->custom->description->fill.abs_y, params[6]);
+
+        break;
+      case EDJE_STATE_PARAM_TEXT:
+        if ( (rp->part->type != EDJE_PART_TYPE_TEXT) && \
+              (rp->part->type != EDJE_PART_TYPE_TEXTBLOCK))
+          return 0;
+        CHKPARAM(4);
+
+        s = rp->custom->description->text.text;
+        SETSTRALLOCATE(s);
+
+        break;
+      case EDJE_STATE_PARAM_TEXT_CLASS:
+        if ( (rp->part->type != EDJE_PART_TYPE_TEXT) && \
+              (rp->part->type != EDJE_PART_TYPE_TEXTBLOCK))
+          return 0;
+        CHKPARAM(4);
+
+        s = rp->custom->description->text.text_class;
+        SETSTRALLOCATE(s);
+
+        break;
+      case EDJE_STATE_PARAM_TEXT_FONT:
+        if ((rp->part->type != EDJE_PART_TYPE_TEXT)) return 0;
+        CHKPARAM(4);
+
+        s = rp->custom->description->text.font;
+        SETSTRALLOCATE(s);
+
+        break;
+      case EDJE_STATE_PARAM_TEXT_STYLE:
+        if ((rp->part->type != EDJE_PART_TYPE_TEXTBLOCK)) return 0;
+        CHKPARAM(4);
+
+        s = rp->custom->description->text.style;
+        SETSTRALLOCATE(s);
+
+        break;
+      case EDJE_STATE_PARAM_TEXT_SIZE:
+        if ((rp->part->type != EDJE_PART_TYPE_TEXT)) return 0;
+        CHKPARAM(3);
+
+        SETINT(rp->custom->description->text.size, params[3]);
+
+        break;
+      case EDJE_STATE_PARAM_TEXT_FIT:
+        if ((rp->part->type != EDJE_PART_TYPE_TEXT)) return 0;
+        CHKPARAM(4);
+
+        SETINT(rp->custom->description->text.fit_x, params[3]);
+        SETINT(rp->custom->description->text.fit_y, params[4]);
+
+        break;
+      case EDJE_STATE_PARAM_TEXT_MIN:
+        if ( (rp->part->type != EDJE_PART_TYPE_TEXT) && \
+              (rp->part->type != EDJE_PART_TYPE_TEXTBLOCK))
+          return 0;
+        CHKPARAM(4);
+
+        SETINT(rp->custom->description->text.min_x, params[3]);
+        SETINT(rp->custom->description->text.min_y, params[4]);
+
+        break;
+      case EDJE_STATE_PARAM_TEXT_MAX:
+        if ( (rp->part->type != EDJE_PART_TYPE_TEXT) && \
+              (rp->part->type != EDJE_PART_TYPE_TEXTBLOCK))
+          return 0;
+        CHKPARAM(4);
+
+        SETINT(rp->custom->description->text.max_x, params[3]);
+        SETINT(rp->custom->description->text.max_y, params[4]);
+
+        break;
+      case EDJE_STATE_PARAM_TEXT_ALIGN:
+        if ((rp->part->type != EDJE_PART_TYPE_TEXT)) return 0;
+        CHKPARAM(4);
+
+        SETFLOAT_T(rp->custom->description->text.align.x, params[3]);
+        SETFLOAT_T(rp->custom->description->text.align.y, params[4]);
+
+        break;
+      case EDJE_STATE_PARAM_VISIBLE:
+        CHKPARAM(3);
+
+        SETINT(rp->custom->description->visible, params[3]);
+
+        break;
+      default:
+        break;
+     }
+
+   return 0;
+}
+
+/* part_swallow(part_id, group_name) */
+static Embryo_Cell
+_edje_embryo_fn_part_swallow(Embryo_Program *ep, Embryo_Cell *params)
+{
+   int part_id = 0;
+   char* group_name = 0;
+   Edje *ed;
+   Edje_Real_Part *rp;
+   Evas_Object *new_obj;
+   
+   CHKPARAM(2);
+
+   part_id = params[1];
+   if (part_id < 0) return 0;
+
+   GETSTR(group_name, params[2]);
+   if (!group_name) return 0;
+
+   ed = embryo_program_data_get(ep);
+
+   rp = ed->table_parts[part_id % ed->table_parts_size];
+   if (!rp) return 0;
+
+   new_obj =  edje_object_add(ed->evas);
+   if (!new_obj) return 0;
+
+   if (!edje_object_file_set(new_obj, ed->file->path, group_name)) 
+     {
+        evas_object_del(new_obj);
+        return 0;
+     }
+   edje_object_part_swallow(ed->obj, rp->part->name, new_obj);
+
+   return 0;
+}
+
+/* external_param_get_int(id, param_name[]) */
+static Embryo_Cell
+_edje_embryo_fn_external_param_get_int(Embryo_Program *ep, Embryo_Cell *params)
+{
+   Edje *ed;
+   int part_id;
+   Edje_Real_Part *rp;
+   Edje_External_Param eep;
+   char *param_name;
+
+   CHKPARAM(2);
+   ed = embryo_program_data_get(ep);
+
+   part_id = params[1];
+   if (part_id < 0) return 0;
+   rp = ed->table_parts[part_id % ed->table_parts_size];
+
+   GETSTR(param_name, params[2]);
+   if (!param_name) return 0;
+   eep.name = param_name;
+   eep.type = EDJE_EXTERNAL_PARAM_TYPE_INT;
+   eep.i = 0;
+   _edje_external_param_get(rp->swallowed_object, &eep);
+   return eep.i;
+}
+
+/* external_param_set_int(id, param_name[], val) */
+static Embryo_Cell
+_edje_embryo_fn_external_param_set_int(Embryo_Program *ep, Embryo_Cell *params)
+{
+   Edje *ed;
+   int part_id;
+   Edje_Real_Part *rp;
+   Edje_External_Param eep;
+   char *param_name;
+
+   CHKPARAM(3);
+   ed = embryo_program_data_get(ep);
+
+   part_id = params[1];
+   if (part_id < 0) return 0;
+   rp = ed->table_parts[part_id % ed->table_parts_size];
+
+   GETSTR(param_name, params[2]);
+   if (!param_name) return 0;
+   eep.name = param_name;
+   eep.type = EDJE_EXTERNAL_PARAM_TYPE_INT;
+   eep.i = params[3];
+   return _edje_external_param_set(rp->swallowed_object, &eep);
+}
+
+/* Float:external_param_get_float(id, param_name[]) */
+static Embryo_Cell
+_edje_embryo_fn_external_param_get_float(Embryo_Program *ep, Embryo_Cell *params)
+{
+   Edje *ed;
+   int part_id;
+   Edje_Real_Part *rp;
+   Edje_External_Param eep;
+   char *param_name;
+   float v;
+
+   CHKPARAM(2);
+   ed = embryo_program_data_get(ep);
+
+   part_id = params[1];
+   if (part_id < 0) return 0;
+   rp = ed->table_parts[part_id % ed->table_parts_size];
+
+   GETSTR(param_name, params[2]);
+   if (!param_name) return 0;
+   eep.name = param_name;
+   eep.type = EDJE_EXTERNAL_PARAM_TYPE_DOUBLE;
+   eep.d = 0.0;
+   _edje_external_param_get(rp->swallowed_object, &eep);
+   v = eep.d;
+   return EMBRYO_FLOAT_TO_CELL(v);
+}
+
+/* external_param_set_float(id, param_name[], Float:val) */
+static Embryo_Cell
+_edje_embryo_fn_external_param_set_float(Embryo_Program *ep, Embryo_Cell *params)
+{
+   Edje *ed;
+   int part_id;
+   Edje_Real_Part *rp;
+   Edje_External_Param eep;
+   char *param_name;
+
+   CHKPARAM(3);
+   ed = embryo_program_data_get(ep);
+
+   part_id = params[1];
+   if (part_id < 0) return 0;
+   rp = ed->table_parts[part_id % ed->table_parts_size];
+
+   GETSTR(param_name, params[2]);
+   if (!param_name) return 0;
+   eep.name = param_name;
+   eep.type = EDJE_EXTERNAL_PARAM_TYPE_DOUBLE;
+   eep.d = EMBRYO_CELL_TO_FLOAT(params[3]);
+   return _edje_external_param_set(rp->swallowed_object, &eep);
+}
+
+/* external_param_get_strlen(id, param_name[]) */
+static Embryo_Cell
+_edje_embryo_fn_external_param_get_strlen(Embryo_Program *ep, Embryo_Cell *params)
+{
+   Edje *ed;
+   int part_id;
+   Edje_Real_Part *rp;
+   Edje_External_Param eep;
+   char *param_name;
+
+   CHKPARAM(2);
+   ed = embryo_program_data_get(ep);
+
+   part_id = params[1];
+   if (part_id < 0) return 0;
+   rp = ed->table_parts[part_id % ed->table_parts_size];
+
+   GETSTR(param_name, params[2]);
+   if (!param_name) return 0;
+   eep.name = param_name;
+   eep.type = EDJE_EXTERNAL_PARAM_TYPE_STRING;
+   eep.s = NULL;
+   _edje_external_param_get(rp->swallowed_object, &eep);
+   if (!eep.s) return 0;
+   return strlen(eep.s);
+}
+
+/* external_param_get_str(id, param_name[], val[], val_maxlen) */
+static Embryo_Cell
+_edje_embryo_fn_external_param_get_str(Embryo_Program *ep, Embryo_Cell *params)
+{
+   Edje *ed;
+   int part_id;
+   Edje_Real_Part *rp;
+   Edje_External_Param eep;
+   char *param_name;
+   size_t src_len, dst_len;
+
+   CHKPARAM(4);
+   dst_len = params[4];
+   if (dst_len < 1) goto error;
+
+   ed = embryo_program_data_get(ep);
+
+   part_id = params[1];
+   if (part_id < 0) goto error;
+   rp = ed->table_parts[part_id % ed->table_parts_size];
+
+   GETSTR(param_name, params[2]);
+   if (!param_name) return 0;
+   eep.name = param_name;
+   eep.type = EDJE_EXTERNAL_PARAM_TYPE_STRING;
+   eep.s = NULL;
+   _edje_external_param_get(rp->swallowed_object, &eep);
+   if (!eep.s) goto error;
+   src_len = strlen(eep.s);
+   if (src_len < dst_len)
+     {
+       SETSTR(eep.s, params[3]);
+     }
+   else
+     {
+       char *tmp = alloca(dst_len);
+       memcpy(tmp, eep.s, dst_len - 1);
+       tmp[dst_len] = '\0';
+       SETSTR(tmp, params[3]);
+     }
+   return 1;
+
+ error:
+   SETSTR("", params[3]);
+   return 0;
+}
+
+/* external_param_set_str(id, param_name[], val[]) */
+static Embryo_Cell
+_edje_embryo_fn_external_param_set_str(Embryo_Program *ep, Embryo_Cell *params)
+{
+   Edje *ed;
+   int part_id;
+   Edje_Real_Part *rp;
+   Edje_External_Param eep;
+   char *param_name, *val;
+
+   CHKPARAM(3);
+   ed = embryo_program_data_get(ep);
+
+   part_id = params[1];
+   if (part_id < 0) return 0;
+   rp = ed->table_parts[part_id % ed->table_parts_size];
+
+   GETSTR(param_name, params[2]);
+   if (!param_name) return 0;
+   eep.name = param_name;
+   eep.type = EDJE_EXTERNAL_PARAM_TYPE_STRING;
+   GETSTR(val, params[3]);
+   if (!val) return 0;
+   eep.s = val;
+   return _edje_external_param_set(rp->swallowed_object, &eep);
+}
+
+/* external_param_get_choice_len(id, param_name[]) */
+static Embryo_Cell
+_edje_embryo_fn_external_param_get_choice_len(Embryo_Program *ep, Embryo_Cell *params)
+{
+   Edje *ed;
+   int part_id;
+   Edje_Real_Part *rp;
+   Edje_External_Param eep;
+   char *param_name;
+
+   CHKPARAM(2);
+   ed = embryo_program_data_get(ep);
+
+   part_id = params[1];
+   if (part_id < 0) return 0;
+   rp = ed->table_parts[part_id % ed->table_parts_size];
+
+   GETSTR(param_name, params[2]);
+   if (!param_name) return 0;
+   eep.name = param_name;
+   eep.type = EDJE_EXTERNAL_PARAM_TYPE_CHOICE;
+   eep.s = NULL;
+   _edje_external_param_get(rp->swallowed_object, &eep);
+   if (!eep.s) return 0;
+   return strlen(eep.s);
+}
+
+/* external_param_get_choice(id, param_name[], val[], val_maxlen) */
+static Embryo_Cell
+_edje_embryo_fn_external_param_get_choice(Embryo_Program *ep, Embryo_Cell *params)
+{
+   Edje *ed;
+   int part_id;
+   Edje_Real_Part *rp;
+   Edje_External_Param eep;
+   char *param_name;
+   size_t src_len, dst_len;
+
+   CHKPARAM(4);
+   dst_len = params[4];
+   if (dst_len < 1) goto error;
+
+   ed = embryo_program_data_get(ep);
+
+   part_id = params[1];
+   if (part_id < 0) goto error;
+   rp = ed->table_parts[part_id % ed->table_parts_size];
+
+   GETSTR(param_name, params[2]);
+   if (!param_name) return 0;
+   eep.name = param_name;
+   eep.type = EDJE_EXTERNAL_PARAM_TYPE_CHOICE;
+   eep.s = NULL;
+   _edje_external_param_get(rp->swallowed_object, &eep);
+   if (!eep.s) goto error;
+   src_len = strlen(eep.s);
+   if (src_len < dst_len)
+     {
+       SETSTR(eep.s, params[3]);
+     }
+   else
+     {
+       char *tmp = alloca(dst_len);
+       memcpy(tmp, eep.s, dst_len - 1);
+       tmp[dst_len] = '\0';
+       SETSTR(tmp, params[3]);
+     }
+   return 1;
+
+ error:
+   SETSTR("", params[3]);
+   return 0;
+}
+
+/* external_param_set_choice(id, param_name[], val[]) */
+static Embryo_Cell
+_edje_embryo_fn_external_param_set_choice(Embryo_Program *ep, Embryo_Cell *params)
+{
+   Edje *ed;
+   int part_id;
+   Edje_Real_Part *rp;
+   Edje_External_Param eep;
+   char *param_name, *val;
+
+   CHKPARAM(3);
+   ed = embryo_program_data_get(ep);
+
+   part_id = params[1];
+   if (part_id < 0) return 0;
+   rp = ed->table_parts[part_id % ed->table_parts_size];
+
+   GETSTR(param_name, params[2]);
+   if (!param_name) return 0;
+   eep.name = param_name;
+   eep.type = EDJE_EXTERNAL_PARAM_TYPE_CHOICE;
+   GETSTR(val, params[3]);
+   if (!val) return 0;
+   eep.s = val;
+   return _edje_external_param_set(rp->swallowed_object, &eep);
+}
+
+/* external_param_get_bool(id, param_name[]) */
+static Embryo_Cell
+_edje_embryo_fn_external_param_get_bool(Embryo_Program *ep, Embryo_Cell *params)
+{
+   Edje *ed;
+   int part_id;
+   Edje_Real_Part *rp;
+   Edje_External_Param eep;
+   char *param_name;
+
+   CHKPARAM(2);
+   ed = embryo_program_data_get(ep);
+
+   part_id = params[1];
+   if (part_id < 0) return 0;
+   rp = ed->table_parts[part_id % ed->table_parts_size];
+
+   GETSTR(param_name, params[2]);
+   if (!param_name) return 0;
+   eep.name = param_name;
+   eep.type = EDJE_EXTERNAL_PARAM_TYPE_BOOL;
+   eep.i = 0;
+   _edje_external_param_get(rp->swallowed_object, &eep);
+   return eep.i;
+}
+
+/* external_param_set_bool(id, param_name[], val) */
+static Embryo_Cell
+_edje_embryo_fn_external_param_set_bool(Embryo_Program *ep, Embryo_Cell *params)
+{
+   Edje *ed;
+   int part_id;
+   Edje_Real_Part *rp;
+   Edje_External_Param eep;
+   char *param_name;
+
+   CHKPARAM(3);
+   ed = embryo_program_data_get(ep);
+
+   part_id = params[1];
+   if (part_id < 0) return 0;
+   rp = ed->table_parts[part_id % ed->table_parts_size];
+
+   GETSTR(param_name, params[2]);
+   if (!param_name) return 0;
+   eep.name = param_name;
+   eep.type = EDJE_EXTERNAL_PARAM_TYPE_BOOL;
+   eep.i = params[3];
+   return _edje_external_param_set(rp->swallowed_object, &eep);
+}
+
+void
+_edje_embryo_script_init(Edje *ed)
+{
+   Embryo_Program *ep;
+
+   if (!ed) return;
+   if (!ed->collection) return;
+   if (!ed->collection->script) return;
+   ep = ed->collection->script;
+   embryo_program_data_set(ep, ed);
+   /* first advertise all the edje "script" calls */
+   embryo_program_native_call_add(ep, "get_int", _edje_embryo_fn_get_int);
+   embryo_program_native_call_add(ep, "set_int", _edje_embryo_fn_set_int);
+   embryo_program_native_call_add(ep, "get_float", _edje_embryo_fn_get_float);
+   embryo_program_native_call_add(ep, "set_float", _edje_embryo_fn_set_float);
+   embryo_program_native_call_add(ep, "get_str", _edje_embryo_fn_get_str);
+   embryo_program_native_call_add(ep, "get_strlen", _edje_embryo_fn_get_strlen);
+   embryo_program_native_call_add(ep, "set_str", _edje_embryo_fn_set_str);
+   embryo_program_native_call_add(ep, "count", _edje_embryo_fn_count);
+   embryo_program_native_call_add(ep, "remove", _edje_embryo_fn_remove);
+   embryo_program_native_call_add(ep, "append_int", _edje_embryo_fn_append_int);
+   embryo_program_native_call_add(ep, "prepend_int", _edje_embryo_fn_prepend_int);
+   embryo_program_native_call_add(ep, "insert_int", _edje_embryo_fn_insert_int);
+   embryo_program_native_call_add(ep, "replace_int", _edje_embryo_fn_replace_int);
+   embryo_program_native_call_add(ep, "fetch_int", _edje_embryo_fn_fetch_int);
+   embryo_program_native_call_add(ep, "append_str", _edje_embryo_fn_append_str);
+   embryo_program_native_call_add(ep, "prepend_str", _edje_embryo_fn_prepend_str);
+   embryo_program_native_call_add(ep, "insert_str", _edje_embryo_fn_insert_str);
+   embryo_program_native_call_add(ep, "replace_str", _edje_embryo_fn_replace_str);
+   embryo_program_native_call_add(ep, "fetch_str", _edje_embryo_fn_fetch_str);
+   embryo_program_native_call_add(ep, "append_float", _edje_embryo_fn_append_float);
+   embryo_program_native_call_add(ep, "prepend_float", _edje_embryo_fn_prepend_float);
+   embryo_program_native_call_add(ep, "insert_float", _edje_embryo_fn_insert_float);
+   embryo_program_native_call_add(ep, "replace_float", _edje_embryo_fn_replace_float);
+   embryo_program_native_call_add(ep, "fetch_float", _edje_embryo_fn_fetch_float);
+
+   embryo_program_native_call_add(ep, "timer", _edje_embryo_fn_timer);
+   embryo_program_native_call_add(ep, "cancel_timer", _edje_embryo_fn_cancel_timer);
+
+   embryo_program_native_call_add(ep, "anim", _edje_embryo_fn_anim);
+   embryo_program_native_call_add(ep, "cancel_anim", _edje_embryo_fn_cancel_anim);
+
+   embryo_program_native_call_add(ep, "emit", _edje_embryo_fn_emit);
+   embryo_program_native_call_add(ep, "set_state", _edje_embryo_fn_set_state);
+   embryo_program_native_call_add(ep, "get_state", _edje_embryo_fn_get_state);
+   embryo_program_native_call_add(ep, "set_tween_state", _edje_embryo_fn_set_tween_state);
+   embryo_program_native_call_add(ep, "run_program", _edje_embryo_fn_run_program);
+   embryo_program_native_call_add(ep, "get_drag_dir", _edje_embryo_fn_get_drag_dir);
+   embryo_program_native_call_add(ep, "get_drag", _edje_embryo_fn_get_drag);
+   embryo_program_native_call_add(ep, "set_drag", _edje_embryo_fn_set_drag);
+   embryo_program_native_call_add(ep, "get_drag_size", _edje_embryo_fn_get_drag_size);
+   embryo_program_native_call_add(ep, "set_drag_size", _edje_embryo_fn_set_drag_size);
+   embryo_program_native_call_add(ep, "set_text", _edje_embryo_fn_set_text);
+   embryo_program_native_call_add(ep, "get_text", _edje_embryo_fn_get_text);
+   embryo_program_native_call_add(ep, "get_min_size", _edje_embryo_fn_get_min_size);
+   embryo_program_native_call_add(ep, "get_max_size", _edje_embryo_fn_get_max_size);
+   embryo_program_native_call_add(ep, "get_color_class", _edje_embryo_fn_get_color_class);
+   embryo_program_native_call_add(ep, "set_color_class", _edje_embryo_fn_set_color_class);
+   embryo_program_native_call_add(ep, "set_text_class", _edje_embryo_fn_set_text_class);
+   embryo_program_native_call_add(ep, "get_text_class", _edje_embryo_fn_get_text_class);
+   embryo_program_native_call_add(ep, "get_drag_step", _edje_embryo_fn_get_drag_step);
+   embryo_program_native_call_add(ep, "set_drag_step", _edje_embryo_fn_set_drag_step);
+   embryo_program_native_call_add(ep, "get_drag_page", _edje_embryo_fn_get_drag_page);
+   embryo_program_native_call_add(ep, "set_drag_page", _edje_embryo_fn_set_drag_page);
+   embryo_program_native_call_add(ep, "get_mouse", _edje_embryo_fn_get_mouse);
+   embryo_program_native_call_add(ep, "get_mouse_buttons", _edje_embryo_fn_get_mouse_buttons);
+   embryo_program_native_call_add(ep, "stop_program", _edje_embryo_fn_stop_program);
+   embryo_program_native_call_add(ep, "stop_programs_on", _edje_embryo_fn_stop_programs_on);
+   embryo_program_native_call_add(ep, "set_min_size", _edje_embryo_fn_set_min_size);
+   embryo_program_native_call_add(ep, "set_max_size", _edje_embryo_fn_set_max_size);
+
+   embryo_program_native_call_add(ep, "send_message", _edje_embryo_fn_send_message);
+   embryo_program_native_call_add(ep, "get_geometry", _edje_embryo_fn_get_geometry);
+   embryo_program_native_call_add(ep, "custom_state", _edje_embryo_fn_custom_state);
+   embryo_program_native_call_add(ep, "set_state_val", _edje_embryo_fn_set_state_val);
+   embryo_program_native_call_add(ep, "get_state_val", _edje_embryo_fn_get_state_val);
+
+   embryo_program_native_call_add(ep, "part_swallow", _edje_embryo_fn_part_swallow);
+
+   embryo_program_native_call_add(ep, "external_param_get_int", _edje_embryo_fn_external_param_get_int);
+   embryo_program_native_call_add(ep, "external_param_set_int", _edje_embryo_fn_external_param_set_int);
+   embryo_program_native_call_add(ep, "external_param_get_float", _edje_embryo_fn_external_param_get_float);
+   embryo_program_native_call_add(ep, "external_param_set_float", _edje_embryo_fn_external_param_set_float);
+   embryo_program_native_call_add(ep, "external_param_get_strlen", _edje_embryo_fn_external_param_get_strlen);
+   embryo_program_native_call_add(ep, "external_param_get_str", _edje_embryo_fn_external_param_get_str);
+   embryo_program_native_call_add(ep, "external_param_set_str", _edje_embryo_fn_external_param_set_str);
+   embryo_program_native_call_add(ep, "external_param_get_choice_len", _edje_embryo_fn_external_param_get_choice_len);
+   embryo_program_native_call_add(ep, "external_param_get_choice", _edje_embryo_fn_external_param_get_choice);
+   embryo_program_native_call_add(ep, "external_param_set_choice", _edje_embryo_fn_external_param_set_choice);
+   embryo_program_native_call_add(ep, "external_param_get_bool", _edje_embryo_fn_external_param_get_bool);
+   embryo_program_native_call_add(ep, "external_param_set_bool", _edje_embryo_fn_external_param_set_bool);
+
+//   embryo_program_vm_push(ed->collection->script);
+//   _edje_embryo_globals_init(ed);
+}
+
+void
+_edje_embryo_script_shutdown(Edje *ed)
+{
+   if (!ed) return;
+   if (!ed->collection) return;
+   if (!ed->collection->script) return;
+   if (embryo_program_recursion_get(ed->collection->script) > 0) return;
+//   embryo_program_vm_pop(ed->collection->script);
+   embryo_program_free(ed->collection->script);
+   ed->collection->script = NULL;
+}
+
+void
+_edje_embryo_script_reset(Edje *ed)
+{
+   if (!ed) return;
+   if (!ed->collection) return;
+   if (!ed->collection->script) return;
+   if (embryo_program_recursion_get(ed->collection->script) > 0) return;
+   embryo_program_vm_reset(ed->collection->script);
+   _edje_embryo_globals_init(ed);
+}
+
+/* this may change in future - thus "test_run" is its name */
+void
+_edje_embryo_test_run(Edje *ed, const char *fname, const char *sig, const char *src)
+{
+   Embryo_Function fn;
+
+   if (!ed) return;
+   if (!ed->collection) return;
+   if (!ed->collection->script) return;
+   embryo_program_vm_push(ed->collection->script);
+   _edje_embryo_globals_init(ed);
+
+   //   _edje_embryo_script_reset(ed);
+   fn = embryo_program_function_find(ed->collection->script, (char *)fname);
+   if (fn != EMBRYO_FUNCTION_NONE)
+     {
+       void *pdata;
+       int ret;
+
+       embryo_parameter_string_push(ed->collection->script, (char *)sig);
+       embryo_parameter_string_push(ed->collection->script, (char *)src);
+       pdata = embryo_program_data_get(ed->collection->script);
+       embryo_program_data_set(ed->collection->script, ed);
+       /* 5 million instructions is an arbitary number. on my p4-2.6 here */
+       /* IF embryo is ONLY runing embryo stuff and NO native calls thats */
+       /* about 0.016 seconds, and longer on slower cpu's. if a simple */
+       /* embryo script snippet hasn't managed to do its work in 5 MILLION */
+       /* embryo virtual machine instructions - something is wrong, or */
+       /* embryo is simply being mis-used. Embryo is meant to be minimal */
+       /* logic enhancment - not entire applications. this cycle count */
+       /* does NOT include time spent in native function calls, that the */
+       /* script may call to do the REAL work, so in terms of time this */
+       /* will likely end up being much longer than 0.016 seconds - more */
+       /* like 0.03 - 0.05 seconds or even more */
+       embryo_program_max_cycle_run_set(ed->collection->script, 5000000);
+       ret = embryo_program_run(ed->collection->script, fn);
+       if (ret == EMBRYO_PROGRAM_FAIL)
+         {
+            ERR("ERROR with embryo script.\n"
+                "ENTRY POINT: %s\n"
+                "ERROR:       %s",
+                fname,
+                embryo_error_string_get(embryo_program_error_get(ed->collection->script)));
+         }
+       else if (ret == EMBRYO_PROGRAM_TOOLONG)
+         {
+            ERR("ERROR with embryo script.\n"
+                "ENTRY POINT: %s\n"
+                "ERROR:       Script exceeded maximum allowed cycle count of %i",
+                fname,
+                embryo_program_max_cycle_run_get(ed->collection->script));
+         }
+       embryo_program_data_set(ed->collection->script, pdata);
+     }
+   embryo_program_vm_pop(ed->collection->script);
+}
+
+void
+_edje_embryo_globals_init(Edje *ed)
+{
+   int n, i;
+   Embryo_Program *ep;
+
+   ep = ed->collection->script;
+   n = embryo_program_variable_count_get(ep);
+   for (i = 0; i < n; i++)
+     {
+       Embryo_Cell cell, *cptr;
+
+       cell = embryo_program_variable_get(ep, i);
+       if (cell != EMBRYO_CELL_NONE)
+         {
+            cptr = embryo_data_address_get(ep, cell);
+            if (cptr) *cptr = EDJE_VAR_MAGIC_BASE + i;
+         }
+     }
+}
diff --git a/src/lib/edje_entry.c b/src/lib/edje_entry.c
new file mode 100644 (file)
index 0000000..2bcc1d0
--- /dev/null
@@ -0,0 +1,2762 @@
+/*
+ * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <string.h>
+
+#ifdef HAVE_ALLOCA_H
+# include <alloca.h>
+#elif defined __GNUC__
+# define alloca __builtin_alloca
+#elif defined _AIX
+# define alloca __alloca
+#elif defined _MSC_VER
+# include <malloc.h>
+# define alloca _alloca
+#else
+# include <stddef.h>
+# ifdef  __cplusplus
+extern "C"
+# endif
+void *alloca (size_t);
+#endif
+
+#include "edje_private.h"
+
+#ifdef HAVE_ECORE_IMF
+static int _edje_entry_imf_retrieve_surrounding_cb(void *data, Ecore_IMF_Context *ctx, char **text, int *cursor_pos);
+static int _edje_entry_imf_event_commit_cb(void *data, int type, void *event);
+static int _edje_entry_imf_event_changed_cb(void *data, int type, void *event);
+static int _edje_entry_imf_event_delete_surrounding_cb(void *data, int type, void *event);
+#endif
+
+typedef struct _Entry Entry;
+typedef struct _Sel Sel;
+typedef struct _Anchor Anchor;
+
+struct _Entry
+{
+   Edje_Real_Part *rp;
+   Evas_Coord cx, cy;
+   Evas_Object *cursor_bg;
+   Evas_Object *cursor_fg;
+   Evas_Textblock_Cursor *cursor;
+   Evas_Textblock_Cursor *sel_start, *sel_end;
+   Eina_List *sel;
+   Eina_List *anchors;
+   Eina_List *anchorlist;
+   Eina_List *itemlist;
+   char *selection;
+   Eina_Bool selecting : 1;
+   Eina_Bool have_selection : 1;
+   Eina_Bool select_allow : 1;
+   Eina_Bool select_mod_start : 1;
+   Eina_Bool select_mod_end : 1;
+   Eina_Bool had_sel : 1;
+
+#ifdef HAVE_ECORE_IMF   
+   int comp_len;
+   Eina_Bool have_composition : 1;
+   Ecore_IMF_Context *imf_context;
+
+   Ecore_Event_Handler *imf_ee_handler_commit;
+   Ecore_Event_Handler *imf_ee_handler_delete;
+   Ecore_Event_Handler *imf_ee_handler_changed;
+#endif   
+};
+
+struct _Sel
+{
+   Evas_Textblock_Rectangle rect;
+   Evas_Object *obj_fg, *obj_bg, *obj, *sobj;
+};
+
+struct _Anchor
+{
+   Entry *en;
+   char *name;
+   Evas_Textblock_Cursor *start, *end;
+   Eina_List *sel;
+   Eina_Bool item : 1;
+};
+
+#ifdef HAVE_ECORE_IMF   
+static void 
+_edje_entry_focus_in_cb(void *data, Evas_Object *o __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__)
+{
+   Edje_Real_Part *rp;
+   Entry *en;
+   
+   rp = data;
+   if (!rp || !rp->entry_data || !rp->edje || !rp->edje->obj) return;
+
+   en = rp->entry_data;
+   if (!en->imf_context) return;
+
+   if (evas_object_focus_get(rp->edje->obj))
+     {
+       ecore_imf_context_reset(en->imf_context);
+       ecore_imf_context_focus_in(en->imf_context);
+     }
+}
+
+static void
+_edje_entry_focus_out_cb(void *data, Evas_Object *o __UNUSED__, const char *emission __UNUSED__, const char *source __UNUSED__)
+{
+   Edje_Real_Part *rp;
+   Entry *en;
+
+   rp = data;
+   if (!rp || !rp->entry_data) return;
+
+   en = rp->entry_data;
+   if (!en->imf_context) return;
+
+   ecore_imf_context_reset(en->imf_context);
+   ecore_imf_context_cursor_position_set(en->imf_context, evas_textblock_cursor_pos_get(en->cursor));
+   ecore_imf_context_focus_out(en->imf_context);
+}
+#endif
+
+static void
+_edje_focus_in_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
+{
+   Edje *ed = data;
+#ifdef HAVE_ECORE_IMF   
+   Edje_Real_Part *rp;
+   Entry *en;
+#endif
+   
+   _edje_emit(ed, "focus,in", "");
+#ifdef HAVE_ECORE_IMF
+   rp = ed->focused_part;
+   if (rp == NULL) return;
+   
+   en = rp->entry_data;
+   if ((!en) || (rp->part->type != EDJE_PART_TYPE_TEXTBLOCK) ||
+       (rp->part->entry_mode < EDJE_ENTRY_EDIT_MODE_EDITABLE))
+     return;
+   if (en->imf_context)
+     {
+       ecore_imf_context_reset(en->imf_context);
+       ecore_imf_context_focus_in(en->imf_context);
+     }
+#endif
+}
+    
+static void
+_edje_focus_out_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
+{
+   Edje *ed = data;
+#ifdef HAVE_ECORE_IMF
+   Edje_Real_Part *rp = ed->focused_part;
+   Entry *en;
+#endif
+   
+   _edje_emit(ed, "focus,out", "");
+
+#ifdef HAVE_ECORE_IMF
+   if (!rp) return;
+   en = rp->entry_data;
+   if ((!en) || (rp->part->type != EDJE_PART_TYPE_TEXTBLOCK) ||
+       (rp->part->entry_mode < EDJE_ENTRY_EDIT_MODE_EDITABLE))
+     return;
+
+   if (en->imf_context)
+     {
+        ecore_imf_context_reset(en->imf_context);
+        ecore_imf_context_cursor_position_set(en->imf_context,
+                                              evas_textblock_cursor_pos_get(en->cursor));
+        ecore_imf_context_focus_out(en->imf_context);
+     }
+#endif
+}
+
+static void
+_curs_update_from_curs(Evas_Textblock_Cursor *c, Evas_Object *o __UNUSED__, Entry *en)
+{
+   Evas_Coord cx, cy, cw, ch;
+   if (c != en->cursor) return;
+   evas_textblock_cursor_char_geometry_get(c, &cx, &cy, &cw, &ch);
+   en->cx = cx + (cw / 2);
+   en->cy = cy + (ch / 2);
+}
+
+static void
+_curs_back(Evas_Textblock_Cursor *c, Evas_Object *o, Entry *en)
+{
+   if (!evas_textblock_cursor_char_prev(c))
+     {
+       if (evas_textblock_cursor_node_prev(c))
+         {
+            while (evas_textblock_cursor_node_format_get(c))
+              {
+                 if (evas_textblock_cursor_node_format_is_visible_get(c)) break;
+                 if (!evas_textblock_cursor_node_prev(c)) break;
+              }
+         }
+     }
+   _curs_update_from_curs(c, o, en);
+}
+
+static void
+_curs_next(Evas_Textblock_Cursor *c, Evas_Object *o, Entry *en)
+{
+   int ln, ln2, ok;
+   Eina_Bool eol;
+
+   ln = evas_textblock_cursor_line_geometry_get(c, NULL, NULL, NULL, NULL);
+   eol = evas_textblock_cursor_eol_get(c);
+   if (!evas_textblock_cursor_char_next(c))
+     {
+        if (!eol)
+          {
+             ln2 = evas_textblock_cursor_line_geometry_get(c, NULL, NULL, NULL, NULL);
+             if (ln2 != ln)
+               {
+                  evas_textblock_cursor_char_prev(c);
+                  evas_textblock_cursor_eol_set(c, 1);
+                  _curs_update_from_curs(c, o, en);
+                  return;
+               }
+             ok = evas_textblock_cursor_node_next(c);
+             if (!ok)
+               {
+                  evas_textblock_cursor_line_last(c);
+                  _curs_update_from_curs(c, o, en);
+                  return;
+               }
+            while (evas_textblock_cursor_node_format_get(c))
+              {
+                 if (evas_textblock_cursor_node_format_is_visible_get(c))
+                   break;
+                 if (!evas_textblock_cursor_node_next(c))
+                   break;
+              }
+             return;
+          }
+        evas_textblock_cursor_eol_set(c, 0);
+       if (evas_textblock_cursor_node_next(c))
+         {
+            while (evas_textblock_cursor_node_format_get(c))
+              {
+                 if (evas_textblock_cursor_node_format_is_visible_get(c))
+                   break;
+                 if (!evas_textblock_cursor_node_next(c))
+                   break;
+              }
+         }
+     }
+   else
+     {
+       int len, pos;
+       
+       len = evas_textblock_cursor_node_text_length_get(c);
+       pos = evas_textblock_cursor_pos_get(c);
+       if (pos == len)
+          {
+             evas_textblock_cursor_node_next(c);
+             if (!eol)
+               {
+                  ln2 = evas_textblock_cursor_line_geometry_get(c, NULL, NULL, NULL, NULL);
+                  if (ln2 != ln)
+                    {
+                       evas_textblock_cursor_node_prev(c);
+                       evas_textblock_cursor_line_last(c);
+                       _curs_update_from_curs(c, o, en);
+                       return;
+                    }
+               }
+          }
+        else
+          {
+             if (!eol)
+               {
+                  ln2 = evas_textblock_cursor_line_geometry_get(c, NULL, NULL, NULL, NULL);
+                  if (ln2 != ln)
+                    {
+                       evas_textblock_cursor_char_prev(c);
+                       evas_textblock_cursor_eol_set(c, 1);
+                       _curs_update_from_curs(c, o, en);
+                       return;
+                    }
+               }
+          }
+        evas_textblock_cursor_eol_set(c, 0);
+     }
+   _curs_update_from_curs(c, o, en);
+}
+
+static int
+_curs_line_last_get(Evas_Textblock_Cursor *c __UNUSED__, Evas_Object *o, Entry *en __UNUSED__)
+{
+   Evas_Textblock_Cursor *cc;
+   int ln;
+   
+   cc = evas_object_textblock_cursor_new(o);
+   evas_textblock_cursor_node_last(cc);
+   ln = evas_textblock_cursor_line_geometry_get(cc, NULL, NULL, NULL, NULL);
+   evas_textblock_cursor_free(cc);
+   return ln;
+}
+
+static void
+_curs_lin_start(Evas_Textblock_Cursor *c, Evas_Object *o, Entry *en)
+{
+   evas_textblock_cursor_line_first(c);
+   _curs_update_from_curs(c, o, en);
+}
+
+static void
+_curs_lin_end(Evas_Textblock_Cursor *c, Evas_Object *o, Entry *en)
+{
+   evas_textblock_cursor_line_last(c);
+//   if (!evas_textblock_cursor_node_format_get(c))
+//     _curs_next(c, o, en);
+   _curs_update_from_curs(c, o, en);
+}
+
+static void
+_curs_start(Evas_Textblock_Cursor *c, Evas_Object *o, Entry *en)
+{
+   evas_textblock_cursor_line_set(c, 0);
+   evas_textblock_cursor_line_first(c);
+   _curs_update_from_curs(c, o, en);
+}
+
+static void
+_curs_end(Evas_Textblock_Cursor *c, Evas_Object *o, Entry *en)
+{
+   evas_textblock_cursor_node_last(c);
+   _curs_lin_end(c, o, en);
+//   evas_textblock_cursor_line_set(c, _curs_line_last_get(c, o, en));
+//   _curs_lin_end(c, o, en);
+   _curs_update_from_curs(c, o, en);
+}
+
+static void
+_curs_jump_line(Evas_Textblock_Cursor *c, Evas_Object *o, Entry *en, int ln)
+{
+   Evas_Coord lx, ly, lw, lh;
+   int last = _curs_line_last_get(c, o, en);
+
+   if (ln < 0) ln = 0;
+   else
+     {
+       if (ln > last) ln = last;
+     }
+   if (!evas_object_textblock_line_number_geometry_get(o, ln, &lx, &ly, &lw, &lh))
+     return;
+   if (evas_textblock_cursor_char_coord_set(c, en->cx, ly + (lh / 2)))
+     return;
+   evas_textblock_cursor_line_set(c, ln);
+   if (en->cx < (lx + (lw / 2)))
+     {
+        if (ln == last) _curs_end(c, o, en);
+//        evas_textblock_cursor_line_first(c);
+        _curs_lin_start(c, o, en);
+     }
+   else
+     {
+        if (ln == last)
+          _curs_end(c, o, en);
+        else
+          _curs_lin_end(c, o, en);
+//        evas_textblock_cursor_line_last(c);
+     }
+}
+
+static void
+_curs_jump_line_by(Evas_Textblock_Cursor *c, Evas_Object *o, Entry *en, int by)
+{
+   int ln;
+   
+   ln = evas_textblock_cursor_line_geometry_get(c, NULL, NULL, NULL, NULL) + by;
+   _curs_jump_line(c, o, en, ln);
+}
+
+static void
+_curs_up(Evas_Textblock_Cursor *c, Evas_Object *o, Entry *en)
+{
+   _curs_jump_line_by(c, o, en, -1);
+}
+
+static void
+_curs_down(Evas_Textblock_Cursor *c, Evas_Object *o, Entry *en)
+{
+   _curs_jump_line_by(c, o, en, 1);
+}
+
+static void
+_sel_start(Evas_Textblock_Cursor *c, Evas_Object *o, Entry *en)
+{
+   if (en->sel_start) return;
+   en->sel_start = evas_object_textblock_cursor_new(o);
+   evas_textblock_cursor_copy(c, en->sel_start);
+   en->sel_end = evas_object_textblock_cursor_new(o);
+   evas_textblock_cursor_copy(c, en->sel_end);
+
+   en->have_selection = EINA_FALSE;
+   if (en->selection)
+     {
+       free(en->selection);
+       en->selection = NULL;
+     }
+}
+
+static void
+_sel_enable(Evas_Textblock_Cursor *c __UNUSED__, Evas_Object *o __UNUSED__, Entry *en)
+{
+   if (en->have_selection) return;
+   en->have_selection = EINA_TRUE;
+   if (en->selection)
+     {
+       free(en->selection);
+       en->selection = NULL;
+     }
+   _edje_emit(en->rp->edje, "selection,start", en->rp->part->name);
+}
+
+static void
+_sel_extend(Evas_Textblock_Cursor *c, Evas_Object *o, Entry *en)
+{
+   if (!en->sel_end) return;
+   _sel_enable(c, o, en);
+   if (!evas_textblock_cursor_compare(c, en->sel_end)) return;
+   evas_textblock_cursor_copy(c, en->sel_end);
+   if (en->selection)
+     {
+       free(en->selection);
+       en->selection = NULL;
+     }
+   _edje_emit(en->rp->edje, "selection,changed", en->rp->part->name);
+}
+
+static void
+_sel_preextend(Evas_Textblock_Cursor *c, Evas_Object *o, Entry *en)
+{
+   if (!en->sel_end) return;
+   _sel_enable(c, o, en);
+   if (!evas_textblock_cursor_compare(c, en->sel_start)) return;
+   evas_textblock_cursor_copy(c, en->sel_start);
+   if (en->selection)
+     {
+       free(en->selection);
+       en->selection = NULL;
+     }
+   _edje_emit(en->rp->edje, "selection,changed", en->rp->part->name);
+}
+
+static void
+_sel_clear(Evas_Textblock_Cursor *c __UNUSED__, Evas_Object *o __UNUSED__, Entry *en)
+{
+   en->had_sel = EINA_FALSE;
+   if (en->sel_start)
+     {
+       evas_textblock_cursor_free(en->sel_start);
+       evas_textblock_cursor_free(en->sel_end);
+       en->sel_start = NULL;
+       en->sel_end = NULL;
+     }
+   if (en->selection)
+     {
+       free(en->selection);
+       en->selection = NULL;
+     }
+   while (en->sel)
+     {
+       Sel *sel;
+       
+       sel = en->sel->data;
+        en->rp->edje->subobjs = eina_list_remove(en->rp->edje->subobjs, sel->obj_bg);
+        en->rp->edje->subobjs = eina_list_remove(en->rp->edje->subobjs, sel->obj_fg);
+       if (sel->obj_bg) evas_object_del(sel->obj_bg);
+       if (sel->obj_fg) evas_object_del(sel->obj_fg);
+       free(sel);
+       en->sel = eina_list_remove_list(en->sel, en->sel);
+     }
+   if (en->have_selection)
+     {
+        en->have_selection = EINA_FALSE;
+       _edje_emit(en->rp->edje, "selection,cleared", en->rp->part->name);
+     }
+}
+
+static void
+_sel_update(Evas_Textblock_Cursor *c __UNUSED__, Evas_Object *o, Entry *en)
+{
+   Eina_List *range = NULL, *l;
+   Sel *sel;
+   Evas_Coord x, y, w, h;
+   Evas_Object *smart, *clip;
+   
+   smart = evas_object_smart_parent_get(o);
+   clip = evas_object_clip_get(o);
+   if (en->sel_start)
+     range = evas_textblock_cursor_range_geometry_get(en->sel_start, en->sel_end);
+   else
+     return;
+   if (eina_list_count(range) != eina_list_count(en->sel))
+     {
+       while (en->sel)
+         {
+            sel = en->sel->data;
+             en->rp->edje->subobjs = eina_list_remove(en->rp->edje->subobjs, sel->obj_bg);
+             en->rp->edje->subobjs = eina_list_remove(en->rp->edje->subobjs, sel->obj_fg);
+            if (sel->obj_bg) evas_object_del(sel->obj_bg);
+            if (sel->obj_fg) evas_object_del(sel->obj_fg);
+            free(sel);
+            en->sel = eina_list_remove_list(en->sel, en->sel);
+         }
+       if (en->have_selection)
+         {
+            for (l = range; l; l = eina_list_next(l))
+              {
+                 Evas_Object *ob;
+                 
+                 sel = calloc(1, sizeof(Sel));
+                 en->sel = eina_list_append(en->sel, sel);
+                 ob = edje_object_add(en->rp->edje->evas);
+                 edje_object_file_set(ob, en->rp->edje->path, en->rp->part->source);
+                 evas_object_smart_member_add(ob, smart);
+                 evas_object_stack_below(ob, o);
+                 evas_object_clip_set(ob, clip);
+                 evas_object_pass_events_set(ob, 1);
+                 evas_object_show(ob);
+                 sel->obj_bg = ob;
+                  en->rp->edje->subobjs = eina_list_append(en->rp->edje->subobjs, sel->obj_bg);
+                  
+                 ob = edje_object_add(en->rp->edje->evas);
+                 edje_object_file_set(ob, en->rp->edje->path, en->rp->part->source2);
+                 evas_object_smart_member_add(ob, smart);
+                 evas_object_stack_above(ob, o);
+                 evas_object_clip_set(ob, clip);
+                 evas_object_pass_events_set(ob, 1);
+                 evas_object_show(ob);
+                 sel->obj_fg = ob;
+                  en->rp->edje->subobjs = eina_list_append(en->rp->edje->subobjs, sel->obj_fg);
+              }
+         }
+     }
+   x = y = w = h = -1;
+   evas_object_geometry_get(o, &x, &y, &w, &h);
+   if (en->have_selection)
+     {
+       EINA_LIST_FOREACH(en->sel, l, sel)
+         {
+            Evas_Textblock_Rectangle *r;
+            
+            r = range->data;
+            if (sel->obj_bg)
+              {
+                 evas_object_move(sel->obj_bg, x + r->x, y + r->y);
+                 evas_object_resize(sel->obj_bg, r->w, r->h);
+              }
+            if (sel->obj_fg)
+              {
+                 evas_object_move(sel->obj_fg, x + r->x, y + r->y);
+                 evas_object_resize(sel->obj_fg, r->w, r->h);
+              }
+            *(&(sel->rect)) = *r;
+            range = eina_list_remove_list(range, range);
+            free(r);
+         }
+     }
+   else
+     {
+       while (range)
+         {
+            free(range->data);
+            range = eina_list_remove_list(range, range);
+         }
+     }
+}
+
+static void
+_edje_anchor_mouse_down_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info)
+{
+   Anchor *an = data;
+   Evas_Event_Mouse_Down *ev = event_info;
+   Edje_Real_Part *rp = an->en->rp;
+   char *buf, *n;
+   int len;
+   int ignored;
+   Entry *en;
+   
+   en = rp->entry_data;
+   if ((rp->part->select_mode == EDJE_ENTRY_SELECTION_MODE_EXPLICIT) &&
+       (en->select_allow))
+     return;
+   ignored = rp->part->ignore_flags & ev->event_flags;
+   if ((!ev->event_flags) || (!ignored))
+     {
+       n = an->name;
+       if (!n) n = "";
+       len = 200 + strlen(n);
+       buf = alloca(len);
+        if (ev->flags & EVAS_BUTTON_TRIPLE_CLICK)
+          snprintf(buf, len, "anchor,mouse,down,%i,%s,triple", ev->button, an->name);
+        else if (ev->flags & EVAS_BUTTON_DOUBLE_CLICK)
+         snprintf(buf, len, "anchor,mouse,down,%i,%s,double", ev->button, an->name);
+       else
+         snprintf(buf, len, "anchor,mouse,down,%i,%s", ev->button, an->name);
+       _edje_emit(rp->edje, buf, rp->part->name);
+     }
+}
+
+static void
+_edje_anchor_mouse_up_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info)
+{
+   Anchor *an = data;
+   Evas_Event_Mouse_Up *ev = event_info;
+   Edje_Real_Part *rp = an->en->rp;
+   char *buf, *n;
+   int len;
+   int ignored;
+   Entry *en;
+   
+   en = rp->entry_data;
+   ignored = rp->part->ignore_flags & ev->event_flags;
+   if ((rp->part->select_mode == EDJE_ENTRY_SELECTION_MODE_EXPLICIT) &&
+       (en->select_allow))
+     return;
+   if ((!ev->event_flags) || (!ignored))
+     {
+       n = an->name;
+       if (!n) n = "";
+       len = 200 + strlen(n);
+       buf = alloca(len);
+       snprintf(buf, len, "anchor,mouse,up,%i,%s", ev->button, an->name);
+       _edje_emit(rp->edje, buf, rp->part->name);
+     }
+}
+
+static void
+_edje_anchor_mouse_move_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info)
+{
+   Anchor *an = data;
+   Evas_Event_Mouse_Move *ev = event_info;
+   Edje_Real_Part *rp = an->en->rp;
+   char *buf, *n;
+   int len;
+   int ignored;
+   Entry *en;
+   
+   en = rp->entry_data;
+   if ((rp->part->select_mode == EDJE_ENTRY_SELECTION_MODE_EXPLICIT) &&
+       (en->select_allow))
+     return;
+   ignored = rp->part->ignore_flags & ev->event_flags;
+   if ((!ev->event_flags) || (!ignored))
+     {
+       n = an->name;
+       if (!n) n = "";
+       len = 200 + strlen(n);
+       buf = alloca(len);
+       snprintf(buf, len, "anchor,mouse,move,%s", an->name);
+       _edje_emit(rp->edje, buf, rp->part->name);
+     }
+}
+
+static void
+_edje_anchor_mouse_in_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info)
+{
+   Anchor *an = data;
+   Evas_Event_Mouse_In *ev = event_info;
+   Edje_Real_Part *rp = an->en->rp;
+   char *buf, *n;
+   int len;
+   int ignored;
+
+   ignored = rp->part->ignore_flags & ev->event_flags;
+   if ((!ev->event_flags) || (!ignored))
+     {
+       n = an->name;
+       if (!n) n = "";
+       len = 200 + strlen(n);
+       buf = alloca(len);
+       snprintf(buf, len, "anchor,mouse,in,%s", an->name);
+       _edje_emit(rp->edje, buf, rp->part->name);
+     }
+}
+
+static void
+_edje_anchor_mouse_out_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info)
+{
+   Anchor *an = data;
+   Evas_Event_Mouse_Out *ev = event_info;
+   Edje_Real_Part *rp = an->en->rp;
+   char *buf, *n;
+   int len;
+   int ignored;
+
+   ignored = rp->part->ignore_flags & ev->event_flags;
+   if ((!ev->event_flags) || (!ignored))
+     {
+       n = an->name;
+       if (!n) n = "";
+       len = 200 + strlen(n);
+       buf = alloca(len);
+       snprintf(buf, len, "anchor,mouse,out,%s", an->name);
+       _edje_emit(rp->edje, buf, rp->part->name);
+     }
+}
+
+static void
+_anchors_update(Evas_Textblock_Cursor *c __UNUSED__, Evas_Object *o, Entry *en)
+{
+   Eina_List *l, *ll, *range;
+   Evas_Coord x, y, w, h;
+   Evas_Object *smart, *clip;
+   Sel *sel;
+   Anchor *an;
+
+   smart = evas_object_smart_parent_get(o);
+   clip = evas_object_clip_get(o);
+   x = y = w = h = -1;
+   evas_object_geometry_get(o, &x, &y, &w, &h);
+   EINA_LIST_FOREACH(en->anchors, l, an)
+     {
+        // for item anchors
+        if (an->item)
+          {
+             Evas_Object *ob;
+             
+            while (an->sel)
+              {
+                 sel = an->sel->data;
+                  en->rp->edje->subobjs = eina_list_remove(en->rp->edje->subobjs, sel->obj_bg);
+                  en->rp->edje->subobjs = eina_list_remove(en->rp->edje->subobjs, sel->obj_fg);
+                 if (sel->obj_bg) evas_object_del(sel->obj_bg);
+                 if (sel->obj_fg) evas_object_del(sel->obj_fg);
+                 if (sel->obj) evas_object_del(sel->obj);
+                 free(sel);
+                 an->sel = eina_list_remove_list(an->sel, an->sel);
+              }
+
+             sel = calloc(1, sizeof(Sel));
+             an->sel = eina_list_append(an->sel, sel);
+/*             
+             ob = evas_object_rectangle_add(en->rp->edje->evas);
+             evas_object_color_set(ob, 0, 0, 0, 0);
+             evas_object_smart_member_add(ob, smart);
+             evas_object_stack_above(ob, o);
+             evas_object_clip_set(ob, clip);
+             evas_object_pass_events_set(ob, 1);
+             evas_object_show(ob);
+ */
+             if (en->rp->edje->item_provider.func)
+               {
+                  ob = en->rp->edje->item_provider.func
+                    (en->rp->edje->item_provider.data, smart, 
+                     en->rp->part->name, an->name);
+                  evas_object_smart_member_add(ob, smart);
+                  evas_object_stack_above(ob, o);
+                  evas_object_clip_set(ob, clip);
+                  evas_object_pass_events_set(ob, 1);
+                  evas_object_show(ob);
+                  sel->obj = ob;
+               }
+          }
+        // for link anchors
+        else
+          {
+             range = evas_textblock_cursor_range_geometry_get(an->start, an->end);
+             if (eina_list_count(range) != eina_list_count(an->sel))
+               {
+                  while (an->sel)
+                    {
+                       sel = an->sel->data;
+                       en->rp->edje->subobjs = eina_list_remove(en->rp->edje->subobjs, sel->obj_bg);
+                       en->rp->edje->subobjs = eina_list_remove(en->rp->edje->subobjs, sel->obj_fg);
+                       if (sel->obj_bg) evas_object_del(sel->obj_bg);
+                       if (sel->obj_fg) evas_object_del(sel->obj_fg);
+                       if (sel->obj) evas_object_del(sel->obj);
+                       free(sel);
+                       an->sel = eina_list_remove_list(an->sel, an->sel);
+                    }
+                  for (ll = range; ll; ll = eina_list_next(ll))
+                    {
+                       Evas_Object *ob;
+                       
+                       sel = calloc(1, sizeof(Sel));
+                       an->sel = eina_list_append(an->sel, sel);
+                       ob = edje_object_add(en->rp->edje->evas);
+                       edje_object_file_set(ob, en->rp->edje->path, en->rp->part->source5);
+                       evas_object_smart_member_add(ob, smart);
+                       evas_object_stack_below(ob, o);
+                       evas_object_clip_set(ob, clip);
+                       evas_object_pass_events_set(ob, 1);
+                       evas_object_show(ob);
+                       sel->obj_bg = ob;
+                       en->rp->edje->subobjs = eina_list_append(en->rp->edje->subobjs, sel->obj_bg);
+                       
+                       ob = edje_object_add(en->rp->edje->evas);
+                       edje_object_file_set(ob, en->rp->edje->path, en->rp->part->source6);
+                       evas_object_smart_member_add(ob, smart);
+                       evas_object_stack_above(ob, o);
+                       evas_object_clip_set(ob, clip);
+                       evas_object_pass_events_set(ob, 1);
+                       evas_object_show(ob);
+                       sel->obj_fg = ob;
+                       en->rp->edje->subobjs = eina_list_append(en->rp->edje->subobjs, sel->obj_fg);
+                       
+                       ob = evas_object_rectangle_add(en->rp->edje->evas);
+                       evas_object_color_set(ob, 0, 0, 0, 0);
+                       evas_object_smart_member_add(ob, smart);
+                       evas_object_stack_above(ob, o);
+                       evas_object_clip_set(ob, clip);
+                       evas_object_repeat_events_set(ob, 1);
+                       evas_object_event_callback_add(ob, EVAS_CALLBACK_MOUSE_DOWN, _edje_anchor_mouse_down_cb, an);
+                       evas_object_event_callback_add(ob, EVAS_CALLBACK_MOUSE_UP, _edje_anchor_mouse_up_cb, an);
+                       evas_object_event_callback_add(ob, EVAS_CALLBACK_MOUSE_MOVE, _edje_anchor_mouse_move_cb, an);
+                       evas_object_event_callback_add(ob, EVAS_CALLBACK_MOUSE_IN, _edje_anchor_mouse_in_cb, an);
+                       evas_object_event_callback_add(ob, EVAS_CALLBACK_MOUSE_OUT, _edje_anchor_mouse_out_cb, an);
+                       evas_object_show(ob);
+                       sel->obj = ob;
+                    }
+               }
+          }
+        EINA_LIST_FOREACH(an->sel, ll, sel)
+          {
+             if (an->item)
+               {
+                  Evas_Coord cx, cy, cw, ch;
+                  
+                  evas_textblock_cursor_format_item_geometry_get(an->start, &cx, &cy, &cw, &ch);
+                  evas_object_move(sel->obj, x + cx, y + cy);
+                  evas_object_resize(sel->obj, cw, ch);
+               }
+             else
+               {
+                  Evas_Textblock_Rectangle *r;
+                  
+                  r = range->data;
+                  *(&(sel->rect)) = *r;
+                  if (sel->obj_bg)
+                    {
+                       evas_object_move(sel->obj_bg, x + r->x, y + r->y);
+                       evas_object_resize(sel->obj_bg, r->w, r->h);
+                    }
+                  if (sel->obj_fg)
+                    {
+                       evas_object_move(sel->obj_fg, x + r->x, y + r->y);
+                       evas_object_resize(sel->obj_fg, r->w, r->h);
+                    }
+                  if (sel->obj)
+                    {
+                       evas_object_move(sel->obj, x + r->x, y + r->y);
+                       evas_object_resize(sel->obj, r->w, r->h);
+                    }
+                  range = eina_list_remove_list(range, range);
+                  free(r);
+               }
+         }
+     }
+}
+
+static void
+_anchors_clear(Evas_Textblock_Cursor *c __UNUSED__, Evas_Object *o __UNUSED__, Entry *en)
+{
+   while (en->anchorlist)
+     {
+       free(en->anchorlist->data);
+       en->anchorlist = eina_list_remove_list(en->anchorlist, en->anchorlist);
+     }
+   while (en->itemlist)
+     {
+       free(en->itemlist->data);
+       en->itemlist = eina_list_remove_list(en->itemlist, en->itemlist);
+     }
+   while (en->anchors)
+     {
+       Anchor *an = en->anchors->data;
+       
+       evas_textblock_cursor_free(an->start);
+       evas_textblock_cursor_free(an->end);
+       while (an->sel)
+         {
+            Sel *sel = an->sel->data;
+             en->rp->edje->subobjs = eina_list_remove(en->rp->edje->subobjs, sel->obj_bg);
+             en->rp->edje->subobjs = eina_list_remove(en->rp->edje->subobjs, sel->obj_fg);
+            if (sel->obj_bg) evas_object_del(sel->obj_bg);
+            if (sel->obj_fg) evas_object_del(sel->obj_fg);
+            if (sel->obj) evas_object_del(sel->obj);
+            free(sel);
+            an->sel = eina_list_remove_list(an->sel, an->sel);
+         }
+        free(an->name);
+       free(an);
+       en->anchors = eina_list_remove_list(en->anchors, en->anchors);
+     }
+}
+
+static void
+_anchors_get(Evas_Textblock_Cursor *c, Evas_Object *o, Entry *en)
+{
+   Evas_Textblock_Cursor *c1;
+   Anchor *an = NULL;
+   int firsttext = 0;
+
+   _anchors_clear(c, o, en);
+   c1 = evas_object_textblock_cursor_new(o);
+   evas_textblock_cursor_node_first(c1);
+   do 
+     {
+       const char *s;
+       
+       s = evas_textblock_cursor_node_format_get(c1);
+       if (s)
+         {
+            if ((!strncmp(s, "+ a ", 4)) || (!strncmp(s, "+a ", 3)))
+              {
+                 an = calloc(1, sizeof(Anchor));
+                 if (an)
+                   {
+                      char *p;
+                      
+                      an->en = en;
+                      p = strstr(s, "href=");
+                      if (p)
+                        {
+                           an->name = strdup(p + 5);
+                        }
+                      en->anchors = eina_list_append(en->anchors, an);
+                      an->start = evas_object_textblock_cursor_new(o);
+                      an->end = evas_object_textblock_cursor_new(o);
+                      evas_textblock_cursor_copy(c1, an->start);
+                      evas_textblock_cursor_copy(c1, an->end);
+                   }
+              }
+            else if ((!strcmp(s, "- a")) || (!strcmp(s, "-a")))
+              {
+                 if (an)
+                   {
+                      if (!firsttext)
+                        {
+                           if (an->name) free(an->name);
+                           evas_textblock_cursor_free(an->start);
+                           evas_textblock_cursor_free(an->end);
+                           en->anchors = eina_list_remove(en->anchors, an);
+                           free(an);
+                        }
+                      firsttext = 0;
+                      an = NULL;
+                   }
+              }
+            else if (!strncmp(s, "+ item ", 7))
+              {
+                 an = calloc(1, sizeof(Anchor));
+                 if (an)
+                   {
+                      char *p;
+                      
+                      an->en = en;
+                       an->item = 1;
+                      p = strstr(s, "href=");
+                      if (p)
+                        {
+                           an->name = strdup(p + 5);
+                        }
+                      en->anchors = eina_list_append(en->anchors, an);
+                      an->start = evas_object_textblock_cursor_new(o);
+                      an->end = evas_object_textblock_cursor_new(o);
+                      evas_textblock_cursor_copy(c1, an->start);
+                      evas_textblock_cursor_copy(c1, an->end);
+                   }
+              }
+            else if ((!strcmp(s, "- item")) || (!strcmp(s, "-item")))
+              {
+                 if (an)
+                   {
+/*                       
+                      if (!firsttext)
+                        {
+                           if (an->name) free(an->name);
+                           evas_textblock_cursor_free(an->start);
+                           evas_textblock_cursor_free(an->end);
+                           en->anchors = eina_list_remove(en->anchors, an);
+                           free(an);
+                        }
+ */
+                      firsttext = 0;
+                      an = NULL;
+                   }
+              }
+         }
+       else
+         {
+            s = evas_textblock_cursor_node_text_get(c1);
+            if (an)
+              {
+                  if (!an->item)
+                    {
+                       if (!firsttext)
+                         {
+                            evas_textblock_cursor_copy(c1, an->start);
+                            firsttext = 1;
+                         }
+                    }
+                 evas_textblock_cursor_char_last(c1);
+                 evas_textblock_cursor_copy(c1, an->end);
+              }
+         }
+     } 
+   while (evas_textblock_cursor_node_next(c1));
+   evas_textblock_cursor_free(c1);
+}
+
+
+static void
+_range_del(Evas_Textblock_Cursor *c __UNUSED__, Evas_Object *o, Entry *en)
+{
+   Evas_Textblock_Cursor *c1;
+   
+   c1 = evas_object_textblock_cursor_new(o);
+   evas_textblock_cursor_node_last(c1);
+   if (!evas_textblock_cursor_compare(en->sel_end, c1))
+     evas_textblock_cursor_node_prev(en->sel_end);
+   if (!evas_textblock_cursor_compare(en->sel_start, c1))
+     evas_textblock_cursor_node_prev(en->sel_start);
+   evas_textblock_cursor_free(c1);
+   evas_textblock_cursor_range_delete(en->sel_start, en->sel_end);
+}
+
+static void
+_backspace(Evas_Textblock_Cursor *c, Evas_Object *o, Entry *en)
+{
+   Evas_Textblock_Cursor *c1, *c2;
+   int nodel = 0;
+   
+   c1 = evas_object_textblock_cursor_new(o);
+   if (!evas_textblock_cursor_char_prev(c))
+     {
+       if (!evas_textblock_cursor_node_prev(c))
+         nodel = 1;
+       else
+         {
+            evas_textblock_cursor_copy(c, c1);
+            if (evas_textblock_cursor_node_format_get(c) &&
+                (!evas_textblock_cursor_node_format_is_visible_get(c)))
+              _curs_back(c, o, en);
+         }
+     }
+   else
+     {
+        evas_textblock_cursor_copy(c, c1);
+     }
+   c2 = evas_object_textblock_cursor_new(o);
+   evas_textblock_cursor_copy(c, c2);
+   if (!nodel)
+     {
+        evas_textblock_cursor_range_delete(c1, c2);
+     }
+   evas_textblock_cursor_copy(c, c1);
+   _curs_back(c, o, en);
+   evas_textblock_cursor_copy(c, c2);
+   if ((!evas_textblock_cursor_char_next(c2)) &&
+       (!evas_textblock_cursor_node_next(c2)))
+     {
+        _curs_end(c, o, en);
+     }
+   else if (evas_textblock_cursor_compare(c, c1))
+     {
+        _curs_next(c, o, en);
+     }
+   
+   evas_textblock_cursor_free(c1);
+   evas_textblock_cursor_free(c2);
+}
+
+static void
+_delete(Evas_Textblock_Cursor *c, Evas_Object *o, Entry *en)
+{
+   Evas_Textblock_Cursor *c1, *c2;
+   
+   c1 = evas_object_textblock_cursor_new(o);
+   c2 = evas_object_textblock_cursor_new(o);
+   evas_textblock_cursor_copy(c, c1);
+   evas_textblock_cursor_copy(c, c2);
+   evas_textblock_cursor_char_last(c2);
+   if (evas_textblock_cursor_node_format_get(c1) &&
+       (!evas_textblock_cursor_node_format_is_visible_get(c1)))
+     {
+        // non-visible format-node
+        evas_textblock_cursor_copy(c1, c2);
+        while (evas_textblock_cursor_node_next(c2))
+          {
+             if ((!evas_textblock_cursor_node_format_get(c2)) ||
+                 (evas_textblock_cursor_node_format_is_visible_get(c2)))
+               {
+                  evas_textblock_cursor_node_prev(c2);
+                  break;
+               }
+          }
+     }
+   else
+     {
+        if (evas_textblock_cursor_node_format_is_visible_get(c1))
+          {
+             // visible format node
+             // do nothing just copy c to c1/c2 and range del
+          }
+        else
+          {
+             // if it's a text node
+             if (!evas_textblock_cursor_char_next(c1))
+               {
+                  if (evas_textblock_cursor_compare(c1, c2) > 0)
+                    _curs_next(c, o, en);
+               }
+          }
+        evas_textblock_cursor_copy(c, c1);
+        evas_textblock_cursor_copy(c, c2);
+     }
+   evas_textblock_cursor_range_delete(c1, c2);
+   evas_textblock_cursor_free(c1);
+   evas_textblock_cursor_free(c2);
+}
+
+static void
+_edje_key_down_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info)
+{
+   Edje *ed = data;
+   Evas_Event_Key_Down *ev = event_info;
+   Edje_Real_Part *rp = ed->focused_part;
+   Entry *en;
+   Eina_Bool control, alt, shift;
+   Eina_Bool multiline;
+   Eina_Bool cursor_changed;
+   Evas_Textblock_Cursor *tc;
+   if (!rp) return;
+   en = rp->entry_data;
+   if ((!en) || (rp->part->type != EDJE_PART_TYPE_TEXTBLOCK) ||
+       (rp->part->entry_mode < EDJE_ENTRY_EDIT_MODE_EDITABLE))
+     return;
+   if (!ev->key) return;
+
+#ifdef HAVE_ECORE_IMF
+#if 0 // FIXME -- keyboard activated IMF
+   if (en->imf_context)
+     {
+        Ecore_IMF_Event_Key_Down ecore_ev;
+        ecore_imf_evas_event_key_down_wrap(ev, &ecore_ev);
+        if (ecore_imf_context_filter_event(en->imf_context,
+                                           ECORE_IMF_EVENT_KEY_DOWN,
+                                           (Ecore_IMF_Event *)&ecore_ev))
+          return;
+     }
+#endif
+#endif
+   
+   tc = evas_object_textblock_cursor_new(rp->object);
+   evas_textblock_cursor_copy(en->cursor, tc);
+   
+   control = evas_key_modifier_is_set(ev->modifiers, "Control");
+   alt = evas_key_modifier_is_set(ev->modifiers, "Alt");
+   shift = evas_key_modifier_is_set(ev->modifiers, "Shift");
+   multiline = rp->part->multiline;
+   cursor_changed = EINA_FALSE;
+   if (!strcmp(ev->key, "Escape"))
+     {
+       // dead keys here. Escape for now (should emit these)
+        _edje_emit(ed, "entry,key,escape", rp->part->name);
+       ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
+     }
+   else if (!strcmp(ev->key, "Up"))
+     {
+       if (multiline)
+         {
+             if (en->select_allow)
+               {
+                  if (shift) _sel_start(en->cursor, rp->object, en);
+                  else _sel_clear(en->cursor, rp->object, en);
+               }
+            _curs_up(en->cursor, rp->object, en);
+             if (en->select_allow)
+               {
+                  if (shift) _sel_extend(en->cursor, rp->object, en);
+               }
+            ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
+         }
+        _edje_emit(ed, "entry,key,up", rp->part->name);
+     }
+   else if (!strcmp(ev->key, "Down"))
+     {
+       if (multiline)
+         {
+             if (en->select_allow)
+               {
+                  if (shift) _sel_start(en->cursor, rp->object, en);
+                  else _sel_clear(en->cursor, rp->object, en);
+               }
+            _curs_down(en->cursor, rp->object, en);
+             if (en->select_allow)
+               {
+                  if (shift) _sel_extend(en->cursor, rp->object, en);
+               }
+            ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
+         }
+        _edje_emit(ed, "entry,key,down", rp->part->name);
+     }
+   else if (!strcmp(ev->key, "Left"))
+     {
+        if (en->select_allow)
+          {
+             if (shift) _sel_start(en->cursor, rp->object, en);
+             else _sel_clear(en->cursor, rp->object, en);
+          }
+       _curs_back(en->cursor, rp->object, en);
+        if (en->select_allow)
+          {
+             if (shift) _sel_extend(en->cursor, rp->object, en);
+          }
+        _edje_emit(ed, "entry,key,left", rp->part->name);
+       ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
+     }
+   else if (!strcmp(ev->key, "Right"))
+     {
+        if (en->select_allow)
+          {
+             if (shift) _sel_start(en->cursor, rp->object, en);
+             else _sel_clear(en->cursor, rp->object, en);
+          }
+       _curs_next(en->cursor, rp->object, en);
+        if (en->select_allow)
+          {
+             if (shift) _sel_extend(en->cursor, rp->object, en);
+          }
+        _edje_emit(ed, "entry,key,right", rp->part->name);
+       ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
+     }
+   else if (!strcmp(ev->key, "BackSpace"))
+     {
+       if (control)
+         {
+            // del to start of previous word
+         }
+       else if ((alt) && (shift))
+         {
+            // undo last action
+         }
+       else
+         {
+            if (en->have_selection)
+              _range_del(en->cursor, rp->object, en);
+            else
+              _backspace(en->cursor, rp->object, en);
+         }
+       _sel_clear(en->cursor, rp->object, en);
+       _curs_update_from_curs(en->cursor, rp->object, en);
+       _anchors_get(en->cursor, rp->object, en);
+       _edje_emit(ed, "entry,changed", rp->part->name);
+        _edje_emit(ed, "entry,key,backspace", rp->part->name);
+       ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
+     }
+   else if (!strcmp(ev->key, "Delete"))
+     {
+       if (control)
+         {
+            // del to end of next word
+         }
+       else if (shift)
+         {
+            // cut
+         }
+       else
+         {     
+            if (en->have_selection)
+              _range_del(en->cursor, rp->object, en);
+            else
+               _delete(en->cursor, rp->object, en);
+         }
+       _sel_clear(en->cursor, rp->object, en);
+       _curs_update_from_curs(en->cursor, rp->object, en);
+       _anchors_get(en->cursor, rp->object, en);
+       _edje_emit(ed, "entry,changed", rp->part->name);
+        _edje_emit(ed, "entry,key,delete", rp->part->name);
+       ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
+     }
+   else if (!strcmp(ev->key, "Home"))
+     {
+        if (en->select_allow)
+          {
+             if (shift) _sel_start(en->cursor, rp->object, en);
+             else _sel_clear(en->cursor, rp->object, en);
+          }
+       if ((control) && (multiline))
+         _curs_start(en->cursor, rp->object, en);
+       else
+         _curs_lin_start(en->cursor, rp->object, en);
+        if (en->select_allow)
+          {
+             if (shift) _sel_extend(en->cursor, rp->object, en);
+          }
+        _edje_emit(ed, "entry,key,home", rp->part->name);
+       ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
+     }
+   else if (!strcmp(ev->key, "End"))
+     {
+        if (en->select_allow)
+          {
+             if (shift) _sel_start(en->cursor, rp->object, en);
+             else _sel_clear(en->cursor, rp->object, en);
+          }
+       if ((control) && (multiline))
+         _curs_end(en->cursor, rp->object, en);
+       else
+         _curs_lin_end(en->cursor, rp->object, en);
+        if (en->select_allow)
+          {
+             if (shift) _sel_extend(en->cursor, rp->object, en);
+          }
+        _edje_emit(ed, "entry,key,end", rp->part->name);
+       ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
+     }
+   else if ((control) && (!strcmp(ev->key, "v")))
+     {
+       _edje_emit(ed, "entry,paste,request", rp->part->name);
+       ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
+     }
+   else if ((control) && ((!strcmp(ev->key, "c") || (!strcmp(ev->key, "Insert")))))
+     {
+       // FIXME: copy - save selection
+       _edje_emit(ed, "entry,copy,notify", rp->part->name);
+       ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
+     }
+   else if ((control) && ((!strcmp(ev->key, "x") || (!strcmp(ev->key, "m")))))
+     {
+       // FIXME: cut - save selection, delete seletion
+       _curs_update_from_curs(en->cursor, rp->object, en);
+       _edje_emit(ed, "entry,cut,notify", rp->part->name);
+       ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
+     }
+   else if ((control) && (!strcmp(ev->key, "z")))
+     {
+       if (shift)
+         {
+            // redo
+         }
+       else
+         {
+            // undo
+         }
+       ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
+     }
+   else if ((control) && (!strcmp(ev->key, "y")))
+     {
+       // redo
+       ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
+     }
+   else if ((control) && (!strcmp(ev->key, "w")))
+     {
+       _sel_clear(en->cursor, rp->object, en);
+       // select current word
+       ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
+     }
+   else if (!strcmp(ev->key, "Tab"))
+     {
+       if (multiline)
+         {
+            if (shift)
+              {
+                 // remove a tab
+              }
+            else
+              {
+                 evas_textblock_cursor_format_prepend(en->cursor, "\t");
+                 _curs_update_from_curs(en->cursor, rp->object, en);
+                 _anchors_get(en->cursor, rp->object, en);
+                 _edje_emit(ed, "entry,changed", rp->part->name);
+              }
+            ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
+         }
+        _edje_emit(ed, "entry,key,tab", rp->part->name);
+     }
+   else if ((!strcmp(ev->key, "ISO_Left_Tab")) && (multiline))
+     { 
+       // remove a tab
+       ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
+     }
+   else if (!strcmp(ev->key, "Prior"))
+     {
+        if (en->select_allow)
+          {
+             if (shift) _sel_start(en->cursor, rp->object, en);
+             else _sel_clear(en->cursor, rp->object, en);
+          }
+       _curs_jump_line_by(en->cursor, rp->object, en, -10);
+        if (en->select_allow)
+          {
+             if (shift) _sel_extend(en->cursor, rp->object, en);
+          }
+        _edje_emit(ed, "entry,key,pgup", rp->part->name);
+       ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
+     }
+   else if (!strcmp(ev->key, "Next"))
+     {
+        if (en->select_allow)
+          {
+             if (shift) _sel_start(en->cursor, rp->object, en);
+             else _sel_clear(en->cursor, rp->object, en);
+          }
+       _curs_jump_line_by(en->cursor, rp->object, en, 10);
+        if (en->select_allow)
+          {
+             if (shift) _sel_extend(en->cursor, rp->object, en);
+          }
+        _edje_emit(ed, "entry,key,pgdn", rp->part->name);
+       ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
+     }
+   else if ((!strcmp(ev->key, "Return")) || (!strcmp(ev->key, "KP_Enter")))
+     {
+       if (multiline)
+         {
+             if (en->have_selection)
+               _range_del(en->cursor, rp->object, en);
+             _sel_clear(en->cursor, rp->object, en);
+            evas_textblock_cursor_format_prepend(en->cursor, "\n");
+            _curs_update_from_curs(en->cursor, rp->object, en);
+            _anchors_get(en->cursor, rp->object, en);
+            _edje_emit(ed, "entry,changed", rp->part->name);
+            _edje_emit(ed, "cursor,changed", rp->part->name);
+            cursor_changed = EINA_TRUE;
+            ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
+         }
+        _edje_emit(ed, "entry,key,enter", rp->part->name);
+     }
+   else
+     {
+       if (ev->string)
+         {
+            if (en->have_selection)
+               _range_del(en->cursor, rp->object, en);
+            _sel_clear(en->cursor, rp->object, en);
+            evas_textblock_cursor_text_prepend(en->cursor, ev->string);
+            _curs_update_from_curs(en->cursor, rp->object, en);
+            _anchors_get(en->cursor, rp->object, en);
+            _edje_emit(ed, "entry,changed", rp->part->name);
+            _edje_emit(ed, "cursor,changed", rp->part->name);
+            cursor_changed = EINA_TRUE;
+            ev->event_flags |= EVAS_EVENT_FLAG_ON_HOLD;
+         }
+     }
+   if ((evas_textblock_cursor_compare(tc, en->cursor)) && (!cursor_changed))
+     _edje_emit(ed, "cursor,changed", rp->part->name);
+
+#ifdef HAVE_ECORE_IMF
+   if (en->imf_context)
+     {
+       ecore_imf_context_reset(en->imf_context);
+       ecore_imf_context_cursor_position_set(en->imf_context,
+                                              evas_textblock_cursor_pos_get(en->cursor));
+     }
+#endif
+   
+   evas_textblock_cursor_free(tc);
+   _edje_entry_real_part_configure(rp);
+}
+
+static void
+_edje_key_up_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
+{
+   Edje *ed = data;
+   Edje_Real_Part *rp = ed->focused_part;
+   Entry *en;
+   if (!rp) return;
+   en = rp->entry_data;
+   if ((!en) || (rp->part->type != EDJE_PART_TYPE_TEXTBLOCK) ||
+       (rp->part->entry_mode < EDJE_ENTRY_EDIT_MODE_EDITABLE))
+     return;
+
+#ifdef HAVE_ECORE_IMF
+#if 0 // FIXME key activation imf
+   if (en->imf_context)
+     {
+        Ecore_IMF_Event_Key_Up ecore_ev;
+        ecore_imf_evas_event_key_down_wrap(ev, &ecore_ev);
+        if (ecore_imf_context_filter_event(en->imf_context,
+                                           ECORE_IMF_EVENT_KEY_UP,
+                                           (Ecore_IMF_Event *)&ecore_ev))
+          return;
+     }
+#endif
+#endif
+   
+}
+
+static void
+_edje_part_mouse_down_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info)
+{
+   Edje_Real_Part *rp = data;
+   Evas_Event_Mouse_Down *ev = event_info;
+   Entry *en;
+   Evas_Coord x, y, w, h;
+   Eina_Bool multiline;
+   Evas_Textblock_Cursor *tc;
+   Eina_Bool dosel = EINA_FALSE;
+   if (!rp) return;
+   if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return;
+   en = rp->entry_data;
+   if ((!en) || (rp->part->type != EDJE_PART_TYPE_TEXTBLOCK) ||
+       (rp->part->entry_mode < EDJE_ENTRY_EDIT_MODE_SELECTABLE))
+     return;
+   if (ev->button == 2)
+     {
+       _edje_emit(rp->edje, "entry,paste,request", rp->part->name);
+        return;
+     }
+   if (ev->button != 1) return;
+   en->select_mod_start = EINA_FALSE;
+   en->select_mod_end = EINA_FALSE;
+   if (rp->part->select_mode == EDJE_ENTRY_SELECTION_MODE_DEFAULT)
+     dosel = EINA_TRUE;
+   else if (rp->part->select_mode == EDJE_ENTRY_SELECTION_MODE_EXPLICIT)
+     {
+        if (en->select_allow) dosel = EINA_TRUE;
+     }
+   if (dosel)
+     {
+        // double click -> select word
+        // triple click -> select line
+     }
+   tc = evas_object_textblock_cursor_new(rp->object);
+   evas_textblock_cursor_copy(en->cursor, tc);
+   multiline = rp->part->multiline;
+   evas_object_geometry_get(rp->object, &x, &y, &w, &h);
+   en->cx = ev->canvas.x - x;
+   en->cy = ev->canvas.y - y;
+   if (!evas_textblock_cursor_char_coord_set(en->cursor, en->cx, en->cy))
+     {
+        Evas_Coord lx, ly, lw, lh;
+        int line;
+
+        line = evas_textblock_cursor_line_coord_set(en->cursor, en->cy);
+        if (line == -1)
+          _curs_end(en->cursor, rp->object, en);
+        else
+          {
+             int lnum;
+             
+             lnum = evas_textblock_cursor_line_geometry_get(en->cursor, &lx, &ly, &lw, &lh);
+             if (lnum < 0)
+               {
+                  _curs_lin_start(en->cursor, rp->object, en);
+               }
+             else
+               {
+                  if (en->cx <= lx)
+                    _curs_lin_start(en->cursor, rp->object, en);
+                  else
+                    _curs_lin_end(en->cursor, rp->object, en);
+               }
+          }
+        line = evas_textblock_cursor_line_geometry_get(en->cursor, &lx, &ly, &lw, &lh);
+     }
+   else
+     {
+        Evas_Coord lx, ly, lw, lh;
+        int line;
+        
+        line = evas_textblock_cursor_line_geometry_get(en->cursor, &lx, &ly, &lw, &lh);
+     }
+   if (dosel)
+     {
+        if ((en->have_selection) && 
+            (rp->part->select_mode == EDJE_ENTRY_SELECTION_MODE_EXPLICIT))
+          {
+             Eina_List *first, *last;
+             FLOAT_T sc;
+             
+             first = en->sel;
+             last = eina_list_last(en->sel);
+             if (first && last)
+               {
+                  Evas_Textblock_Rectangle *r1, *r2;
+                  Evas_Coord d, d1, d2;
+                  
+                  r1 = first->data;
+                  r2 = last->data;
+                  d = r1->x - en->cx;
+                  d1 = d * d;
+                  d = (r1->y + (r1->h / 2)) - en->cy;
+                  d1 += d * d;
+                  d = r2->x + r2->w - 1 - en->cx;
+                  d2 = d * d;
+                  d = (r2->y + (r2->h / 2)) - en->cy;
+                  d2 += d * d;
+                  sc = rp->edje->scale;
+                  if (sc == ZERO) sc = _edje_scale;
+                  d = (Evas_Coord)MUL(FROM_INT(20), sc); // FIXME: maxing number!
+                  d = d * d;
+                  if (d1 < d2)
+                    {
+                       if (d1 <= d)
+                         {
+                            en->select_mod_start = EINA_TRUE;
+                            en->selecting = EINA_TRUE;
+                         }
+                    }
+                  else
+                    {
+                       if (d2 <= d)
+                         {
+                            en->select_mod_end = EINA_TRUE;
+                            en->selecting = EINA_TRUE;
+                         }
+                    }
+               }
+          }
+        else
+          {
+             en->selecting = EINA_TRUE;
+             _sel_clear(en->cursor, rp->object, en);
+             if (en->select_allow)
+               {
+                  _sel_start(en->cursor, rp->object, en);
+               }
+          }
+     }
+   if (evas_textblock_cursor_compare(tc, en->cursor))
+     _edje_emit(rp->edje, "cursor,changed", rp->part->name);
+
+#ifdef HAVE_ECORE_IMF
+   if (en->imf_context)
+     {
+       ecore_imf_context_reset(en->imf_context);
+       ecore_imf_context_cursor_position_set(en->imf_context,
+                                              evas_textblock_cursor_pos_get(en->cursor));
+     }
+#endif
+   
+   evas_textblock_cursor_free(tc);
+   _edje_entry_real_part_configure(rp);
+}
+
+static void
+_edje_part_mouse_up_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info)
+{
+   Edje_Real_Part *rp = data;
+   Evas_Event_Mouse_Up *ev = event_info;
+   Entry *en;
+   Evas_Coord x, y, w, h;
+   Evas_Textblock_Cursor *tc;
+   if (ev->button != 1) return;
+   if (!rp) return;
+   if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) return;
+   en = rp->entry_data;
+   if ((!en) || (rp->part->type != EDJE_PART_TYPE_TEXTBLOCK) ||
+       (rp->part->entry_mode < EDJE_ENTRY_EDIT_MODE_SELECTABLE))
+     return;
+   tc = evas_object_textblock_cursor_new(rp->object);
+   evas_textblock_cursor_copy(en->cursor, tc);
+   evas_object_geometry_get(rp->object, &x, &y, &w, &h);
+   en->cx = ev->canvas.x - x;
+   en->cy = ev->canvas.y - y;
+   if (!evas_textblock_cursor_char_coord_set(en->cursor, en->cx, en->cy))
+     {
+        Evas_Coord lx, ly, lw, lh;
+        
+        evas_textblock_cursor_line_coord_set(en->cursor, en->cy);
+        evas_textblock_cursor_line_geometry_get(en->cursor, &lx, &ly, &lw, &lh);
+        if (en->cx <= lx)
+          _curs_lin_start(en->cursor, rp->object, en);
+        else
+          _curs_lin_end(en->cursor, rp->object, en);
+     }
+   if (rp->part->select_mode == EDJE_ENTRY_SELECTION_MODE_EXPLICIT)
+     {  
+        if (en->select_allow)
+          {
+             if (en->had_sel)
+               {
+                  if (en->select_mod_end)
+                    _sel_extend(en->cursor, rp->object, en);
+                  else if (en->select_mod_start)
+                    _sel_preextend(en->cursor, rp->object, en);
+               }
+             else
+               _sel_extend(en->cursor, rp->object, en);
+//             evas_textblock_cursor_copy(en->cursor, en->sel_end);
+          }
+     }
+   else
+     evas_textblock_cursor_copy(en->cursor, en->sel_end);
+   if (en->selecting)
+     {
+        if (en->have_selection)
+          en->had_sel = EINA_TRUE;
+        en->selecting = EINA_FALSE;
+     }
+   if (evas_textblock_cursor_compare(tc, en->cursor))
+     _edje_emit(rp->edje, "cursor,changed", rp->part->name);
+   evas_textblock_cursor_free(tc);
+
+#ifdef HAVE_ECORE_IMF
+   if (en->imf_context)
+     {
+       ecore_imf_context_reset(en->imf_context);
+       ecore_imf_context_cursor_position_set(en->imf_context,
+                                              evas_textblock_cursor_pos_get(en->cursor));
+     }
+#endif
+   
+   _edje_entry_real_part_configure(rp);
+}
+
+static void
+_edje_part_mouse_move_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info)
+{
+   Edje_Real_Part *rp = data;
+   Evas_Event_Mouse_Move *ev = event_info;
+   Entry *en;
+   Evas_Coord x, y, w, h;
+   Evas_Textblock_Cursor *tc;
+   if (!rp) return;
+   en = rp->entry_data;
+   if ((!en) || (rp->part->type != EDJE_PART_TYPE_TEXTBLOCK) ||
+       (rp->part->entry_mode < EDJE_ENTRY_EDIT_MODE_SELECTABLE))
+     return;
+   if (en->selecting)
+     {
+        tc = evas_object_textblock_cursor_new(rp->object);
+        evas_textblock_cursor_copy(en->cursor, tc);
+        evas_object_geometry_get(rp->object, &x, &y, &w, &h);
+        en->cx = ev->cur.canvas.x - x;
+        en->cy = ev->cur.canvas.y - y;
+        if (!evas_textblock_cursor_char_coord_set(en->cursor, en->cx, en->cy))
+          {
+             Evas_Coord lx, ly, lw, lh;
+             
+             evas_textblock_cursor_line_coord_set(en->cursor, en->cy);
+             evas_textblock_cursor_line_geometry_get(en->cursor, &lx, &ly, &lw, &lh);
+             if (en->cx <= lx)
+               _curs_lin_start(en->cursor, rp->object, en);
+             else
+               _curs_lin_end(en->cursor, rp->object, en);
+          }
+        if (rp->part->select_mode == EDJE_ENTRY_SELECTION_MODE_EXPLICIT)
+          {
+             if (en->select_allow)
+               {
+                  if (en->had_sel)
+                    {
+                       if (en->select_mod_end)
+                         _sel_extend(en->cursor, rp->object, en);
+                       else if (en->select_mod_start)
+                         _sel_preextend(en->cursor, rp->object, en);
+                    }
+                  else
+                    _sel_extend(en->cursor, rp->object, en);
+               }
+          }
+        else
+          {
+             _sel_extend(en->cursor, rp->object, en);
+          }
+        if (en->select_allow)
+          {
+             if (evas_textblock_cursor_compare(en->sel_start, en->sel_end) != 0)
+               _sel_enable(en->cursor, rp->object, en);
+             if (en->have_selection)
+               _sel_update(en->cursor, rp->object, en);
+          }
+        if (evas_textblock_cursor_compare(tc, en->cursor))
+          _edje_emit(rp->edje, "cursor,changed", rp->part->name);
+        evas_textblock_cursor_free(tc);
+
+#ifdef HAVE_ECORE_IMF
+        if (en->imf_context)
+          {
+             ecore_imf_context_reset(en->imf_context);
+             ecore_imf_context_cursor_position_set(en->imf_context,
+                                                   evas_textblock_cursor_pos_get(en->cursor));
+          }
+#endif
+        
+        _edje_entry_real_part_configure(rp);
+     }
+}
+
+static void
+_evas_focus_in_cb(void *data, Evas *e, void *event_info)
+{
+   Edje *ed = (Edje *)data;
+
+   if (evas_focus_get(e) == ed->obj) {
+      _edje_focus_in_cb(data, NULL, NULL, NULL);
+   }
+}
+
+static void
+_evas_focus_out_cb(void *data, Evas *e, void *event_info)
+{
+   Edje *ed = (Edje *)data;
+
+   if (evas_focus_get(e) == ed->obj) {
+      _edje_focus_out_cb(data, NULL, NULL, NULL);
+   }
+}
+
+/***************************************************************/
+void
+_edje_entry_init(Edje *ed)
+{
+   if (!ed->has_entries)
+     return;
+   if (ed->entries_inited)
+     return;
+   ed->entries_inited = EINA_TRUE;
+
+   evas_object_event_callback_add(ed->obj, EVAS_CALLBACK_FOCUS_IN, _edje_focus_in_cb, ed);
+   evas_object_event_callback_add(ed->obj, EVAS_CALLBACK_FOCUS_OUT, _edje_focus_out_cb, ed);
+   evas_object_event_callback_add(ed->obj, EVAS_CALLBACK_KEY_DOWN, _edje_key_down_cb, ed);
+   evas_object_event_callback_add(ed->obj, EVAS_CALLBACK_KEY_UP, _edje_key_up_cb, ed);
+   evas_event_callback_add(ed->evas, EVAS_CALLBACK_CANVAS_FOCUS_IN, _evas_focus_in_cb, ed);
+   evas_event_callback_add(ed->evas, EVAS_CALLBACK_CANVAS_FOCUS_OUT, _evas_focus_out_cb, ed);
+}
+
+void
+_edje_entry_shutdown(Edje *ed)
+{
+   if (!ed->has_entries)
+     return;
+   if (!ed->entries_inited)
+     return;
+   ed->entries_inited = EINA_FALSE;
+
+   evas_object_event_callback_del(ed->obj, EVAS_CALLBACK_FOCUS_IN, _edje_focus_in_cb);
+   evas_object_event_callback_del(ed->obj, EVAS_CALLBACK_FOCUS_OUT, _edje_focus_out_cb);
+   evas_object_event_callback_del(ed->obj, EVAS_CALLBACK_KEY_DOWN, _edje_key_down_cb);
+   evas_object_event_callback_del(ed->obj, EVAS_CALLBACK_KEY_UP, _edje_key_up_cb);
+   if (evas_event_callback_del_full(ed->evas, EVAS_CALLBACK_CANVAS_FOCUS_IN, _evas_focus_in_cb, ed) != ed)
+     ERR("could not unregister EVAS_CALLBACK_FOCUS_IN");
+   if (evas_event_callback_del_full(ed->evas, EVAS_CALLBACK_CANVAS_FOCUS_OUT, _evas_focus_out_cb, ed) != ed)
+     ERR("could not unregister EVAS_CALLBACK_FOCUS_OUT");
+}
+
+void
+_edje_entry_real_part_init(Edje_Real_Part *rp)
+{
+   Entry *en;
+#ifdef HAVE_ECORE_IMF
+   const char *ctx_id;
+   const Ecore_IMF_Context_Info *ctx_info;
+#endif
+   
+   en = calloc(1, sizeof(Entry));
+   if (!en) return;
+   rp->entry_data = en;
+   en->rp = rp;
+
+   evas_object_event_callback_add(rp->object, EVAS_CALLBACK_MOUSE_DOWN, _edje_part_mouse_down_cb, rp);
+   evas_object_event_callback_add(rp->object, EVAS_CALLBACK_MOUSE_UP, _edje_part_mouse_up_cb, rp);
+   evas_object_event_callback_add(rp->object, EVAS_CALLBACK_MOUSE_MOVE, _edje_part_mouse_move_cb, rp);
+   
+   if (rp->part->select_mode == EDJE_ENTRY_SELECTION_MODE_DEFAULT)
+     en->select_allow = 1;
+
+   if (rp->part->entry_mode == EDJE_ENTRY_EDIT_MODE_PASSWORD)
+     {
+        en->select_allow = 0;
+       if ((rp->chosen_description) &&
+           (rp->chosen_description->text.repch))
+         evas_object_textblock_replace_char_set(rp->object, rp->chosen_description->text.repch);
+       else
+         evas_object_textblock_replace_char_set(rp->object, "*");
+     }
+
+   en->cursor_bg = edje_object_add(rp->edje->evas);
+   edje_object_file_set(en->cursor_bg, rp->edje->path, rp->part->source3);
+   evas_object_smart_member_add(en->cursor_bg, rp->edje->obj);
+   evas_object_stack_below(en->cursor_bg, rp->object);
+   evas_object_clip_set(en->cursor_bg, evas_object_clip_get(rp->object));
+   evas_object_pass_events_set(en->cursor_bg, 1);
+   rp->edje->subobjs = eina_list_append(rp->edje->subobjs, en->cursor_bg);
+   
+   en->cursor_fg = edje_object_add(rp->edje->evas);
+   edje_object_file_set(en->cursor_fg, rp->edje->path, rp->part->source4);
+   evas_object_smart_member_add(en->cursor_fg, rp->edje->obj);
+   evas_object_stack_above(en->cursor_fg, rp->object);
+   evas_object_clip_set(en->cursor_fg, evas_object_clip_get(rp->object));
+   evas_object_pass_events_set(en->cursor_fg, 1);
+   rp->edje->subobjs = eina_list_append(rp->edje->subobjs, en->cursor_fg);
+   
+   if (rp->part->entry_mode >= EDJE_ENTRY_EDIT_MODE_EDITABLE)
+     {
+       evas_object_show(en->cursor_bg);
+       evas_object_show(en->cursor_fg);
+#ifdef HAVE_ECORE_IMF
+        ecore_imf_init();
+        
+        edje_object_signal_callback_add(rp->edje->obj, "focus,part,in", rp->part->name, _edje_entry_focus_in_cb, rp);
+        edje_object_signal_callback_add(rp->edje->obj, "focus,part,out", rp->part->name, _edje_entry_focus_out_cb, rp);
+        
+        ctx_id = ecore_imf_context_default_id_get();
+        if (ctx_id)
+          {
+             ctx_info = ecore_imf_context_info_by_id_get(ctx_id);
+             if (!ctx_info->canvas_type ||
+                 strcmp(ctx_info->canvas_type, "evas") == 0)
+               {
+                  en->imf_context = ecore_imf_context_add(ctx_id);
+               }
+             
+             else
+               {
+                  ctx_id = ecore_imf_context_default_id_by_canvas_type_get("evas");
+                  if (ctx_id)
+                    {
+                       en->imf_context = ecore_imf_context_add(ctx_id);
+                    }
+               }
+          }
+        else
+          en->imf_context = NULL;
+        
+        if (!en->imf_context) goto done;
+        
+        ecore_imf_context_client_window_set(en->imf_context, rp->object);
+        ecore_imf_context_client_canvas_set(en->imf_context, rp->edje->evas);
+        
+        ecore_imf_context_retrieve_surrounding_callback_set(en->imf_context, _edje_entry_imf_retrieve_surrounding_cb, rp);
+        en->imf_ee_handler_commit = ecore_event_handler_add(ECORE_IMF_EVENT_COMMIT, _edje_entry_imf_event_commit_cb, rp->edje);     
+        en->imf_ee_handler_delete = ecore_event_handler_add(ECORE_IMF_EVENT_DELETE_SURROUNDING, _edje_entry_imf_event_delete_surrounding_cb, rp);
+        en->imf_ee_handler_changed = ecore_event_handler_add(ECORE_IMF_EVENT_PREEDIT_CHANGED, _edje_entry_imf_event_changed_cb, rp->edje);
+        ecore_imf_context_input_mode_set(en->imf_context, 
+                                         rp->part->entry_mode == EDJE_ENTRY_EDIT_MODE_PASSWORD ? 
+                                         ECORE_IMF_INPUT_MODE_INVISIBLE : ECORE_IMF_INPUT_MODE_FULL);
+#endif
+     }
+   done:
+   en->cursor = (Evas_Textblock_Cursor *)evas_object_textblock_cursor_get(rp->object);
+}
+
+void
+_edje_entry_real_part_shutdown(Edje_Real_Part *rp)
+{
+   Entry *en = rp->entry_data;
+   if (!en) return;
+   rp->entry_data = NULL;
+   _sel_clear(en->cursor, rp->object, en);
+   _anchors_clear(en->cursor, rp->object, en);
+   rp->edje->subobjs = eina_list_remove(rp->edje->subobjs, en->cursor_bg);
+   rp->edje->subobjs = eina_list_remove(rp->edje->subobjs, en->cursor_fg);
+   evas_object_del(en->cursor_bg);
+   evas_object_del(en->cursor_fg);
+
+#ifdef HAVE_ECORE_IMF
+   if (rp->part->entry_mode >= EDJE_ENTRY_EDIT_MODE_EDITABLE)
+     {
+        if (en->imf_context)
+          {
+             if (en->imf_ee_handler_commit)
+               {
+                  ecore_event_handler_del(en->imf_ee_handler_commit);
+                  en->imf_ee_handler_commit = NULL;
+               }
+             
+             if (en->imf_ee_handler_delete)
+               {
+                  ecore_event_handler_del(en->imf_ee_handler_delete);
+                  en->imf_ee_handler_delete = NULL;
+               }
+             
+             if (en->imf_ee_handler_changed) 
+               {
+                  ecore_event_handler_del(en->imf_ee_handler_changed);
+                  en->imf_ee_handler_changed = NULL;
+               }
+             
+             ecore_imf_context_del(en->imf_context);
+             en->imf_context = NULL;
+          }
+        
+        edje_object_signal_callback_del(rp->edje->obj, "focus,part,in", rp->part->name, _edje_entry_focus_in_cb);
+        edje_object_signal_callback_del(rp->edje->obj, "focus,part,out", rp->part->name, _edje_entry_focus_out_cb);
+        ecore_imf_shutdown();
+     }
+#endif
+   
+   free(en);
+}
+
+void
+_edje_entry_real_part_configure(Edje_Real_Part *rp)
+{
+   Evas_Coord x, y, w, h, xx, yy, ww, hh;
+   Entry *en = rp->entry_data;
+   if (!en) return;
+
+   _sel_update(en->cursor, rp->object, en);
+   _anchors_update(en->cursor, rp->object, en);
+   x = y = w = h = -1;
+   xx = yy = ww = hh = -1;
+   evas_object_geometry_get(rp->object, &x, &y, &w, &h);
+   evas_textblock_cursor_char_geometry_get(en->cursor, &xx, &yy, &ww, &hh);
+   if (ww < 1) ww = 1;
+   if (hh < 1) ww = 1;
+   if (en->cursor_bg)
+     {
+       evas_object_move(en->cursor_bg, x + xx, y + yy);
+       evas_object_resize(en->cursor_bg, ww, hh);
+     }
+   if (en->cursor_fg)
+     {
+       evas_object_move(en->cursor_fg, x + xx, y + yy);
+       evas_object_resize(en->cursor_fg, ww, hh);
+     }
+}
+
+const char *
+_edje_entry_selection_get(Edje_Real_Part *rp)
+{
+   Entry *en = rp->entry_data;
+   if (!en) return NULL;
+   // get selection - convert to markup
+   if ((!en->selection) && (en->have_selection))
+     en->selection = evas_textblock_cursor_range_text_get
+     (en->sel_start, en->sel_end, EVAS_TEXTBLOCK_TEXT_MARKUP);
+   return en->selection;
+}
+
+const char *
+_edje_entry_text_get(Edje_Real_Part *rp)
+{
+   Entry *en = rp->entry_data;
+   if (!en) return NULL;
+   // get text - convert to markup
+   return evas_object_textblock_text_markup_get(rp->object);
+}
+
+void
+_edje_entry_text_markup_set(Edje_Real_Part *rp, const char *text)
+{
+   Entry *en = rp->entry_data;
+   if (!en) return;
+   // set text as markup
+   _sel_clear(en->cursor, rp->object, en);
+   evas_object_textblock_text_markup_set(rp->object, text); 
+/*   
+   evas_textblock_cursor_node_last(en->cursor);
+   if (!evas_textblock_cursor_node_format_get(en->cursor))
+     {
+       evas_textblock_cursor_format_append(en->cursor, "\n");
+     }
+   else if (!((!strcmp(evas_textblock_cursor_node_format_get(en->cursor), "\n")) ||
+             (!strcmp(evas_textblock_cursor_node_format_get(en->cursor), "\\n"))))
+     {
+       evas_textblock_cursor_format_append(en->cursor, "\n");
+     }
+ */
+   _anchors_get(en->cursor, rp->object, en);
+   _edje_emit(rp->edje, "entry,changed", rp->part->name);
+   _edje_entry_set_cursor_start(rp);
+}
+
+void
+_edje_entry_text_markup_insert(Edje_Real_Part *rp, const char *text)
+{
+   Entry *en = rp->entry_data;
+   if (!en) return;
+   // prepend markup @ cursor pos
+   if (en->have_selection)
+     _range_del(en->cursor, rp->object, en);
+   _sel_clear(en->cursor, rp->object, en);
+   evas_object_textblock_text_markup_prepend(en->cursor, text);
+   _curs_update_from_curs(en->cursor, rp->object, en);
+   _anchors_get(en->cursor, rp->object, en);
+   _edje_emit(rp->edje, "entry,changed", rp->part->name);
+   _edje_emit(rp->edje, "cursor,changed", rp->part->name);
+   
+#ifdef HAVE_ECORE_IMF
+   if (en->imf_context)
+     {
+       ecore_imf_context_reset(en->imf_context);
+       ecore_imf_context_cursor_position_set(en->imf_context,
+                                              evas_textblock_cursor_pos_get(en->cursor));
+     }
+#endif
+   _edje_entry_real_part_configure(rp);
+}
+
+void
+_edje_entry_set_cursor_start(Edje_Real_Part *rp)
+{
+   Entry *en = rp->entry_data;
+   if (!en) return;
+   _curs_start(en->cursor, rp->object, en);
+}
+
+void
+_edje_entry_set_cursor_end(Edje_Real_Part *rp)
+{
+   Entry *en = rp->entry_data;
+   if (!en) return;
+   _curs_end(en->cursor, rp->object, en);
+}
+
+void
+_edje_entry_select_none(Edje_Real_Part *rp)
+{
+   Entry *en = rp->entry_data;
+   if (!en) return;
+   _sel_clear(en->cursor, rp->object, en);
+}
+
+void
+_edje_entry_select_all(Edje_Real_Part *rp)
+{
+   Entry *en = rp->entry_data;
+   if (!en) return;
+   _sel_clear(en->cursor, rp->object, en);
+   _curs_start(en->cursor, rp->object, en);
+   _sel_enable(en->cursor, rp->object, en);
+   _sel_start(en->cursor, rp->object, en);
+   _curs_end(en->cursor, rp->object, en);
+   _sel_extend(en->cursor, rp->object, en);
+
+#ifdef HAVE_ECORE_IMF
+   if (en->imf_context)
+     {
+       ecore_imf_context_reset(en->imf_context);
+       ecore_imf_context_cursor_position_set(en->imf_context,
+                                              evas_textblock_cursor_pos_get(en->cursor));
+     }
+#endif
+   
+   _edje_entry_real_part_configure(rp);
+}
+
+void
+_edje_entry_select_begin(Edje_Real_Part *rp)
+{
+   Entry *en = rp->entry_data;
+   if (!en) return;
+   _sel_clear(en->cursor, rp->object, en);
+   _sel_enable(en->cursor, rp->object, en);
+   _sel_start(en->cursor, rp->object, en);
+   _sel_extend(en->cursor, rp->object, en);
+
+#ifdef HAVE_ECORE_IMF
+   if (en->imf_context)
+     {
+       ecore_imf_context_reset(en->imf_context);
+       ecore_imf_context_cursor_position_set(en->imf_context,
+                                              evas_textblock_cursor_pos_get(en->cursor));
+     }
+#endif
+   
+   _edje_entry_real_part_configure(rp);
+}
+
+void
+_edje_entry_select_extend(Edje_Real_Part *rp)
+{
+   Entry *en = rp->entry_data;
+   if (!en) return;
+   _sel_extend(en->cursor, rp->object, en);
+
+#ifdef HAVE_ECORE_IMF
+   if (en->imf_context)
+     {
+       ecore_imf_context_reset(en->imf_context);
+       ecore_imf_context_cursor_position_set(en->imf_context,
+                                              evas_textblock_cursor_pos_get(en->cursor));
+     }
+#endif
+   
+   _edje_entry_real_part_configure(rp);
+}
+
+const Eina_List *
+_edje_entry_anchor_geometry_get(Edje_Real_Part *rp, const char *anchor)
+{
+   Entry *en = rp->entry_data;
+   Eina_List *l;
+   Anchor *an;
+   
+   if (!en) return NULL;
+   EINA_LIST_FOREACH(en->anchors, l, an)
+     {
+        if (an->item) continue;
+       if (!strcmp(anchor, an->name))
+         return an->sel;
+     }
+   return NULL;
+}
+
+const Eina_List *
+_edje_entry_anchors_list(Edje_Real_Part *rp)
+{
+   Entry *en = rp->entry_data;
+   Eina_List *l, *anchors = NULL;
+   Anchor *an;
+
+   if (!en) return NULL;
+   if (!en->anchorlist)
+     {
+        EINA_LIST_FOREACH(en->anchors, l, an)
+         {
+            const char *n = an->name;
+             if (an->item) continue;
+            if (!n) n = "";
+            anchors = eina_list_append(anchors, strdup(n));
+         }
+       en->anchorlist = anchors;
+     }
+   return en->anchorlist;
+}
+
+Eina_Bool
+_edje_entry_item_geometry_get(Edje_Real_Part *rp, const char *item, Evas_Coord *cx, Evas_Coord *cy, Evas_Coord *cw, Evas_Coord *ch)
+{
+   Entry *en = rp->entry_data;
+   Eina_List *l;
+   Anchor *an;
+   
+   if (!en) return 0;
+   EINA_LIST_FOREACH(en->anchors, l, an)
+     {
+        if (an->item) continue;
+       if (!strcmp(item, an->name))
+          {
+             evas_textblock_cursor_format_item_geometry_get(an->start, cx, cy, cw, ch);
+             return 1;
+          }
+     }
+   return 0;
+}
+
+const Eina_List *
+_edje_entry_items_list(Edje_Real_Part *rp)
+{
+   Entry *en = rp->entry_data;
+   Eina_List *l, *items = NULL;
+   Anchor *an;
+
+   if (!en) return NULL;
+   if (!en->itemlist)
+     {
+        EINA_LIST_FOREACH(en->anchors, l, an)
+         {
+            const char *n = an->name;
+             if (an->item) continue;
+            if (!n) n = "";
+            items = eina_list_append(items, strdup(n));
+         }
+       en->itemlist = items;
+     }
+   return en->itemlist;
+}
+
+void
+_edje_entry_cursor_geometry_get(Edje_Real_Part *rp, Evas_Coord *cx, Evas_Coord *cy, Evas_Coord *cw, Evas_Coord *ch)
+{
+   Evas_Coord x, y, w, h, xx, yy, ww, hh;
+   Entry *en = rp->entry_data;
+   if (!en) return;
+
+   x = y = w = h = -1;
+   xx = yy = ww = hh = -1;
+   evas_object_geometry_get(rp->object, &x, &y, &w, &h);
+   evas_textblock_cursor_char_geometry_get(en->cursor, &xx, &yy, &ww, &hh);
+   if (ww < 1) ww = 1;
+   if (hh < 1) ww = 1;
+   if (cx) *cx = x + xx;
+   if (cy) *cy = y + yy;
+   if (cw) *cw = ww;
+   if (ch) *ch = hh;
+}
+
+void
+_edje_entry_select_allow_set(Edje_Real_Part *rp, Eina_Bool allow)
+{
+   Entry *en = rp->entry_data;
+   if (rp->part->select_mode == EDJE_ENTRY_SELECTION_MODE_DEFAULT)
+     return;
+   en->select_allow = allow;
+}
+
+Eina_Bool
+_edje_entry_select_allow_get(const Edje_Real_Part *rp)
+{
+  const Entry *en = rp->entry_data;
+  return en->select_allow;
+}
+
+void
+_edje_entry_select_abort(Edje_Real_Part *rp)
+{
+   Entry *en = rp->entry_data;
+   if (en->selecting)
+     {
+        en->selecting = EINA_FALSE;
+
+#ifdef HAVE_ECORE_IMF
+        if (en->imf_context)
+          {
+             ecore_imf_context_reset(en->imf_context);
+             ecore_imf_context_cursor_position_set(en->imf_context,
+                                                   evas_textblock_cursor_pos_get(en->cursor));
+          }
+#endif
+        
+        _edje_entry_real_part_configure(rp);
+     }
+}
+
+static Evas_Textblock_Cursor *
+_cursor_get(Edje_Real_Part *rp, Edje_Cursor cur)
+{
+   Entry *en = rp->entry_data;
+   if (!en) return NULL;
+   switch (cur)
+     {
+     case EDJE_CURSOR_MAIN:
+        return en->cursor;
+        break;
+     case EDJE_CURSOR_SELECTION_BEGIN:
+        return en->sel_start;
+        break;
+     case EDJE_CURSOR_SELECTION_END:
+        return en->sel_end;
+        break;
+     default:
+        break;
+     }
+   return NULL;
+}
+
+Eina_Bool
+_edje_entry_cursor_next(Edje_Real_Part *rp, Edje_Cursor cur)
+{
+   Entry *en = rp->entry_data;
+   Evas_Textblock_Cursor *c = _cursor_get(rp, cur);
+   if (!c) return 0;
+   if (!evas_textblock_cursor_char_next(c))
+     {
+        evas_textblock_cursor_eol_set(c, 0);
+       if (evas_textblock_cursor_node_next(c)) goto ok;
+        else return 0;
+     }
+   ok:
+   _curs_update_from_curs(c, rp->object, rp->entry_data);
+   _sel_update(c, rp->object, rp->entry_data);
+
+#ifdef HAVE_ECORE_IMF
+   if (en->imf_context)
+     {
+       ecore_imf_context_reset(en->imf_context);
+       ecore_imf_context_cursor_position_set(en->imf_context,
+                                              evas_textblock_cursor_pos_get(en->cursor));
+     }
+#endif
+   
+   _edje_emit(rp->edje, "cursor,changed", rp->part->name);
+   _edje_entry_real_part_configure(rp);
+   return 1;
+}
+
+Eina_Bool
+_edje_entry_cursor_prev(Edje_Real_Part *rp, Edje_Cursor cur)
+{
+   Entry *en = rp->entry_data;
+   Evas_Textblock_Cursor *c = _cursor_get(rp, cur);
+   if (!c) return 0;
+   if (!evas_textblock_cursor_char_prev(c))
+     {
+       if (evas_textblock_cursor_node_prev(c)) goto ok;
+        else return 0;
+     }
+   ok:
+   _curs_update_from_curs(c, rp->object, rp->entry_data);
+   _sel_update(c, rp->object, rp->entry_data);
+
+#ifdef HAVE_ECORE_IMF
+   if (en->imf_context)
+     {
+       ecore_imf_context_reset(en->imf_context);
+       ecore_imf_context_cursor_position_set(en->imf_context,
+                                              evas_textblock_cursor_pos_get(en->cursor));
+     }
+#endif
+   
+   _edje_emit(rp->edje, "cursor,changed", rp->part->name);
+   _edje_entry_real_part_configure(rp);
+   return 1;
+}
+
+Eina_Bool
+_edje_entry_cursor_up(Edje_Real_Part *rp, Edje_Cursor cur)
+{
+   Entry *en = rp->entry_data;
+   Evas_Textblock_Cursor *c = _cursor_get(rp, cur);
+   Evas_Coord lx, ly, lw, lh, cx, cy, cw, ch;
+   int ln;
+   if (!c) return 0;
+   ln = evas_textblock_cursor_line_geometry_get(c, NULL, NULL, NULL, NULL);
+   ln--;
+   if (ln < 0) return 0;
+   if (!evas_object_textblock_line_number_geometry_get(rp->object, ln, 
+                                                       &lx, &ly, &lw, &lh))
+     return 0;
+   evas_textblock_cursor_char_geometry_get(c, &cx, &cy, &cw, &ch);
+   if (!evas_textblock_cursor_char_coord_set(c, cx, ly + (lh / 2)))
+     {
+        if (cx < (lx +(lw / 2)))
+          evas_textblock_cursor_line_first(c);
+        else
+          evas_textblock_cursor_line_last(c);
+     }
+   _curs_update_from_curs(c, rp->object, rp->entry_data);
+   _sel_update(c, rp->object, rp->entry_data);
+
+#ifdef HAVE_ECORE_IMF
+   if (en->imf_context)
+     {
+       ecore_imf_context_reset(en->imf_context);
+       ecore_imf_context_cursor_position_set(en->imf_context,
+                                              evas_textblock_cursor_pos_get(en->cursor));
+     }
+#endif
+   
+   _edje_emit(rp->edje, "cursor,changed", rp->part->name);
+   _edje_entry_real_part_configure(rp);
+   return 1;
+}
+
+Eina_Bool
+_edje_entry_cursor_down(Edje_Real_Part *rp, Edje_Cursor cur)
+{
+   Entry *en = rp->entry_data;
+   Evas_Textblock_Cursor *c = _cursor_get(rp, cur);
+   Evas_Coord lx, ly, lw, lh, cx, cy, cw, ch;
+   int ln;
+   if (!c) return 0;
+   ln = evas_textblock_cursor_line_geometry_get(c, NULL, NULL, NULL, NULL);
+   ln++;
+   if (!evas_object_textblock_line_number_geometry_get(rp->object, ln, 
+                                                       &lx, &ly, &lw, &lh))
+     return 0;
+   evas_textblock_cursor_char_geometry_get(c, &cx, &cy, &cw, &ch);
+   if (!evas_textblock_cursor_char_coord_set(c, cx, ly + (lh / 2)))
+     {
+        if (cx < (lx +(lw / 2)))
+          evas_textblock_cursor_line_first(c);
+        else
+          evas_textblock_cursor_line_last(c);
+     }
+   _curs_update_from_curs(c, rp->object, rp->entry_data);
+   _sel_update(c, rp->object, rp->entry_data);
+
+#ifdef HAVE_ECORE_IMF
+   if (en->imf_context)
+     {
+       ecore_imf_context_reset(en->imf_context);
+       ecore_imf_context_cursor_position_set(en->imf_context,
+                                              evas_textblock_cursor_pos_get(en->cursor));
+     }
+#endif
+   
+   _edje_emit(rp->edje, "cursor,changed", rp->part->name);
+   _edje_entry_real_part_configure(rp);
+   return 1;
+}
+
+void
+_edje_entry_cursor_begin(Edje_Real_Part *rp, Edje_Cursor cur)
+{
+   Entry *en = rp->entry_data;
+   Evas_Textblock_Cursor *c = _cursor_get(rp, cur);
+   if (!c) return;
+   evas_textblock_cursor_node_first(c);
+   _curs_update_from_curs(c, rp->object, rp->entry_data);
+   _sel_update(c, rp->object, rp->entry_data);
+
+#ifdef HAVE_ECORE_IMF
+   if (en->imf_context)
+     {
+       ecore_imf_context_reset(en->imf_context);
+       ecore_imf_context_cursor_position_set(en->imf_context,
+                                              evas_textblock_cursor_pos_get(en->cursor));
+     }
+#endif
+   
+   _edje_emit(rp->edje, "cursor,changed", rp->part->name);
+   _edje_entry_real_part_configure(rp);
+}
+
+void
+_edje_entry_cursor_end(Edje_Real_Part *rp, Edje_Cursor cur)
+{
+   Entry *en = rp->entry_data;
+   Evas_Textblock_Cursor *c = _cursor_get(rp, cur);
+   if (!c) return;
+   evas_textblock_cursor_node_last(c);
+   _curs_update_from_curs(c, rp->object, rp->entry_data);
+   _sel_update(c, rp->object, rp->entry_data);
+
+#ifdef HAVE_ECORE_IMF
+   if (en->imf_context)
+     {
+       ecore_imf_context_reset(en->imf_context);
+       ecore_imf_context_cursor_position_set(en->imf_context,
+                                              evas_textblock_cursor_pos_get(en->cursor));
+     }
+#endif
+   
+   _edje_emit(rp->edje, "cursor,changed", rp->part->name);
+   _edje_entry_real_part_configure(rp);
+}
+
+void
+_edje_entry_cursor_copy(Edje_Real_Part *rp, Edje_Cursor cur, Edje_Cursor dst)
+{
+   Entry *en = rp->entry_data;
+   Evas_Textblock_Cursor *c = _cursor_get(rp, cur);
+   if (!c) return;
+   Evas_Textblock_Cursor *d = _cursor_get(rp, dst);
+   if (!d) return;
+   evas_textblock_cursor_copy(c, d);
+   _curs_update_from_curs(c, rp->object, rp->entry_data);
+   _sel_update(c, rp->object, rp->entry_data);
+
+#ifdef HAVE_ECORE_IMF
+   if (en->imf_context)
+     {
+       ecore_imf_context_reset(en->imf_context);
+       ecore_imf_context_cursor_position_set(en->imf_context,
+                                              evas_textblock_cursor_pos_get(en->cursor));
+     }
+#endif
+   
+   _edje_emit(rp->edje, "cursor,changed", rp->part->name);
+   _edje_entry_real_part_configure(rp);
+}
+
+void
+_edje_entry_cursor_line_begin(Edje_Real_Part *rp, Edje_Cursor cur)
+{
+   Entry *en = rp->entry_data;
+   Evas_Textblock_Cursor *c = _cursor_get(rp, cur);
+   if (!c) return;
+   evas_textblock_cursor_line_first(c);
+   _curs_update_from_curs(c, rp->object, rp->entry_data);
+   _sel_update(c, rp->object, rp->entry_data);
+
+#ifdef HAVE_ECORE_IMF
+   if (en->imf_context)
+     {
+       ecore_imf_context_reset(en->imf_context);
+       ecore_imf_context_cursor_position_set(en->imf_context,
+                                              evas_textblock_cursor_pos_get(en->cursor));
+     }
+#endif
+   
+   _edje_emit(rp->edje, "cursor,changed", rp->part->name);
+   _edje_entry_real_part_configure(rp);
+}
+
+void
+_edje_entry_cursor_line_end(Edje_Real_Part *rp, Edje_Cursor cur)
+{
+   Entry *en = rp->entry_data;
+   Evas_Textblock_Cursor *c = _cursor_get(rp, cur);
+   if (!c) return;
+   evas_textblock_cursor_line_last(c);
+   _curs_update_from_curs(c, rp->object, rp->entry_data);
+   _sel_update(c, rp->object, rp->entry_data);
+
+#ifdef HAVE_ECORE_IMF
+   if (en->imf_context)
+     {
+       ecore_imf_context_reset(en->imf_context);
+       ecore_imf_context_cursor_position_set(en->imf_context,
+                                              evas_textblock_cursor_pos_get(en->cursor));
+     }
+#endif
+   
+   _edje_emit(rp->edje, "cursor,changed", rp->part->name);
+   _edje_entry_real_part_configure(rp);
+}
+
+Eina_Bool
+_edje_entry_cursor_is_format_get(Edje_Real_Part *rp, Edje_Cursor cur)
+{
+   Evas_Textblock_Cursor *c = _cursor_get(rp, cur);
+   if (!c) return 0;
+   if (evas_textblock_cursor_node_format_get(c)) return 1;
+   return 0;
+}
+
+Eina_Bool
+_edje_entry_cursor_is_visible_format_get(Edje_Real_Part *rp, Edje_Cursor cur)
+{
+   Evas_Textblock_Cursor *c = _cursor_get(rp, cur);
+   if (!c) return 0;
+   return evas_textblock_cursor_node_format_is_visible_get(c);
+}
+
+const char *
+_edje_entry_cursor_content_get(Edje_Real_Part *rp, Edje_Cursor cur)
+{
+   Evas_Textblock_Cursor *c = _cursor_get(rp, cur);
+   const char *s;
+   static char buf[16];
+   int pos, pos2, ch;
+   if (!c) return NULL;
+   s = evas_textblock_cursor_node_format_get(c);
+   if (s) return s;
+   s = evas_textblock_cursor_node_text_get(c);
+   if (!s) return NULL;
+   pos = evas_textblock_cursor_pos_get(c);
+   pos2 = evas_string_char_next_get(s, pos, &ch);
+   strncpy(buf, s + pos, pos2 - pos);
+   buf[pos2 - pos] = 0;
+   return buf;
+}
+
+#ifdef HAVE_ECORE_IMF
+static int
+_edje_entry_imf_retrieve_surrounding_cb(void *data, Ecore_IMF_Context *ctx __UNUSED__, char **text, int *cursor_pos)
+{
+   Edje_Real_Part *rp = data;
+   Entry *en;
+   const char *str;
+   
+   if (!rp) return 0;
+   en = rp->entry_data;
+   if ((!en) || (rp->part->type != EDJE_PART_TYPE_TEXTBLOCK) ||
+       (rp->part->entry_mode < EDJE_ENTRY_EDIT_MODE_SELECTABLE))
+     return 0;
+   
+   if (text)
+     {
+        str = _edje_entry_text_get(rp);
+        *text = str ? strdup(str) : strdup("");
+     }
+   
+   if (cursor_pos)
+     {
+        *cursor_pos = evas_textblock_cursor_pos_get(en->cursor);
+     }
+   
+   return 1;
+}
+
+static int 
+_edje_entry_imf_event_commit_cb(void *data, int type __UNUSED__, void *event)
+{
+   Edje* ed = data;
+   Edje_Real_Part *rp = ed->focused_part;
+   Entry *en;
+   Ecore_IMF_Event_Commit *ev = event;
+   int i;
+   
+   if (!rp) return 1;
+   
+   en = rp->entry_data;
+   if ((!en) || (rp->part->type != EDJE_PART_TYPE_TEXTBLOCK) ||
+       (rp->part->entry_mode < EDJE_ENTRY_EDIT_MODE_SELECTABLE))
+     return 1;
+   
+   if (en->imf_context != ev->ctx) return 1;
+
+   if (en->have_composition)
+     {
+       for (i = 0; i < en->comp_len; i++)
+         _backspace(en->cursor, rp->object, en);
+       _sel_clear(en->cursor, rp->object, en);
+       en->have_composition = EINA_FALSE;
+     }
+
+   evas_textblock_cursor_text_prepend(en->cursor, ev->str);
+
+   _curs_update_from_curs(en->cursor, rp->object, en);
+   _anchors_get(en->cursor, rp->object, en);
+   _edje_emit(rp->edje, "entry,changed", rp->part->name);
+   _edje_emit(ed, "cursor,changed", rp->part->name);
+   
+   return 0;
+}
+
+static int 
+_edje_entry_imf_event_changed_cb(void *data, int type __UNUSED__, void *event)
+{
+   Edje* ed = data;
+   Edje_Real_Part *rp = ed->focused_part;
+   Entry *en;
+   int length;
+   Ecore_IMF_Event_Commit *ev = event;
+   int i;
+   char *preedit_string;
+
+   if (!rp) return 1;
+
+   en = rp->entry_data;
+   if ((!en) || (rp->part->type != EDJE_PART_TYPE_TEXTBLOCK) ||
+       (rp->part->entry_mode < EDJE_ENTRY_EDIT_MODE_SELECTABLE))
+     return 1;
+   
+   if (!en->imf_context) return 1;
+   
+   if (en->imf_context != ev->ctx) return 1;
+
+   ecore_imf_context_preedit_string_get(en->imf_context, &preedit_string, &length);
+
+   // FIXME : check the maximum length of evas_textblock
+   if ( 0 /* check the maximum length of evas_textblock */ )
+     return 1;
+   
+   if (en->have_composition)
+     {
+       // delete the composing characters
+       for (i = 0;i < en->comp_len; i++)
+         _backspace(en->cursor, rp->object, en);
+     }
+
+   en->comp_len = length;
+
+   _sel_clear(en->cursor, rp->object, en);
+   _sel_enable(en->cursor, rp->object, en);
+   _sel_start(en->cursor, rp->object, en);
+
+   en->have_composition = EINA_TRUE;
+
+   evas_object_textblock_text_markup_prepend (en->cursor, preedit_string);
+   
+   _sel_extend(en->cursor, rp->object, en);
+
+   _curs_update_from_curs(en->cursor, rp->object, en);
+   _anchors_get(en->cursor, rp->object, en);
+   _edje_emit(rp->edje, "entry,changed", rp->part->name);
+   _edje_emit(ed, "cursor,changed", rp->part->name);
+   
+   return 0;
+}
+
+static int
+_edje_entry_imf_event_delete_surrounding_cb(void *data, int type __UNUSED__, void *event)
+{
+   Edje *ed = data;
+   Edje_Real_Part *rp = ed->focused_part;
+   Entry *en;
+   Ecore_IMF_Event_Delete_Surrounding *ev = event;
+   
+   if (!rp) return 1;
+   en = rp->entry_data;
+   if ((!en) || (rp->part->type != EDJE_PART_TYPE_TEXTBLOCK) ||
+       (rp->part->entry_mode < EDJE_ENTRY_EDIT_MODE_SELECTABLE))
+     return 1;
+   
+   if (en->imf_context != ev->ctx) return 1;
+   
+   return 0;
+}
+#endif
diff --git a/src/lib/edje_external.c b/src/lib/edje_external.c
new file mode 100644 (file)
index 0000000..8a8eea5
--- /dev/null
@@ -0,0 +1,674 @@
+/*
+ * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
+ */
+
+#include "edje_private.h"
+
+static Eina_Hash *type_registry = NULL;
+static int init_count = 0;
+
+/**
+ * @brief Converts type identifier to string nicer representation.
+ *
+ * This may be used to debug or other informational purposes.
+ *
+ * @param type the identifier to convert.
+ * @return the string with the string representation, or @c "(unknown)".
+ */
+EAPI const char *
+edje_external_param_type_str(Edje_External_Param_Type type)
+{
+   switch (type)
+     {
+      case EDJE_EXTERNAL_PARAM_TYPE_INT:
+        return "INT";
+      case EDJE_EXTERNAL_PARAM_TYPE_DOUBLE:
+        return "DOUBLE";
+      case EDJE_EXTERNAL_PARAM_TYPE_STRING:
+        return "STRING";
+      case EDJE_EXTERNAL_PARAM_TYPE_BOOL:
+        return "BOOL";
+      case EDJE_EXTERNAL_PARAM_TYPE_CHOICE:
+        return "CHOICE";
+      default:
+        return "(unknown)";
+     }
+}
+
+/**
+ * @brief Get the object created by this external part.
+ *
+ * Parts of type external creates the part object using information
+ * provided by external plugins. It's somehow like "swallow"
+ * (edje_object_part_swallow()), but it's all set automatically.
+ *
+ * This function returns the part created by such external plugins and
+ * being currently managed by this Edje.
+ *
+ * @note Almost all swallow rules apply: you should not move, resize,
+ *       hide, show, set the color or clipper of such part. It's a bit
+ *       more restrictive as one must @b never delete this object!
+ *
+ * @param obj A valid Evas_Object handle
+ * @param part The part name
+ * @return The externally created object, or NULL if there is none or
+ *         part is not an external.
+ */
+EAPI Evas_Object *
+edje_object_part_external_object_get(const Evas_Object *obj, const char *part)
+{
+   Edje *ed;
+   Edje_Real_Part *rp;
+
+   ed = _edje_fetch(obj);
+   if ((!ed) || (!part)) return NULL;
+
+   /* Need to recalc before providing the object. */
+   _edje_recalc_do(ed);
+
+   rp = _edje_real_part_recursive_get(ed, (char *)part);
+   if (!rp)
+     {
+       ERR("no part '%s'", part);
+       return NULL;
+     }
+   if (rp->part->type != EDJE_PART_TYPE_EXTERNAL)
+     {
+       ERR("cannot get external object of a part '%s' that is not EXTERNAL",
+           rp->part->name);
+       return NULL;
+     }
+   return rp->swallowed_object;
+}
+
+/**
+ * @brief Set the parameter for the external part.
+ *
+ * Parts of type external may carry extra properties that have
+ * meanings defined by the external plugin. For instance, it may be a
+ * string that defines a button label and setting this property will
+ * change that label on the fly.
+ *
+ * @note external parts have parameters set when they change
+ *       states. Those parameters will never be changed by this
+ *       function. The interpretation of how state_set parameters and
+ *       param_set will interact is up to the external plugin.
+ *
+ * @note this function will not check if parameter value is valid
+ *       using #Edje_External_Param_Info minimum, maximum, valid
+ *       choices and others. However these should be checked by the
+ *       underlying implementation provided by the external
+ *       plugin. This is done for performance reasons.
+ *
+ * @param obj A valid Evas_Object handle
+ * @param part The part name
+ * @param param the parameter details, including its name, type and
+ *        actual value. This pointer should be valid, and the
+ *        parameter must exist in
+ *        #Edje_External_Type::parameters_info, with the exact type,
+ *        otherwise the operation will fail and @c EINA_FALSE will be
+ *        returned.
+ *
+ * @return @c EINA_TRUE if everything went fine, @c EINA_FALSE on errors.
+ */
+EAPI Eina_Bool
+edje_object_part_external_param_set(Evas_Object *obj, const char *part, const Edje_External_Param *param)
+{
+   Edje *ed;
+   Edje_Real_Part *rp;
+
+   if ((!param) || (!param->name)) return EINA_FALSE;
+
+   ed = _edje_fetch(obj);
+   if ((!ed) || (!part)) return EINA_FALSE;
+
+   rp = _edje_real_part_recursive_get(ed, (char *)part);
+   if (!rp)
+     {
+       ERR("no part '%s'", part);
+       return EINA_FALSE;
+     }
+
+   return _edje_external_param_set(rp->swallowed_object, param);
+}
+
+/**
+ * @brief Get the parameter for the external part.
+ *
+ * Parts of type external may carry extra properties that have
+ * meanings defined by the external plugin. For instance, it may be a
+ * string that defines a button label. This property can be modifed by
+ * state parameters, by explicit calls to
+ * edje_object_part_external_param_set() or getting the actual object
+ * with edje_object_part_external_object_get() and calling native
+ * functions.
+ *
+ * This function asks the external plugin what is the current value,
+ * independent on how it was set.
+ *
+ * @param obj A valid Evas_Object handle
+ * @param part The part name
+
+ * @param param the parameter details. It is used as both input and
+ *        output variable. This pointer should be valid, and the
+ *        parameter must exist in
+ *        #Edje_External_Type::parameters_info, with the exact type,
+ *        otherwise the operation will fail and @c EINA_FALSE will be
+ *        returned.
+ *
+ * @return @c EINA_TRUE if everything went fine and @p param members
+ *         are filled with information, @c EINA_FALSE on errors and @p
+ *         param member values are not set or valid.
+ */
+EAPI Eina_Bool
+edje_object_part_external_param_get(const Evas_Object *obj, const char *part, Edje_External_Param *param)
+{
+   Edje *ed;
+   Edje_Real_Part *rp;
+
+   if ((!param) || (!param->name)) return EINA_FALSE;
+
+   ed = _edje_fetch(obj);
+   if ((!ed) || (!part)) return EINA_FALSE;
+
+   rp = _edje_real_part_recursive_get(ed, (char *)part);
+   if (!rp)
+     {
+       ERR("no part '%s'", part);
+       return EINA_FALSE;
+     }
+
+   return _edje_external_param_get(rp->swallowed_object, param);
+}
+
+/**
+ * Facility to query the type of the given parameter of the given part.
+ *
+ * @param obj A valid Evas_Object handle
+ * @param part The part name
+ * @param param the parameter name to use.
+ *
+ * @return @c EDJE_EXTERNAL_PARAM_TYPE_MAX on errors, or another value
+ *         from #Edje_External_Param_Type on success.
+ */
+EAPI Edje_External_Param_Type
+edje_object_part_external_param_type_get(const Evas_Object *obj, const char *part, const char *param)
+{
+   Edje *ed;
+   Edje_Real_Part *rp;
+   Edje_External_Type *type;
+   Edje_External_Param_Info *info;
+
+   ed = _edje_fetch(obj);
+   if ((!ed) || (!part)) return EDJE_EXTERNAL_PARAM_TYPE_MAX;
+
+   rp = _edje_real_part_recursive_get(ed, (char *)part);
+   if (!rp)
+     {
+       ERR("no part '%s'", part);
+       return EDJE_EXTERNAL_PARAM_TYPE_MAX;
+     }
+   type = evas_object_data_get(rp->swallowed_object, "Edje_External_Type");
+   if (!type)
+     {
+       ERR("no external type for object %p", obj);
+       return EDJE_EXTERNAL_PARAM_TYPE_MAX;
+     }
+   if (!type->parameters_info)
+     {
+       ERR("no parameters information for external type '%s'",
+           type->module_name);
+       return EDJE_EXTERNAL_PARAM_TYPE_MAX;
+     }
+   for (info = type->parameters_info; info->name != NULL; info++)
+     if (strcmp(info->name, param) == 0)
+       return info->type;
+
+   ERR("no parameter '%s' external type '%s'", param, type->module_name);
+   return EDJE_EXTERNAL_PARAM_TYPE_MAX;
+}
+
+
+/**
+ * Register given type name to return the given information.
+ *
+ * @param type_name name to register and be known by edje's "source:"
+ *        parameter of "type: EXTERNAL" parts.
+ * @param type_info meta-information describing how to interact with it.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE on failure (like
+ *         type already registered).
+ *
+ * @see edje_external_type_array_register()
+ */
+EAPI Eina_Bool
+edje_external_type_register(const char *type_name, const Edje_External_Type *type_info)
+{
+   if (!type_name)
+     return EINA_FALSE;
+   if (!type_info)
+     return EINA_FALSE;
+
+   if (type_info->abi_version != EDJE_EXTERNAL_TYPE_ABI_VERSION)
+     {
+       ERR("external type '%s' (%p) has incorrect abi version. "
+              "got %#x where %#x was expected.",
+              type_name, type_info,
+              type_info->abi_version, EDJE_EXTERNAL_TYPE_ABI_VERSION);
+       return EINA_FALSE;
+     }
+
+   if (eina_hash_find(type_registry, type_name))
+     {
+       ERR("External type '%s' already registered", type_name);
+       return EINA_FALSE;
+     }
+   return eina_hash_add(type_registry, type_name, type_info);
+}
+
+/**
+ * Unregister given type name previously registered.
+ *
+ * @param type_name name to unregister. It should be registered with
+ *        edje_external_type_register() before.
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE on failure (like
+ *         type_name did not exist).
+ *
+ * @see edje_external_type_array_unregister()
+ */
+EAPI Eina_Bool
+edje_external_type_unregister(const char *type_name)
+{
+   if (!type_name)
+     return EINA_FALSE;
+   return eina_hash_del_by_key(type_registry, type_name);
+}
+
+/**
+ * Register a batch of types and their information.
+ *
+ * This is the recommended function to add information as it's faster
+ * than the single version edje_external_type_register().
+ *
+ * @note the given array is not modified, but the type name strings
+ *       are @b not duplicated! That is, all type names must be @b
+ *       live until they are unregistered! This was choosen to save
+ *       some memory and most people will just define the array as a
+ *       global static const type anyway.
+ *
+ * @param arrray @c NULL terminated array with type name and
+ *        information. Note that type name or information are not
+ *        modified by are @b referenced, so they must keep alive after
+ *        this function returns!
+ *
+ * @return @c EINA_TRUE on success, @c EINA_FALSE on failure (like
+ *         type already registered).
+ *
+ * @see edje_external_type_register()
+ */
+EAPI void
+edje_external_type_array_register(const Edje_External_Type_Info *array)
+{
+   const Edje_External_Type_Info *itr;
+
+   if (!array)
+     return;
+
+   for (itr = array; itr->name; itr++)
+     {
+       if (itr->info->abi_version != EDJE_EXTERNAL_TYPE_ABI_VERSION)
+         {
+            ERR("external type '%s' (%p) has incorrect abi "
+                   "version. got %#x where %#x was expected.",
+                   itr->name, itr->info,
+                   itr->info->abi_version, EDJE_EXTERNAL_TYPE_ABI_VERSION);
+            continue;
+         }
+
+       eina_hash_direct_add(type_registry, itr->name, itr->info);
+     }
+}
+
+/**
+ * Unregister a batch of given external type previously registered.
+ *
+ * @param array @c NULL terminated array, should be the same as the
+ *        one used to register with edje_external_type_array_register()
+ *
+ * @see edje_external_type_unregister()
+ */
+EAPI void
+edje_external_type_array_unregister(const Edje_External_Type_Info *array)
+{
+   const Edje_External_Type_Info *itr;
+
+   if (!array)
+     return;
+
+   for (itr = array; itr->name; itr++)
+     eina_hash_del(type_registry, itr->name, itr->info);
+}
+
+/**
+ * Return the current ABI version for Edje_External_Type structure.
+ *
+ * Always check this number before accessing Edje_External_Type in
+ * your own software. If the number is not the same, your software may
+ * access invalid memory and crash, or just get garbage values.
+ *
+ * @warning @b NEVER, EVER define your own Edje_External_Type using the
+ *          return of this function as it will change as Edje library
+ *          (libedje.so) changes, but your type definition will
+ *          not. Instead, use #EDJE_EXTERNAL_TYPE_ABI_VERSION.
+ *
+ * Summary:
+ *   - use edje_external_type_abi_version_get() to check.
+ *   - use #EDJE_EXTERNAL_TYPE_ABI_VERSION to define/declare.
+ *
+ * @return version this edje library was compiled.
+ */
+EAPI unsigned int
+edje_external_type_abi_version_get(void)
+{
+   return EDJE_EXTERNAL_TYPE_ABI_VERSION;
+}
+
+EAPI Eina_Iterator *
+edje_external_iterator_get(void)
+{
+   return eina_hash_iterator_tuple_new(type_registry);
+}
+
+EAPI Edje_External_Param *
+edje_external_param_find(const Eina_List *params, const char *key)
+{
+   const Eina_List *l;
+   Edje_External_Param *param;
+
+   EINA_LIST_FOREACH(params, l, param)
+      if (!strcmp(param->name, key)) return param;
+
+   return NULL;
+}
+
+EAPI Eina_Bool
+edje_external_param_int_get(const Eina_List *params, const char *key, int *ret)
+{
+   Edje_External_Param *param;
+
+   if (!params) return EINA_FALSE;
+   param = edje_external_param_find(params, key);
+
+   if (param && param->type == EDJE_EXTERNAL_PARAM_TYPE_INT && ret)
+     {
+       *ret = param->i;
+       return EINA_TRUE;
+     }
+
+   return EINA_FALSE;
+}
+
+EAPI Eina_Bool
+edje_external_param_double_get(const Eina_List *params, const char *key, double *ret)
+{
+   Edje_External_Param *param;
+
+   if (!params) return EINA_FALSE;
+   param = edje_external_param_find(params, key);
+
+   if (param && param->type == EDJE_EXTERNAL_PARAM_TYPE_DOUBLE && ret)
+     {
+       *ret = param->d;
+       return EINA_TRUE;
+     }
+
+   return EINA_FALSE;
+}
+
+EAPI Eina_Bool
+edje_external_param_string_get(const Eina_List *params, const char *key, const char **ret)
+{
+   Edje_External_Param *param;
+
+   if (!params) return EINA_FALSE;
+   param = edje_external_param_find(params, key);
+
+   if (param && param->type == EDJE_EXTERNAL_PARAM_TYPE_STRING && ret)
+     {
+       *ret = param->s;
+       return EINA_TRUE;
+     }
+
+   return EINA_FALSE;
+}
+
+EAPI Eina_Bool
+edje_external_param_bool_get(const Eina_List *params, const char *key, Eina_Bool *ret)
+{
+   Edje_External_Param *param;
+
+   if (!params) return EINA_FALSE;
+   param = edje_external_param_find(params, key);
+
+   if (param && param->type == EDJE_EXTERNAL_PARAM_TYPE_BOOL && ret)
+     {
+       *ret = param->i;
+       return EINA_TRUE;
+     }
+
+   return EINA_FALSE;
+}
+
+EAPI Eina_Bool
+edje_external_param_choice_get(const Eina_List *params, const char *key, const char **ret)
+{
+   Edje_External_Param *param;
+
+   if (!params) return EINA_FALSE;
+   param = edje_external_param_find(params, key);
+
+   if (param && param->type == EDJE_EXTERNAL_PARAM_TYPE_CHOICE && ret)
+     {
+       *ret = param->s;
+       return EINA_TRUE;
+     }
+
+   return EINA_FALSE;
+}
+
+/**
+ * Get the array of parameters information about a type given its name.
+ *
+ * @note the type names and other strings are static, that means they
+ *       @b NOT translated. One must use
+ *       Edje_External_Type::translate() to translate those.
+ *
+ * @return the NULL terminated array, or @c NULL if type is unknown or
+ *         it does not have any parameter information.
+ *
+ * @see edje_external_type_get()
+ */
+EAPI const Edje_External_Param_Info *
+edje_external_param_info_get(const char *type_name)
+{
+   Edje_External_Type *type;
+
+   type = eina_hash_find(type_registry, type_name);
+   if (!type)
+     return NULL;
+   return type->parameters_info;
+}
+
+EAPI const Edje_External_Type *
+edje_external_type_get(const char *type_name)
+{
+   return eina_hash_find(type_registry, type_name);
+}
+
+void
+_edje_external_init()
+{
+   if (!type_registry)
+     type_registry = eina_hash_string_superfast_new(NULL);
+
+   init_count++;
+}
+
+void
+_edje_external_shutdown()
+{
+   if (--init_count == 0)
+     {
+       eina_hash_free(type_registry);
+       type_registry = NULL;
+     }
+}
+
+Evas_Object *
+_edje_external_type_add(const char *type_name, Evas *evas, Evas_Object *parent, const Eina_List *params, const char *part_name)
+{
+   Edje_External_Type *type;
+   Evas_Object *obj;
+
+   type = eina_hash_find(type_registry, type_name);
+   if (!type)
+     {
+       ERR("external type '%s' not registered", type_name);
+       return NULL;
+     }
+
+   obj = type->add(type->data, evas, parent, params, part_name);
+   if (!obj)
+     {
+       ERR("External type '%s' returned NULL from constructor", type_name);
+       return NULL;
+     }
+
+   evas_object_data_set(obj, "Edje_External_Type", type);
+
+   return obj;
+}
+
+void
+_edje_external_signal_emit(Evas_Object *obj, const char *emission, const char *source)
+{
+   Edje_External_Type *type;
+
+   type = evas_object_data_get(obj, "Edje_External_Type");
+   if (!type)
+     {
+       ERR("External type data not found.");
+       return;
+     }
+
+   type->signal_emit(type->data, obj, emission, source);
+}
+
+Eina_Bool
+_edje_external_param_set(Evas_Object *obj, const Edje_External_Param *param)
+{
+   Edje_External_Type *type = evas_object_data_get(obj, "Edje_External_Type");
+   if (!type)
+     {
+       ERR("no external type for object %p", obj);
+       return EINA_FALSE;
+     }
+   if (!type->param_set)
+     {
+       ERR("external type '%s' from module '%s' does not provide param_set()",
+           type->module_name, type->module);
+       return EINA_FALSE;
+     }
+   return type->param_set(type->data, obj, param);
+}
+
+Eina_Bool
+_edje_external_param_get(const Evas_Object *obj, Edje_External_Param *param)
+{
+   Edje_External_Type *type = evas_object_data_get(obj, "Edje_External_Type");
+   if (!type)
+     {
+       ERR("no external type for object %p", obj);
+       return EINA_FALSE;
+     }
+   if (!type->param_get)
+     {
+       ERR("external type '%s' from module '%s' does not provide param_set()",
+           type->module_name, type->module);
+       return EINA_FALSE;
+     }
+   return type->param_get(type->data, obj, param);
+}
+
+void
+_edje_external_params_free(Eina_List *external_params, Eina_Bool free_strings)
+{
+   Edje_External_Param *param;
+
+   EINA_LIST_FREE(external_params, param)
+     {
+       if (free_strings)
+         {
+            if (param->name) eina_stringshare_del(param->name);
+            if (param->s) eina_stringshare_del(param->s);
+         }
+       free(param);
+     }
+}
+
+void
+_edje_external_recalc_apply(Edje *ed, Edje_Real_Part *ep,
+      Edje_Calc_Params *params,
+      Edje_Part_Description *chosen_desc)
+{
+   Edje_External_Type *type;
+   void *params1, *params2 = NULL;
+   if (!ep->swallowed_object) return;
+
+   type = evas_object_data_get(ep->swallowed_object, "Edje_External_Type");
+
+   if (!type) return;
+
+   if (!type->state_set) return;
+
+   params1 = ep->param1.external_params ?
+                 ep->param1.external_params :
+                 ep->param1.description->external_params;
+
+   if (ep->param2 && ep->param2->description)
+     params2 = ep->param2->external_params ?
+                 ep->param2->external_params :
+                 ep->param2->description->external_params;
+
+   type->state_set(type->data, ep->swallowed_object,
+        params1, params2, ep->description_pos);
+}
+
+void *
+_edje_external_params_parse(Evas_Object *obj, const Eina_List *params)
+{
+   Edje_External_Type *type;
+
+   type = evas_object_data_get(obj, "Edje_External_Type");
+   if (!type) return NULL;
+
+   if (!type->params_parse) return NULL;
+
+   return type->params_parse(type->data, obj, params);
+}
+
+void
+_edje_external_parsed_params_free(Evas_Object *obj, void *params)
+{
+   Edje_External_Type *type;
+
+   if (!params) return;
+
+   type = evas_object_data_get(obj, "Edje_External_Type");
+   if (!type) return;
+
+   if (!type->params_free) return;
+
+   type->params_free(params);
+}
diff --git a/src/lib/edje_load.c b/src/lib/edje_load.c
new file mode 100644 (file)
index 0000000..42cdcf7
--- /dev/null
@@ -0,0 +1,1285 @@
+/*
+ * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
+ */
+
+#include <string.h>
+
+#include "edje_private.h"
+
+static Eina_Bool _edje_file_collection_hash_foreach(const Eina_Hash *hash, const void *key, void *data, void *fdata);
+#ifdef EDJE_PROGRAM_CACHE
+static Eina_Bool  _edje_collection_free_prog_cache_matches_free_cb(const Eina_Hash *hash, const void *key, void *data, void *fdata);
+#endif
+static void _edje_object_pack_item_hints_set(Evas_Object *obj, Edje_Pack_Element *it);
+static void _cb_signal_repeat(void *data, Evas_Object *obj, const char *signal, const char *source);
+
+static Eina_List *_edje_swallows_collect(Edje *ed);
+
+/************************** API Routines **************************/
+
+/* FIXDOC: Verify/expand doc */
+/** Sets the EET file and group to load @a obj from
+ * @param obj A valid Evas_Object handle
+ * @param file The path to the EET file
+ * @param group The group name in the Edje
+ * @return 0 on Error\n
+ * 1 on Success and sets EDJE_LOAD_ERROR_NONE
+ *
+ * Edje uses EET files, conventionally ending in .edj, to store object
+ * descriptions. A single file contains multiple named groups. This function
+ * specifies the file and group name to load @a obj from.
+ */
+EAPI Eina_Bool
+edje_object_file_set(Evas_Object *obj, const char *file, const char *group)
+{
+   Edje *ed;
+
+   ed = _edje_fetch(obj);
+   if (!ed)
+     return EINA_FALSE;
+   return ed->api->file_set(obj, file, group);
+}
+
+/* FIXDOC: Verify/expand doc. */
+/** Get the file and group name that @a obj was loaded from
+ * @param obj A valid Evas_Object handle
+ * @param file A pointer to store a pointer to the filename in
+ * @param group A pointer to store a pointer to the group name in
+ *
+ * This gets the EET file location and group for the given Evas_Object.
+ * If @a obj is either not an edje file, or has not had its file/group set
+ * using edje_object_file_set(), then both @a file and @a group will be set
+ * to NULL.
+ *
+ * It is valid to pass in NULL for either @a file or @a group if you are not
+ * interested in one of the values.
+ */
+EAPI void
+edje_object_file_get(const Evas_Object *obj, const char **file, const char **group)
+{
+   Edje *ed;
+
+   ed = _edje_fetch(obj);
+   if (!ed)
+     {
+       if (file) *file = NULL;
+       if (group) *group = NULL;
+       return;
+     }
+   if (file) *file = ed->path;
+   if (group) *group = ed->group;
+}
+
+/* FIXDOC: Verify. return error? */
+/** Gets the Edje load error
+ * @param obj A valid Evas_Object handle
+ *
+ * @return The Edje load error:\n
+ * EDJE_LOAD_ERROR_NONE: No Error\n
+ * EDJE_LOAD_ERROR_GENERIC: Generic Error\n
+ * EDJE_LOAD_ERROR_DOES_NOT_EXIST: Does not Exist\n
+ * EDJE_LOAD_ERROR_PERMISSION_DENIED: Permission Denied\n
+ * EDJE_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED: Resource Allocation Failed\n
+ * EDJE_LOAD_ERROR_CORRUPT_FILE: Corrupt File\n
+ * EDJE_LOAD_ERROR_UNKNOWN_FORMAT: Unknown Format\n
+ * EDJE_LOAD_ERROR_INCOMPATIBLE_FILE: Incompatible File\n
+ * EDJE_LOAD_ERROR_UNKNOWN_COLLECTION: Unknown Collection\n
+ * EDJE_LOAD_ERROR_RECURSIVE_REFERENCE: Recursive Reference\n
+ */
+EAPI int
+edje_object_load_error_get(const Evas_Object *obj)
+{
+   Edje *ed;
+
+   ed = _edje_fetch(obj);
+   if (!ed) return EDJE_LOAD_ERROR_NONE;
+   return ed->load_error;
+}
+
+EAPI const char *
+edje_load_error_str(int error)
+{
+   switch (error)
+     {
+      case EDJE_LOAD_ERROR_NONE:
+        return "No Error";
+      case EDJE_LOAD_ERROR_GENERIC:
+        return "Generic Error";
+      case EDJE_LOAD_ERROR_DOES_NOT_EXIST:
+        return "File Does Not Exist";
+      case EDJE_LOAD_ERROR_PERMISSION_DENIED:
+        return "Permission Denied";
+      case EDJE_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED:
+        return "Resource Allocation Failed";
+      case EDJE_LOAD_ERROR_CORRUPT_FILE:
+        return "Corrupt File";
+      case EDJE_LOAD_ERROR_UNKNOWN_FORMAT:
+        return "Unknown Format";
+      case EDJE_LOAD_ERROR_INCOMPATIBLE_FILE:
+        return "Incompatible File";
+      case EDJE_LOAD_ERROR_UNKNOWN_COLLECTION:
+        return "Unknown Collection";
+      case EDJE_LOAD_ERROR_RECURSIVE_REFERENCE:
+        return "Recursive Reference";
+      default:
+        return "Unknown Error";
+     }
+}
+
+
+/** Get a list of groups in an edje file
+ * @param file The path to the edje file
+ *
+ * @return The Eina_List of group names (char *)
+ *
+ * Note: the list must be freed using edje_file_collection_list_free()
+ * when you are done with it.
+ */
+EAPI Eina_List *
+edje_file_collection_list(const char *file)
+{
+   Eina_List *lst = NULL;
+   Edje_File *edf;
+   int error_ret = 0;
+
+   if ((!file) || (!*file)) return NULL;
+   edf = _edje_cache_file_coll_open(file, NULL, &error_ret, NULL);
+   if (edf != NULL)
+     {
+       if (edf->collection_dir)
+         {
+            Eina_List *l;
+            Edje_Part_Collection_Directory_Entry *ce;
+
+            EINA_LIST_FOREACH(edf->collection_dir->entries, l, ce)
+              lst = eina_list_append(lst, eina_stringshare_add(ce->entry));
+         }
+       _edje_cache_file_unref(edf);
+     }
+   return lst;
+}
+
+/** Free file collection list
+ * @param lst The Eina_List of groups
+ *
+ * Frees the list returned by edje_file_collection_list().
+ */
+EAPI void
+edje_file_collection_list_free(Eina_List *lst)
+{
+   while (lst)
+     {
+        if (eina_list_data_get(lst)) eina_stringshare_del(eina_list_data_get(lst));
+       lst = eina_list_remove(lst, eina_list_data_get(lst));
+     }
+}
+
+/** Determine whether a group matching glob exists in an edje file.
+ * @param file The file path
+ * @param glob A glob to match on
+ *
+ * @return 1 if a match is found, 0 otherwise
+ */
+EAPI Eina_Bool
+edje_file_group_exists(const char *file, const char *glob)
+{
+   Edje_File *edf;
+   int error_ret = 0;
+
+   if ((!file) || (!*file)) return 0;
+   edf = _edje_cache_file_coll_open(file, NULL, &error_ret, NULL);
+   if (edf != NULL)
+     {
+       if (edf->collection_dir)
+         {
+             Edje_Patterns *patterns;
+
+             patterns =
+               edje_match_collection_dir_init(edf->collection_dir->entries);
+             if (edje_match_collection_dir_exec(patterns, glob))
+               {
+                  edje_match_patterns_free(patterns);
+                  _edje_cache_file_unref(edf);
+                  return 1;
+               }
+             edje_match_patterns_free(patterns);
+         }
+       _edje_cache_file_unref(edf);
+     }
+   return 0;
+}
+
+
+/** Get data from the file level data block of an edje file
+ * @param file The path to the .edj file
+ * @param key The data key
+ * @return The string value of the data
+ *
+ * If an edje file is built from the following edc:
+ *
+ * data {
+ *   item: "key1" "value1";
+ *   item: "key2" "value2";
+ * }
+ * collections { ... }
+ *
+ * Then, edje_file_data_get("key1") will return "value1"
+ */
+EAPI char *
+edje_file_data_get(const char *file, const char *key)
+{
+   Edje_File *edf;
+   char *str = NULL;
+   int error_ret = 0;
+
+   if (key)
+     {
+       edf = _edje_cache_file_coll_open(file, NULL, &error_ret, NULL);
+       if (edf != NULL)
+         {
+            if (edf->data_cache != NULL)
+              {
+                 str = eina_hash_find(edf->data_cache, key);
+                 if (str) str = strdup(str);
+              }
+            _edje_cache_file_unref(edf);
+         }
+     }
+   return str;
+}
+
+void
+_edje_programs_patterns_clean(Edje *ed)
+{
+   _edje_signals_sources_patterns_clean(&ed->patterns.programs);
+
+   eina_rbtree_delete(ed->patterns.programs.exact_match,
+                     EINA_RBTREE_FREE_CB(edje_match_signal_source_free),
+                     NULL);
+   ed->patterns.programs.exact_match = NULL;
+
+   ed->patterns.programs.globing = eina_list_free(ed->patterns.programs.globing);
+}
+
+void
+_edje_programs_patterns_init(Edje *ed)
+{
+   Edje_Signals_Sources_Patterns *ssp = &ed->patterns.programs;
+
+   if (ssp->signals_patterns)
+     return;
+
+   ssp->globing = edje_match_program_hash_build(ed->collection->programs,
+                                                         &ssp->exact_match);
+
+   ssp->signals_patterns = edje_match_programs_signal_init(ssp->globing);
+   ssp->sources_patterns = edje_match_programs_source_init(ssp->globing);
+}
+
+int
+_edje_object_file_set_internal(Evas_Object *obj, const char *file, const char *group, Eina_List *group_path)
+{
+   Edje *ed;
+   int n;
+   Eina_List *parts = NULL;
+   Eina_List *old_swallows;
+   int group_path_started = 0;
+
+   ed = _edje_fetch(obj);
+   if (!ed) return 0;
+   if (!file) file = "";
+   if (!group) group = "";
+   if (((ed->path) && (!strcmp(file, ed->path))) &&
+       (ed->group) && (!strcmp(group, ed->group)))
+     return 1;
+
+   old_swallows = _edje_swallows_collect(ed);
+
+   if (_edje_script_only(ed)) _edje_script_only_shutdown(ed);
+   if (_edje_lua_script_only(ed)) _edje_lua_script_only_shutdown(ed);
+   _edje_file_del(ed);
+
+   if (ed->path) eina_stringshare_del(ed->path);
+   if (ed->group) eina_stringshare_del(ed->group);
+   ed->path = eina_stringshare_add(file);
+   ed->group = eina_stringshare_add(group);
+
+   ed->load_error = EDJE_LOAD_ERROR_NONE;
+   _edje_file_add(ed);
+
+   if (ed->file && ed->file->external_dir)
+     {
+       const Edje_External_Directory_Entry *ext;
+       const Eina_List *n;
+
+       EINA_LIST_FOREACH(ed->file->external_dir->entries, n, ext)
+         {
+            edje_module_load(ext->entry);
+         }
+     }
+
+   _edje_textblock_styles_add(ed);
+   _edje_textblock_style_all_update(ed);
+
+   ed->has_entries = EINA_FALSE;
+
+   if (ed->collection)
+     {
+       if (ed->collection->script_only)
+         {
+            ed->load_error = EDJE_LOAD_ERROR_NONE;
+            _edje_script_only_init(ed);
+         }
+       else if (ed->collection->lua_script_only)
+         {
+            ed->load_error = EDJE_LOAD_ERROR_NONE;
+            _edje_lua_script_only_init(ed);
+         }
+       else
+         {
+            Eina_List *l;
+            int i;
+            int errors = 0;
+            Edje_Part *ep;
+
+            /* colorclass stuff */
+            EINA_LIST_FOREACH(ed->collection->parts, l, ep)
+              {
+                 Eina_List *hist = NULL;
+                 Edje_Part_Description *desc;
+
+                 if (errors)
+                   break;
+                 /* Register any color classes in this parts descriptions. */
+                 if ((ep->default_desc) && (ep->default_desc->color_class))
+                   _edje_color_class_member_add(ed, ep->default_desc->color_class);
+
+                 EINA_LIST_FOREACH(ep->other_desc, hist, desc)
+                   if (desc->color_class)
+                     _edje_color_class_member_add(ed, desc->color_class);
+              }
+            /* build real parts */
+            for (n = 0, l = ed->collection->parts; l; l = eina_list_next(l), n++)
+              {
+                 Edje_Part *ep;
+                 Edje_Real_Part *rp;
+
+                 ep = eina_list_data_get(l);
+                 rp = eina_mempool_malloc(_edje_real_part_mp, sizeof(Edje_Real_Part));
+                 if (!rp)
+                   {
+                      ed->load_error = EDJE_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
+                      return 0;
+                   }
+
+                 memset(rp, 0, sizeof (Edje_Real_Part));
+
+                 if ((ep->dragable.x != 0) || (ep->dragable.y != 0))
+                   {
+                      rp->drag = calloc(1, sizeof (Edje_Real_Part_Drag));
+                      if (!rp->drag)
+                        {
+                           ed->load_error = EDJE_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
+                           free(rp);
+                           return 0;
+                        }
+
+                      rp->drag->step.x = FROM_INT(ep->dragable.step_x);
+                      rp->drag->step.y = FROM_INT(ep->dragable.step_y);
+                   }
+
+                 rp->edje = ed;
+                 _edje_ref(rp->edje);
+                 rp->part = ep;
+                 parts = eina_list_append(parts, rp);
+                 rp->param1.description = ep->default_desc;
+                 rp->chosen_description = rp->param1.description;
+                 if (!rp->param1.description)
+                   ERR("no default part description!");
+
+                 switch (ep->type)
+                   {
+                    case EDJE_PART_TYPE_RECTANGLE:
+                       rp->object = evas_object_rectangle_add(ed->evas);
+                       break;
+                    case EDJE_PART_TYPE_IMAGE:
+                       rp->object = evas_object_image_add(ed->evas);
+                       break;
+                    case EDJE_PART_TYPE_TEXT:
+                       _edje_text_part_on_add(ed, rp);
+                       rp->object = evas_object_text_add(ed->evas);
+                       evas_object_text_font_source_set(rp->object, ed->path);
+                       break;
+                    case EDJE_PART_TYPE_SWALLOW:
+                    case EDJE_PART_TYPE_GROUP:
+                    case EDJE_PART_TYPE_EXTERNAL:
+                       rp->object = evas_object_rectangle_add(ed->evas);
+                       evas_object_color_set(rp->object, 0, 0, 0, 0);
+                       evas_object_pass_events_set(rp->object, 1);
+                       evas_object_pointer_mode_set(rp->object, EVAS_OBJECT_POINTER_MODE_NOGRAB);
+                       _edje_callbacks_focus_add(rp->object, ed, rp);
+                       break;
+                    case EDJE_PART_TYPE_TEXTBLOCK:
+                       rp->object = evas_object_textblock_add(ed->evas);
+                       break;
+                    case EDJE_PART_TYPE_GRADIENT:
+                       rp->object = evas_object_gradient_add(ed->evas);
+                       break;
+                    case EDJE_PART_TYPE_BOX:
+                       rp->object = evas_object_box_add(ed->evas);
+                       break;
+                    case EDJE_PART_TYPE_TABLE:
+                       rp->object = evas_object_table_add(ed->evas);
+                       break;
+                    default:
+                       ERR("wrong part type %i!", ep->type);
+                       break;
+                   }
+
+                 if (rp->object)
+                   {
+                      evas_object_smart_member_add(rp->object, ed->obj);
+//                    evas_object_layer_set(rp->object, evas_object_layer_get(ed->obj));
+                      if (ep->type != EDJE_PART_TYPE_SWALLOW && ep->type != EDJE_PART_TYPE_GROUP && ep->type != EDJE_PART_TYPE_EXTERNAL)
+                        {
+                           if (ep->mouse_events)
+                             {
+                                _edje_callbacks_add(rp->object, ed, rp);
+                                if (ep->repeat_events)
+                                  evas_object_repeat_events_set(rp->object, 1);
+                                
+                                if (ep->pointer_mode != EVAS_OBJECT_POINTER_MODE_AUTOGRAB)
+                                  evas_object_pointer_mode_set(rp->object, ep->pointer_mode);
+                             }
+                           else
+                             {
+                                evas_object_pass_events_set(rp->object, 1);
+                                evas_object_pointer_mode_set(rp->object, EVAS_OBJECT_POINTER_MODE_NOGRAB);
+                             }
+                           if (ep->precise_is_inside)
+                             evas_object_precise_is_inside_set(rp->object, 1);
+                        }
+                      if (rp->part->clip_to_id < 0)
+                        evas_object_clip_set(rp->object, ed->clipper);
+                   }
+                 rp->gradient_id = -1;
+              }
+            if (n > 0)
+              {
+                 Edje_Real_Part *rp;
+                 ed->table_parts = malloc(sizeof(Edje_Real_Part *) * n);
+                 ed->table_parts_size = n;
+                 /* FIXME: check malloc return */
+                 n = 0;
+                 EINA_LIST_FOREACH(parts, l, rp)
+                   {
+                      ed->table_parts[n] = rp;
+                      n++;
+                   }
+                 eina_list_free(parts);
+                 for (i = 0; i < ed->table_parts_size; i++)
+                   {
+                      rp = ed->table_parts[i];
+                      if (rp->param1.description->rel1.id_x >= 0)
+                        rp->param1.rel1_to_x = ed->table_parts[rp->param1.description->rel1.id_x % ed->table_parts_size];
+                      if (rp->param1.description->rel1.id_y >= 0)
+                        rp->param1.rel1_to_y = ed->table_parts[rp->param1.description->rel1.id_y % ed->table_parts_size];
+                      if (rp->param1.description->rel2.id_x >= 0)
+                        rp->param1.rel2_to_x = ed->table_parts[rp->param1.description->rel2.id_x % ed->table_parts_size];
+                      if (rp->param1.description->rel2.id_y >= 0)
+                        rp->param1.rel2_to_y = ed->table_parts[rp->param1.description->rel2.id_y % ed->table_parts_size];
+                      if (rp->part->clip_to_id >= 0)
+                        {
+                           rp->clip_to = ed->table_parts[rp->part->clip_to_id % ed->table_parts_size];
+                           if (rp->clip_to)
+                             {
+                                evas_object_pass_events_set(rp->clip_to->object, 1);
+                                evas_object_pointer_mode_set(rp->clip_to->object, EVAS_OBJECT_POINTER_MODE_NOGRAB);
+                                evas_object_clip_set(rp->object, rp->clip_to->object);
+                             }
+                        }
+                      if (rp->drag)
+                        {
+                           if (rp->part->dragable.confine_id >= 0)
+                             rp->drag->confine_to = ed->table_parts[rp->part->dragable.confine_id % ed->table_parts_size];
+                        }
+
+                      /* replay events for dragable */
+                      if (rp->part->dragable.events_id >= 0)
+                        {
+                           rp->events_to =
+                             ed->table_parts[rp->part->dragable.events_id % ed->table_parts_size];
+                           /* events_to may be used only with dragable */
+                           if (!rp->events_to->part->dragable.x &&
+                               !rp->events_to->part->dragable.y)
+                             rp->events_to = NULL;
+                        }
+
+                      rp->swallow_params.min.w = 0;
+                      rp->swallow_params.min.w = 0;
+                      rp->swallow_params.max.w = -1;
+                      rp->swallow_params.max.h = -1;
+                      
+                      if (ed->file->feature_ver < 1)
+                        {
+                           rp->param1.description->text.id_source = -1;
+                           rp->param1.description->text.id_text_source = -1;
+                        }
+                      if (rp->param1.description->text.id_source >= 0)
+                        rp->text.source = ed->table_parts[rp->param1.description->text.id_source % ed->table_parts_size];
+                      if (rp->param1.description->text.id_text_source >= 0)
+                        rp->text.text_source = ed->table_parts[rp->param1.description->text.id_text_source % ed->table_parts_size];
+                      if (rp->part->entry_mode > EDJE_ENTRY_EDIT_MODE_NONE)
+                         {
+                            _edje_entry_real_part_init(rp);
+                            if (!ed->has_entries)
+                                ed->has_entries = EINA_TRUE;
+                         }
+                   }
+              }
+            
+            _edje_programs_patterns_init(ed);
+            
+            n = eina_list_count(ed->collection->programs);
+            if (n > 0)
+              {
+                 Edje_Program *pr;
+                 /* FIXME: keeping a table AND a list is just bad - nuke list */
+                 ed->table_programs = malloc(sizeof(Edje_Program *) * n);
+                 ed->table_programs_size = n;
+                 /* FIXME: check malloc return */
+                 n = 0;
+                 EINA_LIST_FOREACH(ed->collection->programs, l, pr)
+                   {
+                      ed->table_programs[n] = pr;
+                      n++;
+                   }
+              }
+            _edje_ref(ed);
+            _edje_block(ed);
+            _edje_freeze(ed);
+            if (ed->collection->script) _edje_embryo_script_init(ed);
+            _edje_var_init(ed);
+            for (i = 0; i < ed->table_parts_size; i++)
+              {
+                 Edje_Real_Part *rp;
+                 
+                 rp = ed->table_parts[i];
+                 evas_object_show(rp->object);
+                 if (_edje_block_break(ed)) break;
+                 if (rp->drag)
+                   {
+                      if (rp->part->dragable.x < 0) rp->drag->val.x = FROM_DOUBLE(1.0);
+                      if (rp->part->dragable.y < 0) rp->drag->val.x = FROM_DOUBLE(1.0);
+                      _edje_dragable_pos_set(ed, rp, rp->drag->val.x, rp->drag->val.y);
+                   }
+              }
+            ed->dirty = 1;
+#ifdef EDJE_CALC_CACHE
+            ed->all_part_change = 1;
+#endif
+            if ((evas_object_clipees_get(ed->clipper)) &&
+                (evas_object_visible_get(obj)))
+              evas_object_show(ed->clipper);
+            
+            /* instantiate 'internal swallows' */
+            for (i = 0; i < ed->table_parts_size; i++)
+              {
+                 Edje_Real_Part *rp;
+                 /* XXX: curr_item and pack_it don't require to be NULL since
+                  * XXX: they are just used when source != NULL and type == BOX,
+                  * XXX: and they're always set in this case, but GCC fails to
+                  * XXX: notice that, so let's shut it up
+                  */
+                 Eina_List *curr_item = NULL;
+                 Edje_Pack_Element *pack_it = NULL;
+                 const char *source = NULL;
+                 
+                 rp = ed->table_parts[i];
+
+                 switch (rp->part->type)
+                   {
+                    case EDJE_PART_TYPE_GROUP:
+                       source = rp->part->source;
+                       break;
+                    case EDJE_PART_TYPE_BOX:
+                    case EDJE_PART_TYPE_TABLE:
+                       if (rp->part->items)
+                         {
+                            curr_item = rp->part->items;
+                            pack_it = curr_item->data;
+                            source = pack_it->source;
+                         }
+                       break;
+                    case EDJE_PART_TYPE_EXTERNAL:
+                         {
+                            Evas_Object *child_obj;
+                            child_obj = _edje_external_type_add(rp->part->source, evas_object_evas_get(ed->obj), ed->obj, rp->part->default_desc->external_params, rp->part->name);
+                            if (child_obj)
+                              {
+                                 _edje_real_part_swallow(rp, child_obj);
+                                 rp->param1.external_params = _edje_external_params_parse(child_obj, rp->param1.description->external_params);
+                                 _edje_external_recalc_apply(ed, rp, NULL, rp->chosen_description);
+                              }
+                         }
+                       continue;
+                    default:
+                       continue;
+                   }
+
+                 while (source)
+                   {
+                      Eina_List *l;
+                      Evas_Object *child_obj;
+                      Edje *child_ed;
+                      const char *group_path_entry = eina_stringshare_add(source);
+                      const char *data;
+
+                      if (!group_path)
+                        {
+                           group_path = eina_list_append(NULL, eina_stringshare_add(group));
+                           group_path_started = 1;
+                        }
+                      /* make sure that this group isn't already in the tree of parents */
+                      EINA_LIST_FOREACH(group_path, l, data)
+                        {
+                           if (data == group_path_entry)
+                             {
+                                _edje_thaw(ed);
+                                _edje_unblock(ed);
+                                _edje_unref(ed);
+                                _edje_file_del(ed);
+                                eina_stringshare_del(group_path_entry);
+                                if (group_path_started)
+                                  {
+                                     eina_stringshare_del(eina_list_data_get(group_path));
+                                     eina_list_free(group_path);
+                                  }
+                                ed->load_error = EDJE_LOAD_ERROR_RECURSIVE_REFERENCE;
+                                return 0;
+                             }
+                        }
+                      
+                      child_obj = edje_object_add(ed->evas);
+                      group_path = eina_list_append(group_path, group_path_entry);
+                      if (!_edje_object_file_set_internal(child_obj, file, source, group_path))
+                        {
+                           _edje_thaw(ed);
+                           _edje_unblock(ed);
+                           _edje_unref(ed);
+                           _edje_file_del(ed);
+                           
+                           if (group_path_started)
+                             {
+                                while (group_path)
+                                  {
+                                     eina_stringshare_del(eina_list_data_get(group_path));
+                                     group_path = eina_list_remove_list(group_path, group_path);
+                                  }
+                             }
+                           ed->load_error = edje_object_load_error_get(child_obj);
+                           return 0;
+                        }
+                      child_ed = _edje_fetch(child_obj);
+                      child_ed->parent = eina_stringshare_add(rp->part->name);
+                      
+                      group_path = eina_list_remove(group_path, group_path_entry);
+                      eina_stringshare_del(group_path_entry);
+
+                      edje_object_signal_callback_add(child_obj, "*", "*", _cb_signal_repeat, obj);
+                      if (rp->part->type == EDJE_PART_TYPE_GROUP)
+                        {
+                           _edje_real_part_swallow(rp, child_obj);
+                           source = NULL;
+                        }
+                      else
+                        {
+                           _edje_object_pack_item_hints_set(child_obj, pack_it);
+                           evas_object_show(child_obj);
+                           if (pack_it->name)
+                             evas_object_name_set(child_obj, pack_it->name);
+                           if (rp->part->type == EDJE_PART_TYPE_BOX)
+                             {
+                                _edje_real_part_box_append(rp, child_obj);
+                                evas_object_data_set(child_obj, "\377 edje.box_item", pack_it);
+                             }
+                           else if(rp->part->type == EDJE_PART_TYPE_TABLE)
+                             {
+                                _edje_real_part_table_pack(rp, child_obj, pack_it->col, pack_it->row, pack_it->colspan, pack_it->rowspan);
+                                evas_object_data_set(child_obj, "\377 edje.table_item", pack_it);
+                             }
+                           rp->items = eina_list_append(rp->items, child_obj);
+                           if (!(curr_item = curr_item->next))
+                             source = NULL;
+                           else
+                             {
+                                pack_it = curr_item->data;
+                                source = pack_it->source;
+                             }
+                        }
+                   }
+              }
+            
+            if (group_path_started)
+              {
+                 const char *str;
+
+                 EINA_LIST_FREE(group_path, str)
+                   eina_stringshare_del(str);
+              }
+            
+            /* reswallow any swallows that existed before setting the file */
+            if (old_swallows)
+              {
+                 while (old_swallows)
+                   {
+                      const char *name;
+                      Evas_Object *swallow;
+                      
+                      name = eina_list_data_get(old_swallows);
+                      old_swallows = eina_list_remove_list(old_swallows, old_swallows);
+                      
+                      swallow = eina_list_data_get(old_swallows);
+                      old_swallows = eina_list_remove_list(old_swallows, old_swallows);
+                      
+                      edje_object_part_swallow(obj, name, swallow);
+                      eina_stringshare_del(name);
+                   }
+              }
+            
+            _edje_recalc(ed);
+            _edje_thaw(ed);
+            _edje_unblock(ed);
+            _edje_unref(ed);
+            ed->load_error = EDJE_LOAD_ERROR_NONE;
+            _edje_emit(ed, "load", NULL);
+            /* instantiate 'internal swallows' */
+            for (i = 0; i < ed->table_parts_size; i++)
+              {
+                 Edje_Real_Part *rp;
+                 
+                 rp = ed->table_parts[i];
+                  if ((rp->part->type == EDJE_PART_TYPE_TEXTBLOCK) &&
+                      (rp->part->default_desc))
+                    {
+                       Edje_Style *stl  = NULL;
+                       const char *style;
+                       
+                       style = rp->part->default_desc->text.style;
+                       if (style)
+                         {
+                            EINA_LIST_FOREACH(ed->file->styles, l, stl)
+                              {
+                                 if ((stl->name) && (!strcmp(stl->name, style))) break;
+                                 stl = NULL;
+                              }
+                         }
+                       if (stl)
+                         {
+                            if (evas_object_textblock_style_get(rp->object) != stl->style)
+                              evas_object_textblock_style_set(rp->object, stl->style);
+                         }
+                    }
+               }
+         }
+        _edje_entry_init(ed);
+       return 1;
+     }
+   else
+     return 0;
+   ed->load_error = EDJE_LOAD_ERROR_NONE;
+   _edje_entry_init(ed);
+   return 1;
+}
+
+void
+_edje_file_add(Edje *ed)
+{
+   if (_edje_edd_edje_file == NULL) return;
+   ed->file = _edje_cache_file_coll_open(ed->path, ed->group,
+                                        &(ed->load_error),
+                                        &(ed->collection));
+
+   if (!ed->collection)
+     {
+       if (ed->file)
+         {
+            _edje_cache_file_unref(ed->file);
+            ed->file = NULL;
+         }
+     }
+}
+
+static Eina_List *
+_edje_swallows_collect(Edje *ed)
+{
+   Eina_List *swallows = NULL;
+   int i;
+
+   if (!ed->file || !ed->table_parts) return NULL;
+   for (i = 0; i < ed->table_parts_size; i++)
+     {
+       Edje_Real_Part *rp;
+
+       rp = ed->table_parts[i];
+       if (rp->part->type != EDJE_PART_TYPE_SWALLOW || !rp->swallowed_object) continue;
+       swallows = eina_list_append(swallows, eina_stringshare_add(rp->part->name));
+       swallows = eina_list_append(swallows, rp->swallowed_object);
+     }
+   return swallows;
+}
+
+void
+_edje_file_del(Edje *ed)
+{
+   if (ed->freeze_calc)
+     {
+        _edje_freeze_calc_list = eina_list_remove(_edje_freeze_calc_list, ed);
+        ed->freeze_calc = 0;
+        _edje_freeze_calc_count--;
+     }
+   _edje_entry_shutdown(ed);
+   _edje_message_del(ed);
+   _edje_block_violate(ed);
+   _edje_var_shutdown(ed);
+   _edje_programs_patterns_clean(ed);
+
+   if (!((ed->file) && (ed->collection))) return;
+   if (ed->table_parts)
+     {
+       int i;
+       for (i = 0; i < ed->table_parts_size; i++)
+         {
+            Edje_Real_Part *rp;
+
+            rp = ed->table_parts[i];
+            if (rp->part->entry_mode > EDJE_ENTRY_EDIT_MODE_NONE)
+              _edje_entry_real_part_shutdown(rp);
+            if (rp->object)
+              {
+                 _edje_callbacks_del(rp->object, ed);
+                 _edje_callbacks_focus_del(rp->object, ed);
+                 evas_object_del(rp->object);
+              }
+            if (rp->swallowed_object)
+              {
+                  _edje_real_part_swallow_clear(rp);
+                  /* Objects swallowed by the app do not get deleted,
+                   but those internally swallowed (GROUP type) do. */
+                 switch (rp->part->type)
+                   {
+                    case EDJE_PART_TYPE_EXTERNAL:
+                       _edje_external_parsed_params_free(rp->swallowed_object, rp->param1.external_params);
+                       if (rp->param2)
+                         _edje_external_parsed_params_free(rp->swallowed_object, rp->param2->external_params);
+                    case EDJE_PART_TYPE_GROUP:
+                       evas_object_del(rp->swallowed_object);
+                    default:
+                       break;
+                   }
+                 rp->swallowed_object = NULL;
+              }
+            if (rp->items)
+              {
+                 /* evas_box/table handles deletion of objects */
+                 rp->items = eina_list_free(rp->items);
+              }
+            if (rp->text.text) eina_stringshare_del(rp->text.text);
+            if (rp->text.font) eina_stringshare_del(rp->text.font);
+            if (rp->text.cache.in_str) eina_stringshare_del(rp->text.cache.in_str);
+            if (rp->text.cache.out_str) eina_stringshare_del(rp->text.cache.out_str);
+
+            if (rp->custom)
+               {
+#ifdef LUA2
+                  // xxx: lua2
+#else
+                  if (ed->L)
+                    {
+                       _edje_lua_get_reg(ed->L, rp->custom->description);
+                       _edje_lua_free_reg(ed->L, lua_touserdata(ed->L, -1)); // created in edje_lua.c::_edje_lua_part_fn_custom_state
+                       lua_pop(ed->L, 1);
+                       _edje_lua_free_reg(ed->L, rp->custom->description); // created in edje_lua.c::_edje_lua_part_fn_custom_state
+                    }
+#endif                  
+                  _edje_collection_free_part_description_free(rp->custom->description, ed->file->free_strings);
+               }
+
+            /* Cleanup optional part. */
+            free(rp->drag);
+
+            eina_mempool_free(_edje_real_part_state_mp, rp->param2);
+            eina_mempool_free(_edje_real_part_state_mp, rp->custom);
+
+            _edje_unref(rp->edje);
+            eina_mempool_free(_edje_real_part_mp, rp);
+         }
+     }
+   if ((ed->file) && (ed->collection))
+     {
+       Eina_List *l;
+       Edje_Part *ep;
+
+       _edje_textblock_styles_del(ed);
+       EINA_LIST_FOREACH(ed->collection->parts, l, ep)
+         {
+           _edje_text_part_on_del(ed, ep);
+           _edje_color_class_on_del(ed, ep);
+         }
+       
+       _edje_cache_coll_unref(ed->file, ed->collection);
+       ed->collection = NULL;
+     }
+   if (ed->file)
+     {
+       _edje_cache_file_unref(ed->file);
+       ed->file = NULL;
+     }
+   if (ed->actions)
+     {
+       Edje_Running_Program *runp;
+
+       EINA_LIST_FREE(ed->actions, runp)
+         {
+            _edje_anim_count--;
+            free(runp);
+         }
+     }
+   _edje_animators = eina_list_remove(_edje_animators, ed);
+   if (ed->pending_actions)
+     {
+       Edje_Pending_Program *pp;
+
+       EINA_LIST_FREE(ed->pending_actions, pp)
+         {
+            ecore_timer_del(pp->timer);
+            free(pp);
+         }
+     }
+   if (ed->L)
+     {
+#ifdef LUA2
+        _edje_lua2_script_shutdown(ed);
+#else
+       _edje_lua_free_reg(ed->L, ed); // created in edje_lua.c::_edje_lua_script_fn_new/_edje_lua_group_fn_new
+       _edje_lua_free_reg(ed->L, ed->L); // created in edje_program.c::_edje_program_run/edje_lua_script_only.c::_edje_lua_script_only_init
+       _edje_lua_free_thread(ed, ed->L); // created in edje_program.c::_edje_program_run/edje_lua_script_only.c::_edje_lua_script_only_init
+       ed->L = NULL;
+#endif   
+     }
+   if (ed->table_parts) free(ed->table_parts);
+   ed->table_parts = NULL;
+   ed->table_parts_size = 0;
+   if (ed->table_programs) free(ed->table_programs);
+   ed->table_programs = NULL;
+   ed->table_programs_size = 0;
+}
+/**
+ * Used to free the cached data values that are stored in the data_cache
+ * hash table.
+ */
+static Eina_Bool data_cache_free(const Eina_Hash *hash __UNUSED__, const void *key __UNUSED__, void *data, void *fdata)
+{
+   Edje_File    *edf;
+
+   edf = fdata;
+   if (edf->free_strings) eina_stringshare_del(data);
+   return 1;
+}
+
+void
+_edje_file_free(Edje_File *edf)
+{
+   Edje_Color_Class *ecc;
+   Edje_Data *edt;
+
+   if (edf->font_dir)
+     {
+       Edje_Font_Directory_Entry *fe;
+
+       EINA_LIST_FREE(edf->font_dir->entries, fe)
+         {
+            eina_hash_del(edf->font_hash, fe->entry, edf);
+            if (edf->free_strings && fe->path) eina_stringshare_del(fe->path);
+            free(fe);
+         }
+       free(edf->font_dir);
+     }
+   if (edf->font_hash)
+     {
+       eina_hash_free(edf->font_hash);
+       edf->font_hash = NULL;
+     }
+   if (edf->image_dir)
+     {
+       Edje_Image_Directory_Entry *ie;
+
+       EINA_LIST_FREE(edf->image_dir->entries, ie)
+         {
+            if (edf->free_strings && ie->entry) eina_stringshare_del(ie->entry);
+            free(ie);
+         }
+       free(edf->image_dir);
+     }
+   if (edf->collection_dir)
+     {
+       Edje_Part_Collection_Directory_Entry *ce;
+
+       EINA_LIST_FREE(edf->collection_dir->entries, ce)
+         {
+            if (edf->free_strings && ce->entry) eina_stringshare_del(ce->entry);
+            free(ce);
+         }
+       free(edf->collection_dir);
+     }
+   if (edf->spectrum_dir)
+     {
+       Edje_Spectrum_Directory_Entry *se;
+
+       EINA_LIST_FREE(edf->spectrum_dir->entries, se)
+         {
+            Edje_Spectrum_Color *sc;
+
+            EINA_LIST_FREE(se->color_list, sc)
+              free(sc);
+
+             if (edf->free_strings)
+               {
+                  if (se->entry) eina_stringshare_del(se->entry);
+                  if (se->filename) eina_stringshare_del(se->filename);
+               }
+            free(se);
+         }
+       free(edf->spectrum_dir);
+     }
+
+   EINA_LIST_FREE(edf->data, edt)
+     {
+        if (edf->free_strings)
+          {
+             if (edt->key) eina_stringshare_del(edt->key);
+             if (edt->value) eina_stringshare_del(edt->value);
+          }
+       free(edt);
+     }
+   if (edf->data_cache)
+     {
+       eina_hash_foreach(edf->data_cache, data_cache_free, edf);
+       eina_hash_free(edf->data_cache);
+       edf->data_cache = NULL;
+     }
+
+   EINA_LIST_FREE(edf->color_classes, ecc)
+     {
+       if (edf->free_strings && ecc->name) eina_stringshare_del(ecc->name);
+       free(ecc);
+     }
+
+   /* FIXME: free collection_hash and collection_cache */
+   if (edf->collection_hash)
+     {
+       ERR("EDJE ERROR:\n"
+           "\n"
+           "Naughty Programmer - spank spank!\n"
+           "\n"
+           "This program as probably called edje_shutdown() with active Edje objects\n"
+           "still around.\n This can cause problems as both Evas and Edje retain\n"
+           "references to the objects. you should shut down all canvases and objects\n"
+           "before calling edje_shutdown().\n"
+           "The following errors are the edje object files and parts that are still\n"
+           "hanging around, with their reference counts");
+       eina_hash_foreach(edf->collection_hash,
+                          _edje_file_collection_hash_foreach, edf);
+       eina_hash_free(edf->collection_hash);
+     }
+   if (edf->path) eina_stringshare_del(edf->path);
+   if (edf->free_strings && edf->compiler) eina_stringshare_del(edf->compiler);
+   if (edf->collection_cache) _edje_cache_coll_flush(edf);
+   _edje_textblock_style_cleanup(edf);
+   if (edf->ef) eet_close(edf->ef);
+   free(edf);
+}
+
+void
+_edje_collection_free(Edje_File *edf, Edje_Part_Collection *ec)
+{
+   Edje_Program *pr;
+   Edje_Part *ep;
+
+   EINA_LIST_FREE(ec->programs, pr)
+     {
+       Edje_Program_Target *prt;
+       Edje_Program_After *pa;
+
+        if (edf->free_strings)
+          {
+             if (pr->name) eina_stringshare_del(pr->name);
+             if (pr->signal) eina_stringshare_del(pr->signal);
+             if (pr->source) eina_stringshare_del(pr->source);
+             if (pr->filter.part) eina_stringshare_del(pr->filter.part);
+             if (pr->filter.state) eina_stringshare_del(pr->filter.state);
+             if (pr->state) eina_stringshare_del(pr->state);
+             if (pr->state2) eina_stringshare_del(pr->state2);
+          }
+       EINA_LIST_FREE(pr->targets, prt)
+         free(prt);
+       EINA_LIST_FREE(pr->after, pa)
+         free(pa);
+       free(pr);
+     }
+   EINA_LIST_FREE(ec->parts, ep)
+     {
+       Edje_Part_Description *desc;
+
+       if (edf->free_strings && ep->name) eina_stringshare_del(ep->name);
+       if (ep->default_desc)
+         {
+            _edje_collection_free_part_description_free(ep->default_desc, edf->free_strings);
+            ep->default_desc = NULL;
+         }
+       EINA_LIST_FREE(ep->other_desc, desc)
+         _edje_collection_free_part_description_free(desc, edf->free_strings);
+       free(ep);
+     }
+   if (ec->data)
+     {
+       Edje_Data *edt;
+
+       EINA_LIST_FREE(ec->data, edt)
+         {
+             if (edf->free_strings)
+               {
+                  if (edt->key) eina_stringshare_del(edt->key);
+                  if (edt->value) eina_stringshare_del(edt->value);
+               }
+            free(edt);
+         }
+     }
+   if (edf->free_strings && ec->part) eina_stringshare_del(ec->part);
+#ifdef EDJE_PROGRAM_CACHE
+   if (ec->prog_cache.no_matches) eina_hash_free(ec->prog_cache.no_matches);
+   if (ec->prog_cache.matches)
+     {
+       eina_hash_foreach(ec->prog_cache.matches,
+                         _edje_collection_free_prog_cache_matches_free_cb,
+                         NULL);
+       eina_hash_free(ec->prog_cache.matches);
+     }
+#endif
+   if (ec->script) embryo_program_free(ec->script);
+#ifdef LUA2   
+   _edje_lua2_script_unload(ec);
+#endif
+   free(ec);
+}
+
+void
+_edje_collection_free_part_description_free(Edje_Part_Description *desc, Eina_Bool free_strings)
+{
+   Edje_Part_Image_Id *pi;
+
+   EINA_LIST_FREE(desc->image.tween_list, pi)
+     free(pi);
+   if (desc->external_params)
+     _edje_external_params_free(desc->external_params, free_strings);
+   if (free_strings)
+     {
+       if (desc->color_class)     eina_stringshare_del(desc->color_class);
+       if (desc->text.text)       eina_stringshare_del(desc->text.text);
+       if (desc->text.text_class) eina_stringshare_del(desc->text.text_class);
+       if (desc->text.style)      eina_stringshare_del(desc->text.style);
+       if (desc->text.font)       eina_stringshare_del(desc->text.font);
+       if (desc->gradient.type)   eina_stringshare_del(desc->gradient.type);
+       if (desc->gradient.params) eina_stringshare_del(desc->gradient.params);
+     }
+   free(desc);
+}
+
+static Eina_Bool
+_edje_file_collection_hash_foreach(const Eina_Hash *hash __UNUSED__, const void *key __UNUSED__, void *data, void *fdata)
+{
+   Edje_File *edf;
+   Edje_Part_Collection *coll;
+
+   edf = fdata;
+   coll = data;
+   ERR("EEK: EDJE FILE: \"%s\" ref(%i) PART: \"%s\" ref(%i) ",
+       edf->path, edf->references,
+       coll->part, coll->references);
+   _edje_collection_free(edf, coll);
+
+   return 1;
+}
+
+#ifdef EDJE_PROGRAM_CACHE
+static Eina_Bool
+_edje_collection_free_prog_cache_matches_free_cb(const Eina_Hash *hash, const void *key, void *data, void *fdata)
+{
+   eina_list_free((Eina_List *)data);
+   return 1;
+   key = NULL;
+   hash = NULL;
+   fdata = NULL;
+}
+#endif
+
+static void
+_edje_object_pack_item_hints_set(Evas_Object *obj, Edje_Pack_Element *it)
+{
+   Evas_Coord w = 0, h = 0, minw, minh;
+
+   minw = it->min.w;
+   minh = it->min.h;
+
+   if ((minw <= 0) && (minh <= 0))
+     {
+       edje_object_size_min_get(obj, &w, &h);
+       if ((w <= 0) && (h <= 0))
+         edje_object_size_min_calc(obj, &w, &h);
+     }
+   else
+     {
+       w = minw;
+       h = minh;
+     }
+   if (((minw <= 0) && (minh <= 0)) && ((w > 0) || (h > 0)))
+     evas_object_size_hint_min_set(obj, w, h);
+   else
+     evas_object_size_hint_min_set(obj, minw, minh);
+
+   evas_object_size_hint_request_set(obj, it->prefer.w, it->prefer.h);
+   evas_object_size_hint_max_set(obj, it->max.w, it->max.h);
+   evas_object_size_hint_padding_set(obj, it->padding.l, it->padding.r, it->padding.t, it->padding.b);
+   evas_object_size_hint_align_set(obj, it->align.x, it->align.y);
+   evas_object_size_hint_weight_set(obj, it->weight.x, it->weight.y);
+   evas_object_size_hint_aspect_set(obj, it->aspect.mode, it->aspect.w, it->aspect.h);
+
+   evas_object_resize(obj, w, h);
+}
+
+static void
+_cb_signal_repeat(void *data, Evas_Object *obj, const char *signal, const char *source)
+{
+   Evas_Object *parent;
+   Edje                *ed;
+   char                 new_src[4096]; /* XXX is this max reasonable? */
+   size_t       length_parent = 0;
+   size_t       length_source;
+
+   parent = data;
+   ed = _edje_fetch(obj);
+   if (!ed) return;
+   /* Replace snprint("%s%c%s") == memcpy + *new_src + memcat */
+   if (ed->parent)
+     length_parent = strlen(ed->parent);
+   length_source = strlen(source);
+   if (length_source + length_parent + 2 > sizeof(new_src))
+     return;
+
+   if (ed->parent)
+     memcpy(new_src, ed->parent, length_parent);
+   new_src[length_parent] = EDJE_PART_PATH_SEPARATOR;
+   memcpy(new_src + length_parent + 1, source, length_source + 1);
+
+   edje_object_signal_emit(parent, signal, new_src);
+}
diff --git a/src/lib/edje_lua.c b/src/lib/edje_lua.c
new file mode 100644 (file)
index 0000000..685ef81
--- /dev/null
@@ -0,0 +1,5714 @@
+/*
+ * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
+ */
+
+/**
+@page luaref Edje LUA scripting
+
+
+@section intro Introduction
+
+Lua scripts are declared in edc files with the @a lua_script keyword. Like this:
+@code
+group {
+   name: "mygroup";
+   lua_script {
+       print("LUA: on-load script");
+   }
+   parts {
+      ...
+   }
+   programs {
+      program {
+         signal: "a_signal";
+         source: "a_part";
+         lua_script {
+            print("LUA: 'mouse,down,1' on 'button'");
+         }
+      }
+   }
+}
+@endcode
+
+Inside a lua_script code block, there's a reference to your edje @ref Group named
+@a ed, which you may use for accessing your parts (e.g. a part named "label"
+is accessed through @a ed.label). This is the main object that is used to
+access every parts and is also used to create @ref Timer, @ref poller and
+@ref animator; to emit signal, send messagges, run/stop programs and more.
+Look at the @ref Group class to see all the methods and properties.
+
+Some object attributes return a table of values, the @ref Object attribute
+@a geometry for example return a table of 4 values (x,y,w,h). This tables don't
+have named index thus you can access the fields only using: geometry[1] for the
+x value. NOTE that you can NOT use gemetry.x or .geometry["x"]. But
+you can use the lua unpack function in this way:
+@code
+x, y, w, h = unpack(ed.part_name.geometry)
+print("geometry: ", x, y, w, h)
+// the same for state names:
+state, val = unpack(ed.part_name.state)
+print("state: ", state, val)
+// and for setting tables attributes:
+custom.color = { 255, 255, 255, 255 }
+ed.part_name.state = { 'custom', 0.0 }
+@endcode
+
+Classes hierarchy:
+- @ref Timer
+- @ref Animator
+- @ref Poller
+- @ref Object
+  - @ref Group
+  - @ref Part
+  - @ref Image
+  - @ref Line
+  - @ref Polygon
+  - @ref Table
+  - @ref Description
+
+References:
+@li For general LUA documentations look at the official LUA manual
+(http://www.lua.org/manual/5.1/)
+@li The lua-users wiki is also full of lua info (http://lua-users.org/wiki/)
+@li Examples of edc files that use LUA can be found in the doc/examples folder
+in the edje sources.
+
+Lua snippets:
+@code
+// print one or more values in console in a tabbed way or using printf style
+print("something to say", val1, val2)
+s = string.format("%d %d", 3, 4)
+print(s)
+
+// string concat
+print("string1" .. "string2" .. val1)
+// var to string
+tostring(var)
+// Print the type of a variable 
+print(type(var))
+
+@endcode
+
+*/
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <string.h>
+
+#ifdef HAVE_ALLOCA_H
+# include <alloca.h>
+#elif defined __GNUC__
+# define alloca __builtin_alloca
+#elif defined _AIX
+# define alloca __alloca
+#elif defined _MSC_VER
+# include <malloc.h>
+# define alloca _alloca
+#else
+# include <stddef.h>
+# ifdef  __cplusplus
+extern "C"
+# endif
+void *alloca(size_t);
+#endif
+
+#include "edje_private.h"
+
+#include <lauxlib.h>
+#include <lualib.h>
+
+#define EDJE_LUA_GET 1
+#define EDJE_LUA_SET 2
+#define EDJE_LUA_FN 3
+
+typedef struct _Edje_Lua_Alloc Edje_Lua_Alloc;
+
+typedef struct _Edje_Lua_Ref Edje_Lua_Ref;
+
+typedef struct _Edje_Lua_Reg Edje_Lua_Reg;
+
+typedef struct _Edje_Lua_Timer Edje_Lua_Timer;
+
+typedef struct _Edje_Lua_Animator Edje_Lua_Animator;
+
+typedef struct _Edje_Lua_Poller Edje_Lua_Poller;
+
+typedef struct _Edje_Lua_Transform Edje_Lua_Transform;
+
+typedef struct _Edje_Lua_Transition Edje_Lua_Transition;
+
+typedef struct _Edje_Lua_Evas_Object Edje_Lua_Evas_Object;
+
+typedef struct _Edje_Lua_Edje_Part_Object Edje_Lua_Edje_Part_Object;
+
+typedef struct _Edje_Lua_Edje_Part_Description Edje_Lua_Edje_Part_Description;
+
+struct _Edje_Lua_Alloc
+{
+   size_t max, cur; /* maximal and current memory used by Lua */
+};
+
+struct _Edje_Lua_Ref
+{
+   int id;
+   lua_State *L;
+};
+
+struct _Edje_Lua_Reg
+{
+   const luaL_Reg *mt, *get, *set, *fn;
+};
+
+struct _Edje_Lua_Timer
+{
+   lua_State *L;
+   Ecore_Timer *et;
+   Edje_Lua_Ref *cb;
+};
+
+struct _Edje_Lua_Animator
+{
+   lua_State *L;
+   Ecore_Animator *ea;
+   Edje_Lua_Ref *cb;
+};
+
+struct _Edje_Lua_Poller
+{
+   lua_State *L;
+   Ecore_Poller *ep;
+   Edje_Lua_Ref *cb;
+};
+
+struct _Edje_Lua_Transform
+{
+   lua_State *L;
+   Evas_Transform et;
+};
+
+struct _Edje_Lua_Transition
+{
+   lua_State *L;
+   Ecore_Timer *et;
+   Edje_Lua_Ref *trans;
+   Edje_Lua_Ref *cb;
+   Edje_Lua_Ref *ref;
+   double dur;
+};
+
+struct _Edje_Lua_Evas_Object
+{
+   lua_State *L;
+   Edje *ed;
+   Evas_Object *eo;
+   Eina_Bool mouse_events;
+   Eina_List *cb;
+};
+
+struct _Edje_Lua_Edje_Part_Object
+{
+   lua_State *L;
+   Edje *ed;
+   Evas_Object *eo;
+   Edje_Real_Part *rp;
+   const char *key;
+};
+
+struct _Edje_Lua_Edje_Part_Description
+{
+   lua_State *L;
+   Edje *ed;
+   Evas_Object *eo;
+   Edje_Real_Part *rp;
+   Edje_Part_Description *pd;
+};
+
+jmp_buf _edje_lua_panic_jmp;
+
+static int
+_edje_lua_custom_panic(lua_State *L)
+{
+   printf("PANIC\n");
+   longjmp(_edje_lua_panic_jmp, 1);
+   return 1; /* longjmp() never returns, but this keep gcc happy */
+}
+
+void
+__edje_lua_error(const char *file, const char *fnc, int line, lua_State *L, int err_code)
+{
+   char *err_type;
+
+   switch (err_code)
+     {
+     case LUA_ERRRUN:
+       err_type = "runtime";
+       break;
+     case LUA_ERRSYNTAX:
+       err_type = "syntax";
+       break;
+     case LUA_ERRMEM:
+       err_type = "memory allocation";
+       break;
+     case LUA_ERRERR:
+       err_type = "error handler";
+       break;
+     default:
+       err_type = "unknown";
+       break;
+     }
+   eina_log_print
+     (_edje_default_log_dom, EINA_LOG_LEVEL_ERR,  file, fnc, line,
+      "Lua %s error: %s", err_type, lua_tostring(L, -1));
+   // don't exit. this is BAD. lua script bugs will cause thngs like e to
+   // exit mysteriously endig your x session. bad!
+   // exit(-1);
+}
+
+lua_State *
+_edje_lua_new_thread(Edje *ed, lua_State *L)
+{
+#if 1 // newlua
+   lua_newtable(L);
+   ed->lua_ref = luaL_ref(L, LUA_REGISTRYINDEX);
+   /* inherit new environment from global environment */
+   lua_createtable(L, 1, 0);
+   lua_pushvalue(L, LUA_GLOBALSINDEX);
+   lua_setfield(L, -2, "__index");
+   lua_setmetatable(L, -2);
+   lua_setfenv(L, -2);
+   return L;
+#else
+   /* create new thread */
+   lua_State *thread = lua_newthread(L);
+   //printf ("new thread %d->%d\n", L, thread);
+   /* create new environment for new thread */
+   lua_newtable(L);
+   /* inherit new environment from global environment */
+   lua_createtable(L, 1, 0);
+   lua_pushvalue(L, LUA_GLOBALSINDEX);
+   lua_setfield(L, -2, "__index");
+   lua_setmetatable(L, -2);
+   lua_setfenv(L, -2);
+   return thread;
+#endif   
+}
+
+void
+_edje_lua_free_thread(Edje *ed, lua_State *L)
+{
+#if 1 // newlua
+   luaL_unref(L, LUA_REGISTRYINDEX, ed->lua_ref);
+   lua_gc(L, LUA_GCCOLLECT, 0);
+#else   
+   lua_pushthread(L);
+   lua_getfenv(L, -1);
+   lua_pushnil(L);
+   while (lua_next(L, -2))
+     {
+       // key at -2, value at -1
+       lua_pop(L, 1);
+       lua_pushvalue(L, -1);
+       lua_pushnil(L);
+       lua_rawset(L, -4);
+     }
+   lua_settop(L, 0);
+   lua_gc(L, LUA_GCCOLLECT, 0);
+#endif   
+}
+
+/*
+ * only for debug, returns number of objects in registry
+ */
+static int
+_edje_lua_reg_count (lua_State *L)
+{
+   int count = 0;
+   lua_pushvalue(L, LUA_REGISTRYINDEX);
+   lua_pushnil(L);
+   while (lua_next(L, -2))
+     {
+       // key at -2, value at -1
+       lua_pop(L, 1);
+       count++;
+     }
+   lua_pop(L, 1);
+   return count;
+}
+
+static Edje_Lua_Ref *
+_edje_lua_new_ref(lua_State *L, int index)
+{
+   //printf ("_edje_lua_new_ref %d %d %d\n", L, lua_objlen(L, LUA_REGISTRYINDEX), _edje_lua_reg_count(L));
+   lua_pushvalue(L, index);
+   Edje_Lua_Ref *ref = malloc(sizeof(Edje_Lua_Ref));
+   ref->id = luaL_ref(L, LUA_REGISTRYINDEX);
+   ref->L = L;
+   return ref;
+}
+
+static void
+_edje_lua_get_ref(lua_State *L, Edje_Lua_Ref *ref)
+{
+   lua_rawgeti(L, LUA_REGISTRYINDEX, ref->id);
+}
+
+static void
+_edje_lua_free_ref(lua_State *L, Edje_Lua_Ref *ref)
+{
+   //printf ("_edje_lua_free_ref %d %d %d\n", L, lua_objlen(L, LUA_REGISTRYINDEX), _edje_lua_reg_count(L));
+   luaL_unref(L, LUA_REGISTRYINDEX, ref->id);
+   free(ref);
+   lua_gc(L, LUA_GCCOLLECT, 0);
+}
+
+void
+_edje_lua_new_reg(lua_State *L, int index, void *ptr)
+{
+   //printf ("_edje_lua_new_reg %d %d %d\n", L, ptr, _edje_lua_reg_count(L));
+   lua_pushvalue(L, index);
+   lua_pushlightuserdata(L, ptr);
+   lua_insert(L, -2);
+   lua_rawset(L, LUA_REGISTRYINDEX); /* freed in _edje_lua_free_reg */
+}
+
+void
+_edje_lua_get_reg(lua_State *L, void *ptr)
+{
+   //printf ("_edje_lua_get_reg %d %d\n", L, ptr);
+   lua_pushlightuserdata(L, ptr);
+   lua_rawget(L, LUA_REGISTRYINDEX);
+}
+
+void
+_edje_lua_free_reg(lua_State *L, void *ptr)
+{
+   //printf ("_edje_lua_free_reg %d %d %d\n", L, ptr, _edje_lua_reg_count(L));
+   lua_pushlightuserdata(L, ptr);
+   lua_pushnil(L);
+   lua_rawset(L, LUA_REGISTRYINDEX); /* created in _edje_lua_new_reg */
+   lua_gc(L, LUA_GCCOLLECT, 0);
+}
+
+static void
+_edje_lua_rawsetfield(lua_State *L, int index, const char *key)
+{
+   lua_pushstring(L, key);
+   lua_insert(L, -2);
+   if (index < 0)
+      lua_rawset(L, index - 1);
+   else
+      lua_rawset(L, index);
+}
+
+static void
+_edje_lua_rawgetfield(lua_State *L, int index, const char *key)
+{
+   lua_pushstring(L, key);
+   if (index < 0)
+      lua_rawget(L, index - 1);
+   else
+      lua_rawget(L, index);
+}
+
+static void
+_edje_lua_new_const(lua_State *L, const char *id, int val)
+{
+   lua_pushnumber(L, val);
+   lua_setglobal(L, id);
+}
+
+static void
+_edje_lua_new_metatable(lua_State *L, const Edje_Lua_Reg ** class)
+{
+   lua_newtable(L);
+   lua_pushlightuserdata(L, class);
+   lua_pushvalue(L, -2);
+   lua_rawset(L, LUA_REGISTRYINDEX); /* freed in _edje_lua_free_metatable */
+   lua_pushvalue(L, -1);
+   lua_pushlightuserdata(L, class);
+   lua_rawset(L, LUA_REGISTRYINDEX); /* freed in _edje_lua_free_metatable */
+}
+
+static void
+_edje_lua_get_metatable(lua_State *L, const Edje_Lua_Reg ** class)
+{
+   lua_pushlightuserdata(L, class);
+   lua_rawget(L, LUA_REGISTRYINDEX);
+}
+
+static void
+_edje_lua_free_metatable(lua_State *L, const Edje_Lua_Reg ** class)
+{
+   lua_pushlightuserdata(L, class);
+   lua_rawget(L, LUA_REGISTRYINDEX);
+   lua_pushnil(L);
+   lua_rawset(L, LUA_REGISTRYINDEX); /* created in _edje_lua_new_metatable */
+   lua_pushlightuserdata(L, class);
+   lua_pushnil(L);
+   lua_rawset(L, LUA_REGISTRYINDEX); /* created in _edje_lua_new_metatable */
+   lua_gc(L, LUA_GCCOLLECT, 0);
+}
+
+static void *
+_edje_lua_checkudata(lua_State *L, int pos, const Edje_Lua_Reg * module)
+{
+   luaL_checktype(L, pos, LUA_TUSERDATA);
+   lua_getmetatable(L, pos);
+   lua_rawget(L, LUA_REGISTRYINDEX);
+   Edje_Lua_Reg **class = lua_touserdata(L, -1);
+   lua_pop(L, 1);              // class
+   int flag = 0;
+   int ptr = 0;
+   while (class[ptr] && !flag)
+      if (class[ptr++] == module)
+        flag = 1;
+   if (!flag)
+     {
+       lua_pushstring(L, "class type mismatch");
+       lua_error(L);
+     }
+   return lua_touserdata(L, pos);
+}
+
+static void
+_edje_lua_new_class(lua_State *L, const Edje_Lua_Reg ** class)
+{
+   int n = 0;
+   _edje_lua_new_metatable(L, class);
+   while (class && (class[n] != NULL))
+     {
+       luaL_register(L, NULL, class[n]->mt);
+       lua_pushstring(L, "hands off, it's none of your business!");
+       _edje_lua_rawsetfield(L, -2, "__metatable");
+
+       if (n == 0)
+         {
+            lua_newtable(L);
+            luaL_register(L, NULL, class[n]->set);
+            lua_rawseti (L, -2, EDJE_LUA_SET);
+
+            lua_newtable(L);
+            luaL_register(L, NULL, class[n]->get);
+            lua_rawseti (L, -2, EDJE_LUA_GET);
+
+            lua_newtable(L);
+            luaL_register(L, NULL, class[n]->fn);
+            lua_rawseti (L, -2, EDJE_LUA_FN);
+         }
+       else
+         {
+            lua_rawgeti(L, -1, EDJE_LUA_SET);
+            luaL_register(L, NULL, class[n]->set);
+            lua_pop(L, 1);
+
+            lua_rawgeti(L, -1, EDJE_LUA_GET);
+            luaL_register(L, NULL, class[n]->get);
+            lua_pop(L, 1);
+
+            lua_rawgeti(L, -1, EDJE_LUA_FN);
+            luaL_register(L, NULL, class[n]->fn);
+            lua_pop(L, 1);
+         }
+       n += 1;
+     }
+}
+
+static void
+_edje_lua_set_class(lua_State *L, int index, const Edje_Lua_Reg ** class)
+{
+   lua_newtable(L);
+   if (index < 0)
+      lua_setfenv(L, index - 1);
+   else
+      lua_setfenv(L, index);
+
+   _edje_lua_get_metatable(L, class);
+   if (index < 0)
+      lua_setmetatable(L, index - 1);
+   else
+      lua_setmetatable(L, index);
+}
+
+static int
+_edje_lua_look_fn(lua_State *L)
+{
+   lua_rawgeti(L, -1, EDJE_LUA_FN);
+   lua_pushvalue(L, 2);                // key
+   lua_rawget(L, -2);          // .fn[key]
+   if (lua_iscfunction(L, -1))
+      return 1;
+   else
+     {
+       lua_pop(L, 2);          // .fn[key], .fn
+       return 0;
+     }
+}
+
+static int
+_edje_lua_look_get(lua_State *L)
+{
+   lua_rawgeti(L, -1, EDJE_LUA_GET);
+   lua_pushvalue(L, 2);                // key
+   lua_rawget(L, -2);          // .get[key]
+   if (lua_iscfunction(L, -1))
+     {
+       int err_code;
+
+       lua_pushvalue(L, 1);
+
+       if ((err_code = lua_pcall(L, 1, 1, 0)))
+          _edje_lua_error(L, err_code);
+       return 1;
+     }
+   else
+     {
+       lua_pop(L, 2);          // .get[key], .get
+       return 0;
+     }
+}
+
+static int
+_edje_lua_look_set(lua_State *L)
+{
+   lua_rawgeti(L, -1, EDJE_LUA_SET);
+   lua_pushvalue(L, 2);                // key
+   lua_rawget(L, -2);          // .set[key]
+   if (lua_iscfunction(L, -1))
+     {
+       int err_code;
+
+       lua_pushvalue(L, 1);    // obj
+       lua_pushvalue(L, 3);    // value
+
+       if ((err_code = lua_pcall(L, 2, 0, 0))) // .set[key](obj,key,value)
+          _edje_lua_error(L, err_code);
+       return 1;
+     }
+   else
+     {
+       lua_pop(L, 2);          // .set[key], .set
+       return 0;
+     }
+}
+
+/*
+ * Lua Class bindings
+ */
+
+const luaL_Reg lNil[] = {
+   {NULL, NULL}                        // sentinel
+};
+
+const luaL_Reg lClass_mt[];
+
+const luaL_Reg lClass_fn[];
+
+const Edje_Lua_Reg mClass = {
+   lClass_mt,
+   lNil,
+   lNil,
+   lClass_fn
+};
+
+static int
+_edje_lua_class_mt_index(lua_State *L)
+{
+   _edje_lua_checkudata(L, 1, &mClass);
+   lua_getmetatable(L, 1);
+   if (!_edje_lua_look_fn(L))  // look in lClass_fn
+      if (!_edje_lua_look_get(L))      // look in lClass_get
+       {                       // look in obj ref hash
+          lua_getfenv(L, 1);
+          lua_pushvalue(L, 2); // key
+          lua_rawget(L, -2);
+       }
+   return 1;
+}
+
+static int
+_edje_lua_class_mt_newindex(lua_State *L)
+{
+   _edje_lua_checkudata(L, 1, &mClass);
+   lua_getmetatable(L, 1);
+   if (!_edje_lua_look_set(L)) // look in lClass_set
+     {                         // look in obj ref hash
+       lua_getfenv(L, 1);
+       lua_pushvalue(L, 2);
+       lua_pushvalue(L, 3);
+       lua_rawset(L, -3);
+     }
+   return 0;
+}
+
+static int
+_edje_lua_class_mt_gc(lua_State *L)
+{
+   _edje_lua_checkudata(L, 1, &mClass);
+   //printf("_edje_lua_class_mt_gc\n");
+   /* FIXME has to be commented to not raise an error, solve differently
+   lua_getfield(L, 1, "del");
+   if (!lua_isnil(L, -1))
+     {
+       lua_pushvalue(L, 1);
+       int err_code;
+
+       if (err_code = lua_pcall(L, 1, 0, 0))
+          _edje_lua_error(L, err_code);
+     }
+   lua_pop(L, 1);
+   */
+   return 0;
+}
+
+static int
+_edje_lua_class_fn_set(lua_State *L)
+{
+   _edje_lua_checkudata(L, 1, &mClass);
+   /*
+    * for k,v in pairs(table) do
+    *   obj[k] = v
+    * end
+    */
+   lua_pushnil(L);
+   while (lua_next(L, 2))
+     {
+       // key at -2, value at -1
+       lua_pushvalue(L, -2);
+       lua_insert(L, -2);
+       lua_settable(L, 1);
+     }
+   return 0;
+}
+
+static int
+_edje_lua_class_fn_get(lua_State *L)
+{
+   _edje_lua_checkudata(L, 1, &mClass);
+   /*
+    * res = {}
+    * mtG = getmetatable(obj)['.get']
+    * for k,v in pairs(mtG) do
+    *   res[k] = obj[k]
+    * end
+    */
+   lua_newtable(L);            // res
+   lua_getmetatable(L, 1);     // mt
+   lua_getfield(L, -1, ".get");
+   lua_remove(L, -2);          // mt
+
+   lua_pushnil(L);
+   while (lua_next(L, -2))
+     {
+       // key at -2, value at -1
+       lua_pop(L, 1);          // value = cfunction
+       lua_pushvalue(L, -1);   // key
+       lua_pushvalue(L, -1);   // key
+       lua_gettable(L, 1);     // obj[key]
+       lua_settable(L, 2);     // res[key]
+     }
+   lua_pop(L, 1);              // .get
+   return 1;
+}
+
+static int
+_edje_lua_class_itr_call(lua_State *L, int id)
+{
+   int err_code;
+
+   _edje_lua_checkudata(L, 1, &mClass);
+   lua_getmetatable(L, 1);     // mt
+   lua_rawgeti(L, -1, id);
+   lua_remove(L, -2);          // mt
+   lua_getglobal(L, "pairs");
+   lua_insert(L, -2);
+
+   if ((err_code = lua_pcall(L, 1, 3, 0)))
+      _edje_lua_error(L, err_code);
+   return 3;
+}
+
+static int
+_edje_lua_class_fn_gpairs(lua_State *L)
+{
+   _edje_lua_checkudata(L, 1, &mClass);
+   return _edje_lua_class_itr_call(L, EDJE_LUA_GET);
+}
+
+static int
+_edje_lua_class_fn_spairs(lua_State *L)
+{
+   _edje_lua_checkudata(L, 1, &mClass);
+   return _edje_lua_class_itr_call(L, EDJE_LUA_SET);
+}
+
+static int
+_edje_lua_class_fn_fpairs(lua_State *L)
+{
+   _edje_lua_checkudata(L, 1, &mClass);
+   return _edje_lua_class_itr_call(L, EDJE_LUA_FN);
+}
+
+static int
+_edje_lua_class_fn_pairs(lua_State *L)
+{
+   int err_code;
+
+   _edje_lua_checkudata(L, 1, &mClass);
+   lua_getfenv(L, 1);
+   lua_getglobal(L, "pairs");
+   lua_insert(L, -2);
+
+   if ((err_code = lua_pcall(L, 1, 3, 0)))
+      _edje_lua_error(L, err_code);
+   return 3;
+}
+
+static int
+_edje_lua_class_fn_ipairs(lua_State *L)
+{
+   int err_code;
+
+   _edje_lua_checkudata(L, 1, &mClass);
+   lua_getfenv(L, 1);
+   lua_getglobal(L, "ipairs");
+   lua_insert(L, -2);
+
+   if ((err_code = lua_pcall(L, 1, 3, 0)))
+      _edje_lua_error(L, err_code);
+   return 3;
+}
+
+const luaL_Reg lClass_mt[] = {
+   {"__index", _edje_lua_class_mt_index},
+   {"__newindex", _edje_lua_class_mt_newindex},
+   {"__gc", _edje_lua_class_mt_gc},
+   {NULL, NULL}                        // sentinel
+};
+
+const luaL_Reg lClass_fn[] = {
+   {"get", _edje_lua_class_fn_get},
+   {"set", _edje_lua_class_fn_set},
+   {"gpairs", _edje_lua_class_fn_gpairs},
+   {"spairs", _edje_lua_class_fn_spairs},
+   {"fpairs", _edje_lua_class_fn_fpairs},
+   {"pairs", _edje_lua_class_fn_pairs},
+   {"ipairs", _edje_lua_class_fn_ipairs},
+   {NULL, NULL}                        // sentinel
+};
+
+/**
+@page luaref
+@luaclass{Timer,Timer Class}
+
+The timer class is a wrapper around ecore_timer. You can create a timer using
+the @a timer(secs,callback) method of the @ref Group class.
+The callback function will be called every @a secs seconds until it will
+return CALLBACK_RENEW. If CALLBACK_CANCEL is returned the timer will stop.
+
+Example:
+@code
+lua_script {
+   function timer_cb()
+      print("timer_cb")
+      return CALLBACK_RENEW
+   end
+
+   timer = ed:timer(0.5, timer_cb)
+}
+@endcode
+
+A more detailed example can be found in doc/examples/lua_timer.edc
+
+@seealso{Ecore Timer Docs,http://docs.enlightenment.org/auto/ecore/group__Ecore__Timer__Group.html}
+*/
+
+const luaL_Reg lTimer_get[];
+
+const luaL_Reg lTimer_set[];
+
+const luaL_Reg lTimer_fn[];
+
+const Edje_Lua_Reg mTimer = {
+   lNil,
+   lTimer_get,
+   lTimer_set,
+   lTimer_fn
+};
+
+const Edje_Lua_Reg *cTimer[] = {
+   &mClass,
+   &mTimer,
+   NULL                                // sentinel
+};
+
+static int
+_edje_lua_timer_cb(void *data)
+{
+   Edje_Lua_Timer *obj = data;
+   lua_State *L = obj->L;
+   int err_code;
+   int res;
+
+   _edje_lua_get_ref(L, obj->cb);      // callback function
+   _edje_lua_get_reg(L, obj);
+
+   if ((err_code = lua_pcall(L, 1, 1, 0)))
+     {
+        _edje_lua_error(L, err_code);
+        return 0;
+     }
+
+   res = luaL_checkint(L, -1);
+   lua_pop(L, 1);              // -- res
+   
+/*   
+ if (_edje_lua_panic_here())
+ printf("blahc\n");
+ else
+ lua_pop(L, 1);                // -- res
+ */
+   if (res == ECORE_CALLBACK_CANCEL)
+     {
+       // delete object
+       _edje_lua_get_reg(L, obj);
+       lua_pushvalue(L, -1);
+       lua_pushstring(L, "del");
+       lua_gettable(L, -2);
+       lua_insert(L, -2);
+        if ((err_code = lua_pcall(L, 1, 0, 0)))
+          _edje_lua_error(L, err_code);
+     }
+   return res;
+}
+
+static int
+_edje_lua_timer_get_pending(lua_State *L)
+{
+   Edje_Lua_Timer *obj = _edje_lua_checkudata(L, 1, &mTimer);
+   if (obj->et)
+      lua_pushnumber(L, ecore_timer_pending_get(obj->et));
+   else
+      lua_pushnil(L);
+   return 1;
+}
+
+static int
+_edje_lua_timer_get_precision(lua_State *L)
+{
+   Edje_Lua_Timer *obj = _edje_lua_checkudata(L, 1, &mTimer);
+
+   if (obj->et)
+     lua_pushnumber(L, ecore_timer_precision_get());
+   else
+     lua_pushnil(L);
+   
+   return 1;
+}
+
+static int
+_edje_lua_timer_get_interval(lua_State *L)
+{
+   Edje_Lua_Timer *obj = _edje_lua_checkudata(L, 1, &mTimer);
+
+   if (obj->et)
+     lua_pushnumber(L, ecore_timer_interval_get(obj->et));
+   else
+     lua_pushnil(L);
+
+   return 1;
+}
+
+/**
+@page luaref
+@attributes
+@li Timer.pending
+@li Timer.precision
+@li Timer.interval
+*/
+const luaL_Reg lTimer_get[] = {
+   {"pending", _edje_lua_timer_get_pending},
+   {"precision", _edje_lua_timer_get_precision},
+   {"interval", _edje_lua_timer_get_interval},
+   {NULL, NULL}                        // sentinel
+};
+
+static int
+_edje_lua_timer_set_interval(lua_State *L)
+{
+   Edje_Lua_Timer *obj = _edje_lua_checkudata(L, 1, &mTimer);
+   if (obj->et)
+      ecore_timer_interval_set(obj->et, luaL_checknumber(L, 2));
+   return 0;
+}
+
+/**
+@page luaref
+@setters
+@li Timer.interval
+*/
+
+const luaL_Reg lTimer_set[] = {
+   {"interval", _edje_lua_timer_set_interval},
+   {NULL, NULL}                        // sentinel
+};
+
+static int
+_edje_lua_timer_fn_del(lua_State *L)
+{
+   Edje_Lua_Timer *obj = _edje_lua_checkudata(L, 1, &mTimer);
+   if (obj->et)
+     {
+       ecore_timer_del(obj->et);
+       obj->et = NULL;
+     }
+   if (obj->cb)
+     {
+       _edje_lua_free_ref(L, obj->cb); // created in _edje_lua_group_fn_timer
+       obj->cb = NULL;
+     }
+   _edje_lua_free_reg(L, obj); // created in _edje_lua_group_fn_timer
+   return 0;
+}
+
+static int
+_edje_lua_timer_fn_freeze(lua_State *L)
+{
+   Edje_Lua_Timer *obj = _edje_lua_checkudata(L, 1, &mTimer);
+   if (obj->et)
+      ecore_timer_freeze(obj->et);
+   return 0;
+}
+
+static int
+_edje_lua_timer_fn_thaw(lua_State *L)
+{
+   Edje_Lua_Timer *obj = _edje_lua_checkudata(L, 1, &mTimer);
+   if (obj->et)
+      ecore_timer_thaw(obj->et);
+   return 0;
+}
+
+static int
+_edje_lua_timer_fn_delay(lua_State *L)
+{
+   Edje_Lua_Timer *obj = _edje_lua_checkudata(L, 1, &mTimer);
+   if (obj->et)
+      ecore_timer_delay(obj->et, luaL_checknumber(L, 2));
+   return 0;
+}
+
+/**
+@page luaref
+@methods
+@li Timer:del()
+@li Timer:freeze()
+@li Timer:thaw()
+@li Timer:delay(secs)
+*/
+const luaL_Reg lTimer_fn[] = {
+   {"del", _edje_lua_timer_fn_del},
+   {"freeze", _edje_lua_timer_fn_freeze},
+   {"thaw", _edje_lua_timer_fn_thaw},
+   {"delay", _edje_lua_timer_fn_delay},
+   {NULL, NULL}                        // sentinel
+};
+
+/**
+@page luaref
+@luaclass{Animator,Animator Class}
+
+The animator class is a wrapper around ecore_animator. Animator are used the
+same way as @ref Timer.
+*/
+const luaL_Reg lAnimator_get[];
+
+const luaL_Reg lAnimator_fn[];
+
+const Edje_Lua_Reg mAnimator = {
+   lNil,
+   lAnimator_get,
+   lNil,
+   lAnimator_fn
+};
+
+const Edje_Lua_Reg *cAnimator[] = {
+   &mClass,
+   &mAnimator,
+   NULL                                // sentinel
+};
+
+static int
+_edje_lua_animator_cb(void *data)
+{
+   int err, res;
+   Edje_Lua_Animator *obj = data;
+   lua_State *L = obj->L;
+
+   _edje_lua_get_ref(L, obj->cb);
+   _edje_lua_get_reg(L, obj);
+
+   if ((err = lua_pcall(L, 1, 1, 0)))
+     {
+        _edje_lua_error(L, err);
+        return 0;
+     }
+
+   res = luaL_checkint(L, -1);
+   lua_pop(L, 1);              // Pop res off the stack
+   if (res == ECORE_CALLBACK_CANCEL)
+     {
+       /* delete animator */
+       _edje_lua_get_reg(L, obj);
+       lua_pushvalue(L, -1);
+       lua_pushstring(L, "del");
+       lua_gettable(L, -2);
+       lua_insert(L, -2);
+        if ((err = lua_pcall(L, 1, 0, 0)))
+          _edje_lua_error(L, err);
+     }
+
+   return res;
+}
+
+static int
+_edje_lua_animator_get_frametime(lua_State *L)
+{
+   Edje_Lua_Animator *obj = _edje_lua_checkudata(L, 1, &mAnimator);
+
+   if (obj->ea)
+     lua_pushnumber(L, ecore_animator_frametime_get());
+   else
+     lua_pushnil(L);
+
+   return 1;
+}
+
+/**
+@page luaref
+@attributes
+@li Animator.frametime
+*/
+const luaL_Reg lAnimator_get[] = {
+    {"frametime", _edje_lua_animator_get_frametime},
+    {NULL, NULL}
+};
+
+static int
+_edje_lua_animator_fn_del(lua_State *L)
+{
+   Edje_Lua_Animator *obj = _edje_lua_checkudata(L, 1, &mAnimator);
+   if (obj->ea)
+     {
+       ecore_animator_del(obj->ea);
+       obj->ea = NULL;
+     }
+   if (obj->cb)
+     {
+       _edje_lua_free_ref(L, obj->cb); // created in _edje_lua_group_fn_animator
+       obj->cb = NULL;
+     }
+   _edje_lua_free_reg(L, obj); // created in _edje_lua_group_fn_animator
+   return 0;
+}
+
+/**
+@page luaref
+@methods
+@li Animator:del()
+*/
+const luaL_Reg lAnimator_fn[] = {
+   {"del", _edje_lua_animator_fn_del},
+   {NULL, NULL}                        // sentinel
+};
+
+/**
+@page luaref
+@luaclass{Poller,Poller Class}
+
+The poller class is a wrapper around ecore_poller.
+
+*/
+const luaL_Reg lPoller_get[];
+
+const luaL_Reg lPoller_fn[];
+
+const Edje_Lua_Reg mPoller = {
+   lNil,
+   lPoller_get,
+   lNil,
+   lPoller_fn
+};
+
+const Edje_Lua_Reg *cPoller[] = {
+   &mClass,
+   &mPoller,
+   NULL                                // sentinel
+};
+
+static int
+_edje_lua_poller_cb(void *data)
+{
+   int err, res;
+   Edje_Lua_Poller *obj = data;
+   lua_State *L = obj->L;
+
+   _edje_lua_get_ref(L, obj->cb);
+   _edje_lua_get_reg(L, obj);
+
+   if ((err = lua_pcall(L, 1, 1, 0)))
+     {
+        _edje_lua_error(L, err);
+        return 0;
+     }
+
+   res = luaL_checkint(L, -1);
+   lua_pop(L, 1);              // Pop res off the stack
+   if (res == ECORE_CALLBACK_CANCEL)
+     {
+       /* delete poller */
+       _edje_lua_get_reg(L, obj);
+       lua_pushvalue(L, -1);
+       lua_pushstring(L, "del");
+       lua_gettable(L, -2);
+       lua_insert(L, -2);
+        if ((err = lua_pcall(L, 1, 0, 0)))
+          _edje_lua_error(L, err);
+     }
+
+   return res;
+}
+
+static int
+_edje_lua_poller_get_interval(lua_State *L)
+{
+   Edje_Lua_Poller *obj = _edje_lua_checkudata(L, 1, &mPoller);
+
+   if (obj->ep)
+     lua_pushnumber(L, ecore_poller_poll_interval_get(ECORE_POLLER_CORE));
+   else
+     lua_pushnil(L);
+
+   return 1;
+}
+
+/**
+@page luaref
+@attributes
+@li Poller.interval
+*/
+const luaL_Reg lPoller_get[] = {
+   {"interval", _edje_lua_poller_get_interval},
+   {NULL, NULL}
+};
+
+static int
+_edje_lua_poller_fn_del(lua_State *L)
+{
+   Edje_Lua_Poller *obj = _edje_lua_checkudata(L, 1, &mPoller);
+   if (obj->ep)
+     {
+       ecore_poller_del(obj->ep);
+       obj->ep = NULL;
+     }
+
+   if (obj->cb)
+     {
+       _edje_lua_free_ref(L, obj->cb); // created in _edje_lua_group_fn_poller
+       obj->cb = NULL;
+     }
+   _edje_lua_free_reg(L, obj); // created in _edje_lua_group_fn_poller
+
+   return 0;
+}
+
+/**
+@page luaref
+@methods
+@li Poller:del()
+*/
+const luaL_Reg lPoller_fn[] = {
+   {"del", _edje_lua_poller_fn_del},
+   {NULL, NULL}
+};
+
+/*
+ * Lua Edje Transform bindings
+ */
+
+const luaL_Reg lTransform_get[];
+
+const luaL_Reg lTransform_set[];
+
+const luaL_Reg lTransform_fn[];
+
+const Edje_Lua_Reg mTransform = {
+   lNil,
+   lTransform_get,
+   lTransform_set,
+   lTransform_fn
+};
+
+const Edje_Lua_Reg *cTransform[] = {
+   &mClass,
+   &mTransform,
+   NULL                                // sentinel
+};
+
+static int
+_edje_lua_transform_get_matrix(lua_State *L)
+{
+   Edje_Lua_Transform *obj = _edje_lua_checkudata(L, 1, &mTransform);
+   lua_createtable(L, 3, 0);
+      lua_createtable(L, 3, 0);
+        lua_pushnumber(L, obj->et.mxx); lua_rawseti(L, -2, 1);
+        lua_pushnumber(L, obj->et.mxy); lua_rawseti(L, -2, 2);
+        lua_pushnumber(L, obj->et.mxz); lua_rawseti(L, -2, 3);
+      lua_rawseti(L, -2, 1);
+      lua_createtable(L, 3, 0);
+        lua_pushnumber(L, obj->et.myx); lua_rawseti(L, -2, 1);
+        lua_pushnumber(L, obj->et.myy); lua_rawseti(L, -2, 2);
+        lua_pushnumber(L, obj->et.myz); lua_rawseti(L, -2, 3);
+      lua_rawseti(L, -2, 2);
+      lua_createtable(L, 3, 0);
+        lua_pushnumber(L, obj->et.mzx); lua_rawseti(L, -2, 1);
+        lua_pushnumber(L, obj->et.mzy); lua_rawseti(L, -2, 2);
+        lua_pushnumber(L, obj->et.mzz); lua_rawseti(L, -2, 3);
+      lua_rawseti(L, -2, 3);
+   return 1;
+}
+
+const luaL_Reg lTransform_get[] = {
+   {"matrix", _edje_lua_transform_get_matrix},
+   {NULL, NULL}                        // sentinel
+};
+
+static int
+_edje_lua_transform_set_matrix(lua_State *L)
+{
+   Edje_Lua_Transform *obj = _edje_lua_checkudata(L, 1, &mTransform);
+   luaL_checktype(L, 2, LUA_TTABLE);
+      lua_rawgeti(L, 2, 1);
+      luaL_checktype(L, -1, LUA_TTABLE);
+        lua_rawgeti(L, -1, 1); obj->et.mxx = luaL_checknumber(L, -1); lua_pop(L, 1);
+        lua_rawgeti(L, -1, 2); obj->et.mxy = luaL_checknumber(L, -1); lua_pop(L, 1);
+        lua_rawgeti(L, -1, 3); obj->et.mxz = luaL_checknumber(L, -1); lua_pop(L, 1);
+      lua_pop(L, 1);
+      lua_rawgeti(L, 2, 2);
+      luaL_checktype(L, -1, LUA_TTABLE);
+        lua_rawgeti(L, -1, 1); obj->et.myx = luaL_checknumber(L, -1); lua_pop(L, 1);
+        lua_rawgeti(L, -1, 2); obj->et.myy = luaL_checknumber(L, -1); lua_pop(L, 1);
+        lua_rawgeti(L, -1, 3); obj->et.myz = luaL_checknumber(L, -1); lua_pop(L, 1);
+      lua_pop(L, 1);
+      lua_rawgeti(L, 2, 3);
+      luaL_checktype(L, -1, LUA_TTABLE);
+        lua_rawgeti(L, -1, 1); obj->et.mzx = luaL_checknumber(L, -1); lua_pop(L, 1);
+        lua_rawgeti(L, -1, 2); obj->et.mzy = luaL_checknumber(L, -1); lua_pop(L, 1);
+        lua_rawgeti(L, -1, 3); obj->et.mzz = luaL_checknumber(L, -1); lua_pop(L, 1);
+      lua_pop(L, 1);
+   return 0;
+}
+
+const luaL_Reg lTransform_set[] = {
+   {"matrix", _edje_lua_transform_set_matrix},
+   {NULL, NULL}                        // sentinel
+};
+
+static int
+_edje_lua_transform_fn_identity(lua_State *L)
+{
+   Edje_Lua_Transform *obj = _edje_lua_checkudata(L, 1, &mTransform);
+   evas_transform_identity_set(&(obj->et));
+   return 0;
+}
+
+static int
+_edje_lua_transform_fn_rotate(lua_State *L)
+{
+   Edje_Lua_Transform *obj = _edje_lua_checkudata(L, 1, &mTransform);
+   evas_transform_rotate(luaL_checknumber(L, 2), &(obj->et));
+   return 0;
+}
+
+static int
+_edje_lua_transform_fn_translate(lua_State *L)
+{
+   Edje_Lua_Transform *obj = _edje_lua_checkudata(L, 1, &mTransform);
+   evas_transform_translate(luaL_checknumber(L, 2), luaL_checknumber(L, 3), &(obj->et));
+   return 0;
+}
+
+static int
+_edje_lua_transform_fn_scale(lua_State *L)
+{
+   Edje_Lua_Transform *obj = _edje_lua_checkudata(L, 1, &mTransform);
+   evas_transform_scale(luaL_checknumber(L, 2), luaL_checknumber(L, 3), &(obj->et));
+   return 0;
+}
+
+static int
+_edje_lua_transform_fn_shear(lua_State *L)
+{
+   Edje_Lua_Transform *obj = _edje_lua_checkudata(L, 1, &mTransform);
+   evas_transform_shear(luaL_checknumber(L, 2), luaL_checknumber(L, 3), &(obj->et));
+   return 0;
+}
+
+static int
+_edje_lua_transform_fn_compose(lua_State *L)
+{
+   Edje_Lua_Transform *obj = _edje_lua_checkudata(L, 1, &mTransform);
+   Edje_Lua_Transform *tar = _edje_lua_checkudata(L, 2, &mTransform);
+   evas_transform_compose(&(tar->et), &(obj->et));
+   return 0;
+}
+
+const luaL_Reg lTransform_fn[] = {
+   {"identity", _edje_lua_transform_fn_identity},
+   {"rotate", _edje_lua_transform_fn_rotate},
+   {"translate", _edje_lua_transform_fn_translate},
+   {"scale", _edje_lua_transform_fn_scale},
+   {"shear", _edje_lua_transform_fn_shear},
+   {"compose", _edje_lua_transform_fn_compose},
+   {NULL, NULL}                        // sentinel
+};
+
+/*
+ * Lua Edje Transition bindings
+ */
+
+const luaL_Reg lTransition_get[];
+
+const luaL_Reg lTransition_set[];
+
+const luaL_Reg lTransition_fn[];
+
+const Edje_Lua_Reg mTransition = {
+   lNil,
+   lTransition_get,
+   lTransition_set,
+   lTransition_fn
+};
+
+const Edje_Lua_Reg *cTransition[] = {
+   &mClass,
+   &mTransition,
+   NULL                                // sentinel
+};
+
+const luaL_Reg lTransition_get[] = {
+   {NULL, NULL}                        // sentinel
+};
+
+const luaL_Reg lTransition_set[] = {
+   {NULL, NULL}                        // sentinel
+};
+
+const luaL_Reg lTransition_fn[] = {
+   {NULL, NULL}                        // sentinel
+};
+
+/**
+@page luaref
+@luaclass{Object,General Object Class}
+
+This is the base class, many other classes are children of this.
+
+You can attach event callbacks to this class using a classic c approach:
+@code
+function mouse_move_cb(self, ...)
+    print("mouse_move", ...)
+end
+
+rect = ed:rectangle()
+rect.mouse_events = true
+rect.mouse_move = mouse_move_cb
+@endcode
+or you can also do the same in a more lua-fashion style
+@code
+rect = ed:rectangle {
+    mouse_events = true,
+    mouse_move = function (self, ...)
+                    print ('mouse_move', ...)
+                 end
+}
+@endcode
+
+
+@seealso{Evas Object Docs,http://docs.enlightenment.org/auto/evas/group__Evas__Object__Group.html}
+*/
+
+const luaL_Reg lObject_get[];
+
+const luaL_Reg lObject_set[];
+
+const luaL_Reg lObject_fn[];
+
+const Edje_Lua_Reg mObject = {
+   lNil,
+   lObject_get,
+   lObject_set,
+   lObject_fn
+};
+
+static void
+_edje_lua_object_del_cb(void *data, Evas * e, Evas_Object * obj,
+                       void *event_info)
+{
+   //printf("_edje_lua_object_delete_cb\n");
+   lua_State *L = data;
+   _edje_lua_get_reg(L, obj);
+   Edje_Lua_Evas_Object *udata = _edje_lua_checkudata(L, -1, &mObject);
+   lua_pop(L, 1);
+   _edje_lua_free_reg(L, udata); // created in EDJE_LUA_SCRIPT_FN_ADD
+   _edje_lua_free_reg(L, obj); // created in EDJE_LUA_SCRIPT_FN_ADD
+
+   Edje_Lua_Ref *ref;
+   EINA_LIST_FREE(udata->cb, ref)
+      _edje_lua_free_ref(L, ref);
+}
+
+static int
+_edje_lua_object_fn_del(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mObject);
+   
+   if (obj->eo)
+     {
+       evas_object_del(obj->eo);
+       obj->eo = NULL;
+       obj->ed = NULL;
+     }
+   return 0;
+}
+
+static int
+_edje_lua_object_fn_show(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mObject);
+   evas_object_show(obj->eo);
+   return 0;
+}
+
+static int
+_edje_lua_object_fn_hide(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mObject);
+   evas_object_hide(obj->eo);
+   return 0;
+}
+
+static int
+_edje_lua_object_fn_move(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mObject);
+   //printf ("%i %i %i %i\n", obj->ed->x, obj->ed->y, luaL_checkint (L, 2), luaL_checkint (L, 3));
+   evas_object_move(obj->eo,
+                   obj->ed->x + luaL_checkint(L, 2),
+                   obj->ed->y + luaL_checkint(L, 3));
+   return 0;
+}
+
+static int
+_edje_lua_object_fn_resize(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mObject);
+   evas_object_resize(obj->eo, luaL_checkint(L, 2), luaL_checkint(L, 3));
+   return 0;
+}
+
+static int
+_edje_lua_object_fn_raise(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mObject);
+   evas_object_raise(obj->eo);
+   return 0;
+}
+
+static int
+_edje_lua_object_fn_lower(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mObject);
+   evas_object_lower(obj->eo);
+   return 0;
+}
+
+static int
+_edje_lua_object_fn_stack_above(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mObject);
+   Edje_Lua_Evas_Object *tar = _edje_lua_checkudata(L, 2, &mObject);
+   evas_object_stack_above(obj->eo, tar->eo);
+   return 0;
+}
+
+static int
+_edje_lua_object_fn_stack_below(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mObject);
+   Edje_Lua_Evas_Object *tar = _edje_lua_checkudata(L, 2, &mObject);
+   evas_object_stack_below(obj->eo, tar->eo);
+   return 0;
+}
+
+static int
+_edje_lua_object_fn_clip_unset(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mObject);
+   evas_object_clip_unset(obj->eo);
+   return 0;
+}
+
+/**
+@page luaref
+@methods
+@li Object:del()
+@li Object:show()
+@li Object:hide()
+@li Object:move(x, y)
+@li Object:resize(w, h)
+@li Object:raise()
+@li Object:lower()
+@li Object:stack_above()
+@li Object:stack_below()
+@li Object:clip_unset()
+*/
+const luaL_Reg lObject_fn[] = {
+   {"del", _edje_lua_object_fn_del},
+   {"show", _edje_lua_object_fn_show},
+   {"hide", _edje_lua_object_fn_hide},
+   {"move", _edje_lua_object_fn_move},
+   {"resize", _edje_lua_object_fn_resize},
+   {"raise", _edje_lua_object_fn_raise},
+   {"lower", _edje_lua_object_fn_lower},
+   {"stack_above", _edje_lua_object_fn_stack_above},
+   {"stack_below", _edje_lua_object_fn_stack_below},
+   {"clip_unset", _edje_lua_object_fn_clip_unset},
+   {NULL, NULL}                        // sentinel
+};
+
+static int
+_edje_lua_object_get_name(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mObject);
+   lua_pushstring(L, evas_object_name_get(obj->eo));
+   return 1;
+}
+
+static int
+_edje_lua_object_get_geometry(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mObject);
+   int x, y, w, h;
+   evas_object_geometry_get(obj->eo, &x, &y, &w, &h);
+   lua_createtable(L, 4, 0);
+   lua_pushnumber(L, x);
+   lua_rawseti(L, -2, 1);
+   lua_pushnumber(L, y);
+   lua_rawseti(L, -2, 2);
+   lua_pushnumber(L, w);
+   lua_rawseti(L, -2, 3);
+   lua_pushnumber(L, h);
+   lua_rawseti(L, -2, 4);
+   return 1;
+}
+
+static int
+_edje_lua_object_get_type(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mObject);
+   lua_pushstring(L, evas_object_type_get(obj->eo));
+   return 1;
+}
+
+static int
+_edje_lua_object_get_layer(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mObject);
+   lua_pushnumber(L, evas_object_layer_get(obj->eo));
+   return 1;
+}
+
+static int
+_edje_lua_object_get_above(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mObject);
+   Evas_Object *above = evas_object_above_get(obj->eo);
+   _edje_lua_get_reg(L, above);
+   // TODO create object if it does not already exist?
+   return 1;
+}
+
+static int
+_edje_lua_object_get_below(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mObject);
+   Evas_Object *below = evas_object_below_get(obj->eo);
+   _edje_lua_get_reg(L, below);
+   // TODO create object if it does not already exist?
+   return 1;
+}
+
+static int
+_edje_lua_object_get_size_hint_min(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mObject);
+   int w, h;
+   evas_object_size_hint_min_get(obj->eo, &w, &h);
+   lua_createtable(L, 2, 0);
+   lua_pushnumber(L, w);
+   lua_rawseti(L, -2, 1);
+   lua_pushnumber(L, h);
+   lua_rawseti(L, -2, 2);
+   return 1;
+}
+
+static int
+_edje_lua_object_get_size_hint_max(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mObject);
+   int w, h;
+   evas_object_size_hint_max_get(obj->eo, &w, &h);
+   lua_createtable(L, 2, 0);
+   lua_pushnumber(L, w);
+   lua_rawseti(L, -2, 1);
+   lua_pushnumber(L, h);
+   lua_rawseti(L, -2, 2);
+   return 1;
+}
+
+static int
+_edje_lua_object_get_size_hint_request(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mObject);
+   int w, h;
+   evas_object_size_hint_request_get(obj->eo, &w, &h);
+   lua_createtable(L, 2, 0);
+   lua_pushnumber(L, w);
+   lua_rawseti(L, -2, 1);
+   lua_pushnumber(L, h);
+   lua_rawseti(L, -2, 2);
+   return 1;
+}
+
+static int
+_edje_lua_object_get_size_hint_aspect(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mObject);
+   Evas_Aspect_Control a;
+   int w, h;
+   evas_object_size_hint_aspect_get(obj->eo, &a, &w, &h);
+   lua_createtable(L, 3, 0);
+   lua_pushnumber(L, a);
+   lua_rawseti(L, -2, 1);
+   lua_pushnumber(L, w);
+   lua_rawseti(L, -2, 2);
+   lua_pushnumber(L, h);
+   lua_rawseti(L, -2, 3);
+   return 1;
+}
+
+static int
+_edje_lua_object_get_size_hint_align(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mObject);
+   double w, h;
+   evas_object_size_hint_align_get(obj->eo, &w, &h);
+   lua_createtable(L, 2, 0);
+   lua_pushnumber(L, w);
+   lua_rawseti(L, -2, 1);
+   lua_pushnumber(L, h);
+   lua_rawseti(L, -2, 2);
+   return 1;
+}
+
+static int
+_edje_lua_object_get_size_hint_weight(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mObject);
+   double w, h;
+   evas_object_size_hint_weight_get(obj->eo, &w, &h);
+   lua_createtable(L, 2, 0);
+   lua_pushnumber(L, w);
+   lua_rawseti(L, -2, 1);
+   lua_pushnumber(L, h);
+   lua_rawseti(L, -2, 2);
+   return 1;
+}
+
+static int
+_edje_lua_object_get_size_hint_padding(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mObject);
+   int l, r, t, b;
+   evas_object_size_hint_padding_get(obj->eo, &l, &r, &t, &b);
+   lua_createtable(L, 4, 0);
+   lua_pushnumber(L, l);
+   lua_rawseti(L, -2, 1);
+   lua_pushnumber(L, r);
+   lua_rawseti(L, -2, 2);
+   lua_pushnumber(L, t);
+   lua_rawseti(L, -2, 3);
+   lua_pushnumber(L, b);
+   lua_rawseti(L, -2, 4);
+   return 1;
+}
+
+static int
+_edje_lua_object_get_visible(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mObject);
+   lua_pushboolean(L, evas_object_visible_get(obj->eo));
+   return 1;
+}
+
+static int
+_edje_lua_object_get_render_op(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mObject);
+   lua_pushnumber(L, evas_object_render_op_get(obj->eo));
+   return 1;
+}
+
+static int
+_edje_lua_object_get_anti_alias(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mObject);
+   lua_pushboolean(L, evas_object_anti_alias_get(obj->eo));
+   return 1;
+}
+
+static int
+_edje_lua_object_get_scale(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mObject);
+   lua_pushnumber(L, evas_object_scale_get(obj->eo));
+   return 1;
+}
+
+static int
+_edje_lua_object_get_color(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mObject);
+   int r, g, b, a;
+   evas_object_color_get(obj->eo, &r, &g, &b, &a);
+   lua_createtable(L, 4, 0);
+   lua_pushnumber(L, r);
+   lua_rawseti(L, -2, 1);
+   lua_pushnumber(L, g);
+   lua_rawseti(L, -2, 2);
+   lua_pushnumber(L, b);
+   lua_rawseti(L, -2, 3);
+   lua_pushnumber(L, a);
+   lua_rawseti(L, -2, 4);
+   return 1;
+}
+
+static int
+_edje_lua_object_get_color_interpolation(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mObject);
+   lua_pushnumber(L, evas_object_color_interpolation_get(obj->eo));
+   return 1;
+}
+
+static int
+_edje_lua_object_get_clip(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mObject);
+   Evas_Object *clip = evas_object_clip_get(obj->eo);
+   _edje_lua_get_reg(L, clip);
+   // TODO create object if it does not already exist?
+   return 1;
+}
+
+static int
+_edje_lua_object_get_clipees(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mObject);
+   Eina_List *clipees = (Eina_List *) evas_object_clipees_get(obj->eo);
+   Eina_List *l;
+   Evas_Object *clip;
+   int i = 1;
+   lua_createtable(L, eina_list_count(clipees), 0);
+   EINA_LIST_FOREACH(clipees, l, clip)
+     {
+       _edje_lua_get_reg(L, clip);
+       // TODO create object if it does not already exist?
+       lua_rawseti(L, -2, i++);
+     }
+   return 1;
+}
+
+static int
+_edje_lua_object_get_evas(lua_State *L)
+{
+   //Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mObject);
+   lua_pushnil(L);
+   // FIXME implement Evas class in the first place?
+   return 1;
+}
+
+static int
+_edje_lua_object_get_pass_events(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mObject);
+   lua_pushboolean(L, evas_object_pass_events_get(obj->eo));
+   return 1;
+}
+
+static int
+_edje_lua_object_get_repeat_events(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mObject);
+   lua_pushboolean(L, evas_object_repeat_events_get(obj->eo));
+   return 1;
+}
+
+static int
+_edje_lua_object_get_propagate_events(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mObject);
+   lua_pushboolean(L, evas_object_propagate_events_get(obj->eo));
+   return 1;
+}
+
+static int
+_edje_lua_object_get_focus(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mObject);
+   lua_pushboolean(L, evas_object_focus_get(obj->eo));
+   return 1;
+}
+
+static int
+_edje_lua_object_get_pointer_mode(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mObject);
+   lua_pushnumber(L, evas_object_pointer_mode_get(obj->eo));
+   return 1;
+}
+
+static int
+_edje_lua_object_get_precise_is_inside(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mObject);
+   lua_pushboolean(L, evas_object_precise_is_inside_get(obj->eo));
+   return 1;
+}
+
+static int
+_edje_lua_object_get_mouse_events(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mObject);
+   lua_pushboolean(L, obj->mouse_events);
+   return 1;
+}
+
+/**
+@page luaref
+@attributes
+@li Object.name
+@li Object.geometry: (x, y, width, height)
+@li Object.type: object type (RECT=1, TEXT, IMAGE, SWALLOW, TEXTBLOCK, GRADIENT, GROUP, BOX, TABLE, EXTERNAL)
+@li Object.layer
+@li Object.above
+@li Object.below
+@li Object.size_hint_min: (w,h)
+@li Object.size_hint_max: (w,h)
+@li Object.size_hint_request: (w,h)
+@li Object.size_hint_aspect: (aspect, w, h)
+@li Object.size_hint_align: (w,h)
+@li Object.size_hint_weight: (w,h)
+@li Object.size_hint_padding: (l,r,t,b)
+@li Object.visible
+@li Object.render_op
+@li Object.anti_alias
+@li Object.scale
+@li Object.color: (r, g, b, alpha)
+@li Object.color_interpolation
+@li Object.clip
+@li Object.clipees
+@li Object.evas (not implemeted, always return nil)
+@li Object.pass_events
+@li Object.repeat_events
+@li Object.propagate_events
+@li Object.focus
+@li Object.pointer_mode
+@li Object.precise_is_inside
+@li Object.mouse_events
+*/
+const luaL_Reg lObject_get[] = {
+   {"name", _edje_lua_object_get_name},
+   {"geometry", _edje_lua_object_get_geometry},
+   {"type", _edje_lua_object_get_type},
+   {"layer", _edje_lua_object_get_layer},
+   {"above", _edje_lua_object_get_above},
+   {"below", _edje_lua_object_get_below},
+   {"size_hint_min", _edje_lua_object_get_size_hint_min},
+   {"size_hint_max", _edje_lua_object_get_size_hint_max},
+   {"size_hint_request", _edje_lua_object_get_size_hint_request},
+   {"size_hint_aspect", _edje_lua_object_get_size_hint_aspect},
+   {"size_hint_align", _edje_lua_object_get_size_hint_align},
+   {"size_hint_weight", _edje_lua_object_get_size_hint_weight},
+   {"size_hint_padding", _edje_lua_object_get_size_hint_padding},
+   {"visible", _edje_lua_object_get_visible},
+   {"render_op", _edje_lua_object_get_render_op},
+   {"anti_alias", _edje_lua_object_get_anti_alias},
+   {"scale", _edje_lua_object_get_scale},
+   {"color", _edje_lua_object_get_color},
+   {"color_interpolation", _edje_lua_object_get_color_interpolation},
+   {"clip", _edje_lua_object_get_clip},
+   {"clipees", _edje_lua_object_get_clipees},
+   {"evas", _edje_lua_object_get_evas},
+   {"pass_events", _edje_lua_object_get_pass_events},
+   {"repeat_events", _edje_lua_object_get_repeat_events},
+   {"propagate_events", _edje_lua_object_get_propagate_events},
+   {"focus", _edje_lua_object_get_focus},
+   {"pointer_mode", _edje_lua_object_get_pointer_mode},
+   {"precise_is_inside", _edje_lua_object_get_precise_is_inside},
+   {"mouse_events", _edje_lua_object_get_mouse_events},
+   {NULL, NULL}                        // sentinel
+};
+
+static int
+_edje_lua_object_set_name(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mObject);
+   evas_object_name_set(obj->eo, luaL_checkstring(L, 2));
+   return 0;
+}
+
+static int
+_edje_lua_object_set_layer(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mObject);
+   evas_object_layer_set(obj->eo, luaL_checkint(L, 2));
+   return 0;
+}
+
+static int
+_edje_lua_object_set_size_hint_min(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mObject);
+   luaL_checktype(L, 2, LUA_TTABLE);
+   lua_rawgeti(L, 2, 1);
+   lua_rawgeti(L, 2, 2);
+   evas_object_size_hint_min_set(obj->eo,
+        luaL_checkint(L, -2),
+        luaL_checkint(L, -1));
+   return 0;
+}
+
+static int
+_edje_lua_object_set_size_hint_max(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mObject);
+   luaL_checktype(L, 2, LUA_TTABLE);
+   lua_rawgeti(L, 2, 1);
+   lua_rawgeti(L, 2, 2);
+   evas_object_size_hint_max_set(obj->eo,
+        luaL_checkint(L, -2),
+        luaL_checkint(L, -1));
+   return 0;
+}
+
+static int
+_edje_lua_object_set_size_hint_request(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mObject);
+   luaL_checktype(L, 2, LUA_TTABLE);
+   lua_rawgeti(L, 2, 1);
+   lua_rawgeti(L, 2, 2);
+   evas_object_size_hint_request_set(obj->eo,
+        luaL_checkint(L, -2),
+        luaL_checkint(L, -1));
+   return 0;
+}
+
+static int
+_edje_lua_object_set_size_hint_aspect(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mObject);
+   luaL_checktype(L, 2, LUA_TTABLE);
+   lua_rawgeti(L, 2, 1);
+   lua_rawgeti(L, 2, 2);
+   lua_rawgeti(L, 2, 3);
+   evas_object_size_hint_aspect_set(obj->eo,
+        luaL_checkint(L, -3),
+        luaL_checkint(L, -2),
+        luaL_checkint(L, -1));
+   return 0;
+}
+
+static int
+_edje_lua_object_set_size_hint_align(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mObject);
+   luaL_checktype(L, 2, LUA_TTABLE);
+   lua_rawgeti(L, 2, 1);
+   lua_rawgeti(L, 2, 2);
+   evas_object_size_hint_align_set(obj->eo,
+        luaL_checknumber(L, -2),
+        luaL_checknumber(L, -1));
+   return 0;
+}
+
+static int
+_edje_lua_object_set_size_hint_weight(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mObject);
+   luaL_checktype(L, 2, LUA_TTABLE);
+   lua_rawgeti(L, 2, 1);
+   lua_rawgeti(L, 2, 2);
+   evas_object_size_hint_weight_set(obj->eo,
+        luaL_checknumber(L, -2),
+        luaL_checknumber(L, -1));
+   return 0;
+}
+
+static int
+_edje_lua_object_set_size_hint_padding(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mObject);
+   luaL_checktype(L, 2, LUA_TTABLE);
+   lua_rawgeti(L, 2, 1);
+   lua_rawgeti(L, 2, 2);
+   lua_rawgeti(L, 2, 3);
+   lua_rawgeti(L, 2, 4);
+   evas_object_size_hint_padding_set(obj->eo,
+        luaL_checknumber(L, -4),
+        luaL_checknumber(L, -3),
+        luaL_checknumber(L, -2),
+        luaL_checknumber(L, -1));
+   return 0;
+}
+
+static int
+_edje_lua_object_set_render_op(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mObject);
+   evas_object_render_op_set(obj->eo, luaL_checkint(L, 2));
+   return 0;
+}
+
+static int
+_edje_lua_object_set_anti_alias(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mObject);
+   evas_object_anti_alias_set(obj->eo, lua_toboolean(L, 2));
+   return 0;
+}
+
+static int
+_edje_lua_object_set_scale(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mObject);
+   evas_object_scale_set(obj->eo, luaL_checknumber(L, 2));
+   return 0;
+}
+
+static int
+_edje_lua_object_set_color(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mObject);
+   luaL_checktype(L, 2, LUA_TTABLE);
+   lua_rawgeti(L, 2, 1);
+   lua_rawgeti(L, 2, 2);
+   lua_rawgeti(L, 2, 3);
+   lua_rawgeti(L, 2, 4);
+   evas_object_color_set(obj->eo,
+        luaL_checkint(L, -4),
+        luaL_checkint(L, -3),
+        luaL_checkint(L, -2),
+        luaL_checkint(L, -1));
+   return 0;
+}
+
+static int
+_edje_lua_object_set_color_interpolation(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mObject);
+   evas_object_color_interpolation_set(obj->eo, luaL_checkint(L, 2));
+   return 0;
+}
+
+static int
+_edje_lua_object_set_clip(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mObject);
+   Edje_Lua_Evas_Object *clip = _edje_lua_checkudata(L, 2, &mObject);
+   evas_object_clip_set(obj->eo, clip->eo);
+   return 0;
+}
+
+static int
+_edje_lua_object_set_pass_events(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mObject);
+   evas_object_pass_events_set(obj->eo, lua_toboolean(L, 2));
+   return 0;
+}
+
+static int
+_edje_lua_object_set_repeat_events(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mObject);
+   evas_object_repeat_events_set(obj->eo, lua_toboolean(L, 2));
+   return 0;
+}
+
+static int
+_edje_lua_object_set_propagate_events(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mObject);
+   evas_object_propagate_events_set(obj->eo, lua_toboolean(L, 2));
+   return 0;
+}
+
+static int
+_edje_lua_object_set_focus(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mObject);
+   evas_object_focus_set(obj->eo, lua_toboolean(L, 2));
+   return 0;
+}
+
+static int
+_edje_lua_object_set_pointer_mode(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mObject);
+   evas_object_pointer_mode_set(obj->eo, luaL_checkint(L, 2));
+   return 0;
+}
+
+static int
+_edje_lua_object_set_precise_is_inside(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mObject);
+   evas_object_precise_is_inside_set(obj->eo, lua_toboolean(L, 2));
+   return 0;
+}
+
+#define OBJECT_CB_MACRO(KEY) \
+   lua_State *L = data; \
+   _edje_lua_get_reg(L, obj); \
+   lua_getfield(L, -1, KEY); \
+   if (lua_type(L, -1) != LUA_TFUNCTION) \
+      { \
+        lua_pop(L, 2); \
+        return; \
+      } \
+   lua_insert(L, -2);
+
+static void
+_edje_lua_object_cb_mouse_in(void *data, Evas * e, Evas_Object * obj,
+                            void *event_info)
+{
+   OBJECT_CB_MACRO("mouse_in");
+   Evas_Event_Mouse_In * ev = event_info;
+   int err_code;
+
+   lua_pushnumber(L, ev->output.x);
+   lua_pushnumber(L, ev->output.y);
+   lua_pushnumber(L, ev->canvas.x);
+   lua_pushnumber(L, ev->canvas.y);
+
+   if ((err_code = lua_pcall(L, 5, 0, 0)))
+     _edje_lua_error(L, err_code);
+}
+
+static void
+_edje_lua_object_cb_mouse_out(void *data, Evas * e, Evas_Object * obj,
+                             void *event_info)
+{
+   OBJECT_CB_MACRO("mouse_out");
+   Evas_Event_Mouse_In * ev = event_info;
+   int err_code;
+
+   lua_pushnumber(L, ev->output.x);
+   lua_pushnumber(L, ev->output.y);
+   lua_pushnumber(L, ev->canvas.x);
+   lua_pushnumber(L, ev->canvas.y);
+
+   if ((err_code = lua_pcall(L, 5, 0, 0)))
+     _edje_lua_error(L, err_code);
+}
+
+static void
+_edje_lua_object_cb_mouse_down(void *data, Evas * e, Evas_Object * obj,
+                              void *event_info)
+{
+   OBJECT_CB_MACRO("mouse_down");
+   Evas_Event_Mouse_Down * ev = event_info;
+   int err_code;
+
+   lua_pushnumber(L, ev->button);
+   lua_pushnumber(L, ev->output.x);
+   lua_pushnumber(L, ev->output.y);
+   lua_pushnumber(L, ev->canvas.x);
+   lua_pushnumber(L, ev->canvas.y);
+
+   if ((err_code = lua_pcall(L, 6, 0, 0)))
+     _edje_lua_error(L, err_code);
+}
+
+static void
+_edje_lua_object_cb_mouse_up(void *data, Evas * e, Evas_Object * obj,
+                            void *event_info)
+{
+   OBJECT_CB_MACRO("mouse_up");
+   Evas_Event_Mouse_Up * ev = event_info;
+   int err_code;
+
+   lua_pushnumber(L, ev->button);
+   lua_pushnumber(L, ev->output.x);
+   lua_pushnumber(L, ev->output.y);
+   lua_pushnumber(L, ev->canvas.x);
+   lua_pushnumber(L, ev->canvas.y);
+
+   if ((err_code = lua_pcall(L, 6, 0, 0)))
+     _edje_lua_error(L, err_code);
+}
+
+static void
+_edje_lua_object_cb_mouse_move(void *data, Evas * e, Evas_Object * obj,
+                              void *event_info)
+{
+   OBJECT_CB_MACRO("mouse_move");
+   Evas_Event_Mouse_Move * ev = event_info;
+   int err_code;
+
+   lua_pushnumber(L, ev->buttons);
+   lua_pushnumber(L, ev->cur.output.x);
+   lua_pushnumber(L, ev->cur.output.y);
+   lua_pushnumber(L, ev->cur.canvas.x);
+   lua_pushnumber(L, ev->cur.canvas.y);
+
+   if ((err_code = lua_pcall(L, 6, 0, 0)))
+     _edje_lua_error(L, err_code);
+}
+
+static void
+_edje_lua_object_cb_mouse_wheel(void *data, Evas * e, Evas_Object * obj,
+                              void *event_info)
+{
+   OBJECT_CB_MACRO("mouse_wheel");
+   Evas_Event_Mouse_Wheel * ev = event_info;
+   int err_code;
+
+   lua_pushnumber(L, ev->z);
+   lua_pushnumber(L, ev->output.x);
+   lua_pushnumber(L, ev->output.y);
+   lua_pushnumber(L, ev->canvas.x);
+   lua_pushnumber(L, ev->canvas.y);
+
+   if ((err_code = lua_pcall(L, 6, 0, 0)))
+     _edje_lua_error(L, err_code);
+}
+
+static int
+_edje_lua_object_set_mouse_events(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mObject);
+   obj->mouse_events = lua_toboolean(L, 2);
+   if (obj->mouse_events)
+     {
+       // add all mouse events
+       evas_object_event_callback_add(obj->eo, EVAS_CALLBACK_MOUSE_IN, _edje_lua_object_cb_mouse_in, L);
+       evas_object_event_callback_add(obj->eo, EVAS_CALLBACK_MOUSE_OUT, _edje_lua_object_cb_mouse_out, L);
+       evas_object_event_callback_add(obj->eo, EVAS_CALLBACK_MOUSE_DOWN, _edje_lua_object_cb_mouse_down, L);
+       evas_object_event_callback_add(obj->eo, EVAS_CALLBACK_MOUSE_UP, _edje_lua_object_cb_mouse_up, L);
+       evas_object_event_callback_add(obj->eo, EVAS_CALLBACK_MOUSE_MOVE, _edje_lua_object_cb_mouse_move, L);
+       evas_object_event_callback_add(obj->eo, EVAS_CALLBACK_MOUSE_WHEEL, _edje_lua_object_cb_mouse_wheel, L);
+     }
+   else
+     {
+       // delete all mouse events
+       evas_object_event_callback_del(obj->eo, EVAS_CALLBACK_MOUSE_IN, _edje_lua_object_cb_mouse_in);
+       evas_object_event_callback_del(obj->eo, EVAS_CALLBACK_MOUSE_OUT, _edje_lua_object_cb_mouse_out);
+       evas_object_event_callback_del(obj->eo, EVAS_CALLBACK_MOUSE_DOWN, _edje_lua_object_cb_mouse_down);
+       evas_object_event_callback_del(obj->eo, EVAS_CALLBACK_MOUSE_UP, _edje_lua_object_cb_mouse_up);
+       evas_object_event_callback_del(obj->eo, EVAS_CALLBACK_MOUSE_MOVE, _edje_lua_object_cb_mouse_move);
+       evas_object_event_callback_del(obj->eo, EVAS_CALLBACK_MOUSE_WHEEL, _edje_lua_object_cb_mouse_wheel);
+     }
+   return 0;
+}
+
+/**
+@page luaref
+@setters
+@li Object.name
+@li Object.layer
+@li Object.size_hint_min: (w,h)
+@li Object.size_hint_max: (w,h)
+@li Object.size_hint_request: (w,h)
+@li Object.size_hint_aspect: (w,h)
+@li Object.size_hint_align: (w,h)
+@li Object.size_hint_weight: (w,h)
+@li Object.size_hint_padding: (l,r,t,b)
+@li Object.render_op
+@li Object.anti_alias
+@li Object.scale
+@li Object.color: (r, g, b, alpha)
+@li Object.color_interpolation
+@li Object.clip
+@li Object.pass_events
+@li Object.repeat_events
+@li Object.propagate_events
+@li Object.focus
+@li Object.pointer_mode
+@li Object.precise_is_inside
+@li Object.mouse_events
+*/
+const luaL_Reg lObject_set[] = {
+   {"name", _edje_lua_object_set_name},
+   {"layer", _edje_lua_object_set_layer},
+   {"size_hint_min", _edje_lua_object_set_size_hint_min},
+   {"size_hint_max", _edje_lua_object_set_size_hint_max},
+   {"size_hint_request", _edje_lua_object_set_size_hint_request},
+   {"size_hint_aspect", _edje_lua_object_set_size_hint_aspect},
+   {"size_hint_align", _edje_lua_object_set_size_hint_align},
+   {"size_hint_weight", _edje_lua_object_set_size_hint_weight},
+   {"size_hint_padding", _edje_lua_object_set_size_hint_padding},
+   {"render_op", _edje_lua_object_set_render_op},
+   {"anti_alias", _edje_lua_object_set_anti_alias},
+   {"scale", _edje_lua_object_set_scale},
+   {"color", _edje_lua_object_set_color},
+   {"color_interpolation", _edje_lua_object_set_color_interpolation},
+   {"clip", _edje_lua_object_set_clip},
+   {"pass_events", _edje_lua_object_set_pass_events},
+   {"repeat_events", _edje_lua_object_set_repeat_events},
+   {"propagate_events", _edje_lua_object_set_propagate_events},
+   {"focus", _edje_lua_object_set_focus},
+   {"pointer_mode", _edje_lua_object_get_pointer_mode},
+   {"precise_is_inside", _edje_lua_object_get_precise_is_inside},
+   {"mouse_events", _edje_lua_object_set_mouse_events},
+   {NULL, NULL}                        // sentinel
+};
+/**
+@page luaref
+@events
+@li Object.mouse_in: func(self,output_x,output_y,canvas_x,canvas_y)
+@li Object.mouse_out: func(self,output_x,output_y,canvas_x,canvas_y)
+@li Object.mouse_down: func(self,button,output_x,output_y,canvas_x,canvas_y)
+@li Object.mouse_up: func(self,button,output_x,output_y,canvas_x,canvas_y)
+@li Object.mouse_move: func(self,buttons,output_x,output_y,canvas_x,canvas_y)
+@li Object.mouse_wheel: func(self,z,output_x,output_y,canvas_x,canvas_y)
+*/
+
+const Edje_Lua_Reg *cRectangle[] = {
+   &mClass,
+   &mObject,
+   NULL                                // sentinel
+};
+
+/**
+@page luaref
+@luaclass{Image,Image Class}
+@seealso{Evas Object Image Docs,http://docs.enlightenment.org/auto/evas/group__Evas__Object__Image.html}
+*/
+const luaL_Reg lImage_get[];
+
+const luaL_Reg lImage_set[];
+
+const Edje_Lua_Reg mImage = {
+   lNil,
+   lImage_get,
+   lImage_set,
+   lNil
+};
+
+const Edje_Lua_Reg *cImage[] = {
+   &mClass,
+   &mObject,
+   &mImage,
+   NULL                                // sentinel
+};
+
+static int
+_edje_lua_image_get_size(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mImage);
+   int w, h;
+   evas_object_image_size_get(obj->eo, &w, &h);
+   lua_createtable(L, 2, 0);
+   lua_pushnumber(L, w);
+   lua_rawseti(L, -2, 1);
+   lua_pushnumber(L, h);
+   lua_rawseti(L, -2, 2);
+   return 1;
+};
+
+/**
+@page luaref
+@attributes
+@li Image.size: (w,h)
+*/
+const luaL_Reg lImage_get[] = {
+   {"size", _edje_lua_image_get_size},
+   {NULL, NULL}                        // sentinel
+};
+
+static int
+_edje_lua_image_set_file(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mImage);
+   int id = edje_edit_image_id_get(obj->ed->obj, luaL_checkstring(L, 2));
+   char buf[256];
+   sprintf(buf, "images/%i", id);
+   evas_object_image_file_set(obj->eo, obj->ed->path, buf);
+   return 0;
+}
+
+static int
+_edje_lua_image_set_fill(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mImage);
+   luaL_checktype(L, 2, LUA_TTABLE);
+   lua_rawgeti(L, 2, 1);
+   lua_rawgeti(L, 2, 2);
+   lua_rawgeti(L, 2, 3);
+   lua_rawgeti(L, 2, 4);
+   evas_object_image_fill_set(obj->eo,
+                             luaL_checkint(L, -4),
+                             luaL_checkint(L, -3),
+                             luaL_checkint(L, -2), luaL_checkint(L, -1));
+   return 0;
+}
+
+static int
+_edje_lua_image_set_fill_transform(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mImage);
+   Edje_Lua_Transform *tar = _edje_lua_checkudata(L, 2, &mTransform);
+   evas_object_image_fill_transform_set(obj->eo, &(tar->et));
+   return 0;
+}
+
+static int
+_edje_lua_image_set_alpha(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mObject);
+   evas_object_image_alpha_set(obj->eo, lua_toboolean(L, 2));
+   return 0;
+}
+
+/**
+@page luaref
+@setters
+@li Image.file
+@li Image.fill: (x,y,w,h)
+@li Image.fill_transform
+@li Image.alpha
+*/
+const luaL_Reg lImage_set[] = {
+   {"file", _edje_lua_image_set_file},
+   {"fill", _edje_lua_image_set_fill},
+   {"fill_transform", _edje_lua_image_set_fill_transform},
+   {"alpha", _edje_lua_image_set_alpha},
+   {NULL, NULL}                        // sentinel
+};
+
+/**
+@page luaref
+@luaclass{Line,Line Class}
+@seealso{Evas Object Line Docs,http://docs.enlightenment.org/auto/evas/group__Evas__Line__Group.html}
+*/
+const luaL_Reg lLine_get[];
+const luaL_Reg lLine_set[];
+
+const Edje_Lua_Reg mLine = {
+   lNil,
+   lLine_get,
+   lLine_set,
+   lNil
+};
+
+const Edje_Lua_Reg *cLine[] = {
+   &mClass,
+   &mObject,
+   &mLine,
+   NULL                                // sentinel
+};
+
+static int
+_edje_lua_line_get_xy(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mLine);
+   int x1, y1, x2, y2;
+   evas_object_line_xy_get(obj->eo, &x1, &y1, &x2, &y2);
+   lua_createtable(L, 4, 0);
+   lua_pushnumber(L, x1); lua_rawseti(L, -2, 1);
+   lua_pushnumber(L, y1); lua_rawseti(L, -2, 2);
+   lua_pushnumber(L, x2); lua_rawseti(L, -2, 3);
+   lua_pushnumber(L, y2); lua_rawseti(L, -2, 4);
+   return 1;
+}
+
+/**
+@page luaref
+@attributes
+@li Line.xy: (x1,y1,x2,y2)
+*/
+const luaL_Reg lLine_get[] = {
+   {"xy", _edje_lua_line_get_xy},
+   {NULL, NULL}                        // sentinel
+};
+
+static int
+_edje_lua_line_set_xy(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mLine);
+   luaL_checktype(L, 2, LUA_TTABLE);
+   lua_rawgeti(L, 2, 1);
+   lua_rawgeti(L, 2, 2);
+   lua_rawgeti(L, 2, 3);
+   lua_rawgeti(L, 2, 4);
+   evas_object_line_xy_set(obj->eo,
+                           luaL_checkint(L, -4),
+                           luaL_checkint(L, -3),
+                           luaL_checkint(L, -2),
+                           luaL_checkint(L, -1));
+   return 0;
+}
+
+/**
+@page luaref
+@setters
+@li Line.xy: (x1,y1,x2,y2)
+*/
+const luaL_Reg lLine_set[] = {
+   {"xy", _edje_lua_line_set_xy},
+   {NULL, NULL}                        // sentinel
+};
+
+/**
+@page luaref
+@luaclass{Polygon,Polygon Class}
+@seealso{Evas Object Polygon Docs,http://docs.enlightenment.org/auto/evas/group__Evas__Object__Polygon.html}
+*/
+const luaL_Reg lPolygon_fn[];
+
+const Edje_Lua_Reg mPolygon = {
+   lNil,
+   lNil,
+   lNil,
+   lPolygon_fn
+};
+
+const Edje_Lua_Reg *cPolygon[] = {
+   &mClass,
+   &mObject,
+   &mPolygon,
+   NULL                                // sentinel
+};
+
+static int
+_edje_lua_polygon_fn_point_add(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mPolygon);
+   evas_object_polygon_point_add(obj->eo,
+                                luaL_checknumber(L, 2),
+                                luaL_checknumber(L, 3));
+   return 0;
+}
+
+static int
+_edje_lua_polygon_fn_points_clear(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mPolygon);
+   evas_object_polygon_points_clear(obj->eo);
+   return 0;
+}
+
+/**
+@page luaref
+@methods
+@li Polygon:point_add(x,y)
+@li Polygon:points_clear()
+*/
+const luaL_Reg lPolygon_fn[] = {
+   {"point_add", _edje_lua_polygon_fn_point_add},
+   {"points_clear", _edje_lua_polygon_fn_points_clear},
+   {NULL, NULL}                        // sentinel
+};
+
+/**
+@page luaref
+@luaclass{Table,Table Class}
+@seealso{Evas Object Table Docs,http://docs.enlightenment.org/auto/evas/group__Evas__Object__Table.html}
+*/
+const luaL_Reg lTable_get[];
+
+const luaL_Reg lTable_set[];
+
+const luaL_Reg lTable_fn[];
+
+const Edje_Lua_Reg mTable = {
+   lNil,
+   lTable_get,
+   lTable_set,
+   lTable_fn
+};
+
+const Edje_Lua_Reg *cTable[] = {
+   &mClass,
+   &mObject,
+   &mTable,
+   NULL                                // sentinel
+};
+
+static int
+_edje_lua_table_get_homogeneous(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mTable);
+   lua_pushnumber(L, evas_object_table_homogeneous_get(obj->eo));
+   return 1;
+}
+
+static int
+_edje_lua_table_get_padding(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mTable);
+   int x, y;
+   evas_object_table_padding_get(obj->eo, &x, &y);
+   lua_createtable(L, 2, 0);
+   lua_pushnumber(L, x);
+   lua_rawseti(L, -2, 1);
+   lua_pushnumber(L, y);
+   lua_rawseti(L, -2, 2);
+   return 1;
+}
+
+static int
+_edje_lua_table_get_align(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mTable);
+   double x, y;
+   evas_object_table_align_get(obj->eo, &x, &y);
+   lua_createtable(L, 2, 0);
+   lua_pushnumber(L, x);
+   lua_rawseti(L, -2, 1);
+   lua_pushnumber(L, y);
+   lua_rawseti(L, -2, 2);
+   return 1;
+}
+
+static int
+_edje_lua_table_get_col_row_size(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mTable);
+   int x, y;
+   evas_object_table_col_row_size_get(obj->eo, &x, &y);
+   lua_createtable(L, 2, 0);
+   lua_pushnumber(L, x);
+   lua_rawseti(L, -2, 1);
+   lua_pushnumber(L, y);
+   lua_rawseti(L, -2, 2);
+   return 1;
+}
+
+static int
+_edje_lua_table_get_children(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mTable);
+   Eina_List *children = (Eina_List *) evas_object_table_children_get(obj->eo);
+   Eina_List *l;
+   Evas_Object *child;
+   int i = 1;
+   lua_createtable(L, eina_list_count(children), 0);
+   EINA_LIST_FOREACH(children, l, child)
+     {
+       _edje_lua_get_reg(L, child);
+       // TODO create object if it does not already exist?
+       lua_rawseti(L, -2, i++);
+     }
+   return 1;
+}
+
+/**
+@page luaref
+@attributes
+@li Table.homogeneous
+@li Table.padding: (horiz,vert)
+@li Table.align: (horiz,vert)
+@li Table.col_row_size: (cols,rows)
+@li Table.children
+*/
+const luaL_Reg lTable_get[] = {
+   {"homogeneous", _edje_lua_table_get_homogeneous},
+   {"padding", _edje_lua_table_get_padding},
+   {"align", _edje_lua_table_get_align},
+   {"col_row_size", _edje_lua_table_get_col_row_size},
+   {"children", _edje_lua_table_get_children},
+   {NULL, NULL}                        // sentinel
+};
+
+static int
+_edje_lua_table_set_homogeneous(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mTable);
+   evas_object_table_homogeneous_set(obj->eo,
+        luaL_checkint(L, 2));
+   return 0;
+}
+
+static int
+_edje_lua_table_set_padding(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mTable);
+   luaL_checktype(L, 2, LUA_TTABLE);
+   lua_rawgeti(L, 2, 1);
+   lua_rawgeti(L, 2, 2);
+   evas_object_table_padding_set(obj->eo,
+        luaL_checkint(L, -2),
+        luaL_checkint(L, -1));
+   return 0;
+}
+
+static int
+_edje_lua_table_set_align(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mTable);
+   luaL_checktype(L, 2, LUA_TTABLE);
+   lua_rawgeti(L, 2, 1);
+   lua_rawgeti(L, 2, 2);
+   evas_object_table_align_set(obj->eo,
+        luaL_checknumber(L, -2),
+        luaL_checknumber(L, -1));
+   return 0;
+}
+
+/**
+@page luaref
+@setters
+@li Table.homogeneous
+@li Table.padding: (horiz,vert)
+@li Table.align: (horiz,vert)
+*/
+const luaL_Reg lTable_set[] = {
+   {"homogeneous", _edje_lua_table_set_homogeneous},
+   {"padding", _edje_lua_table_set_padding},
+   {"align", _edje_lua_table_set_align},
+   {NULL, NULL}                        // sentinel
+};
+
+static int
+_edje_lua_table_fn_pack(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mTable);
+   Edje_Lua_Evas_Object *tar = _edje_lua_checkudata(L, 2, &mObject);
+   lua_pushboolean(L,
+        evas_object_table_pack(obj->eo, tar->eo,
+           luaL_checkint(L, 3),
+           luaL_checkint(L, 4),
+           luaL_checkint(L, 5),
+           luaL_checkint(L, 6)));
+   return 1;
+}
+
+static int
+_edje_lua_table_fn_unpack(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mTable);
+   Edje_Lua_Evas_Object *tar = _edje_lua_checkudata(L, 2, &mObject);
+   lua_pushboolean(L,
+        evas_object_table_unpack(obj->eo, tar->eo));
+   return 1;
+}
+
+static int
+_edje_lua_table_fn_clear(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mTable);
+   evas_object_table_clear(obj->eo, lua_toboolean(L, 2));
+   return 0;
+}
+
+/**
+@page luaref
+@methods
+@li Table.pack(child,col,row,colspan,rowspan)
+@li Table.unpack(child)
+@li Table.clear(clear)
+*/
+const luaL_Reg lTable_fn[] = {
+   {"pack", _edje_lua_table_fn_pack},
+   {"unpack", _edje_lua_table_fn_unpack},
+   {"clear", _edje_lua_table_fn_clear},
+   {NULL, NULL}                        // sentinel
+};
+
+/**
+@page luaref
+@luaclass{Description,Description Class}
+*/
+
+const luaL_Reg lDescription_get[];
+
+const luaL_Reg lDescription_set[];
+
+const Edje_Lua_Reg mDescription = {
+   lNil,
+   lDescription_get,
+   lDescription_set,
+   lNil
+};
+
+const Edje_Lua_Reg *cDescription[] = {
+   &mClass,
+   &mObject,
+   &mDescription,
+   NULL                                // sentinel
+};
+
+static int
+_edje_lua_description_get_alignment(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Description *obj =
+      _edje_lua_checkudata(L, 1, &mDescription);
+   if (!obj->rp->custom) return 0;
+   lua_createtable(L, 2, 0);
+   lua_pushnumber(L, TO_DOUBLE(obj->rp->custom->description->align.x));
+   lua_rawseti(L, -2, 1);
+   lua_pushnumber(L, TO_DOUBLE(obj->rp->custom->description->align.y));
+   lua_rawseti(L, -2, 1);
+   return 1;
+}
+
+static int
+_edje_lua_description_get_min(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Description *obj =
+      _edje_lua_checkudata(L, 1, &mDescription);
+   if (!obj->rp->custom) return 0;
+   lua_createtable(L, 2, 0);
+   lua_pushnumber(L, obj->rp->custom->description->min.w);
+   lua_rawseti(L, -2, 1);
+   lua_pushnumber(L, obj->rp->custom->description->min.h);
+   lua_rawseti(L, -2, 1);
+   return 1;
+}
+
+static int
+_edje_lua_description_get_max(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Description *obj =
+      _edje_lua_checkudata(L, 1, &mDescription);
+   if (!obj->rp->custom) return 0;
+   lua_createtable(L, 2, 0);
+   lua_pushnumber(L, obj->rp->custom->description->max.w);
+   lua_rawseti(L, -2, 1);
+   lua_pushnumber(L, obj->rp->custom->description->max.h);
+   lua_rawseti(L, -2, 1);
+   return 1;
+}
+
+static int
+_edje_lua_description_get_step(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Description *obj =
+      _edje_lua_checkudata(L, 1, &mDescription);
+   if (!obj->rp->custom) return 0;
+   lua_createtable(L, 2, 0);
+   lua_pushnumber(L, obj->rp->custom->description->step.x);
+   lua_rawseti(L, -2, 1);
+   lua_pushnumber(L, obj->rp->custom->description->step.y);
+   lua_rawseti(L, -2, 1);
+   return 1;
+}
+
+static int
+_edje_lua_description_get_aspect(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Description *obj =
+      _edje_lua_checkudata(L, 1, &mDescription);
+   if (!obj->rp->custom) return 0;
+   lua_createtable(L, 2, 0);
+   lua_pushnumber(L, TO_DOUBLE(obj->rp->custom->description->aspect.min));
+   lua_rawseti(L, -2, 1);
+   lua_pushnumber(L, TO_DOUBLE(obj->rp->custom->description->aspect.max));
+   lua_rawseti(L, -2, 1);
+   return 1;
+}
+
+static int
+_edje_lua_description_get_aspect_pref(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Description *obj =
+      _edje_lua_checkudata(L, 1, &mDescription);
+   if (!obj->rp->custom) return 0;
+   lua_pushnumber(L, obj->rp->custom->description->aspect.prefer);
+   return 1;
+}
+
+static int
+_edje_lua_description_get_color(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Description *obj =
+      _edje_lua_checkudata(L, 1, &mDescription);
+   /* check whether this part has a "custom" state */
+   if (!obj->rp->custom) return 0;
+   lua_createtable(L, 4, 0);
+   lua_pushnumber(L, obj->rp->custom->description->color.r);
+   lua_rawseti(L, -2, 1);
+   lua_pushnumber(L, obj->rp->custom->description->color.g);
+   lua_rawseti(L, -2, 2);
+   lua_pushnumber(L, obj->rp->custom->description->color.b);
+   lua_rawseti(L, -2, 3);
+   lua_pushnumber(L, obj->rp->custom->description->color.a);
+   lua_rawseti(L, -2, 4);
+   return 1;
+}
+
+static int
+_edje_lua_description_get_color2(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Description *obj =
+      _edje_lua_checkudata(L, 1, &mDescription);
+   if (!obj->rp->custom) return 0;
+   lua_createtable(L, 4, 0);
+   lua_pushnumber(L, obj->rp->custom->description->color2.r);
+   lua_rawseti(L, -2, 1);
+   lua_pushnumber(L, obj->rp->custom->description->color2.g);
+   lua_rawseti(L, -2, 2);
+   lua_pushnumber(L, obj->rp->custom->description->color2.b);
+   lua_rawseti(L, -2, 3);
+   lua_pushnumber(L, obj->rp->custom->description->color2.a);
+   lua_rawseti(L, -2, 4);
+   return 1;
+}
+
+static int
+_edje_lua_description_get_color3(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Description *obj =
+      _edje_lua_checkudata(L, 1, &mDescription);
+   if (!obj->rp->custom) return 0;
+   lua_createtable(L, 4, 0);
+   lua_pushnumber(L, obj->rp->custom->description->color3.r);
+   lua_rawseti(L, -2, 1);
+   lua_pushnumber(L, obj->rp->custom->description->color3.g);
+   lua_rawseti(L, -2, 2);
+   lua_pushnumber(L, obj->rp->custom->description->color3.b);
+   lua_rawseti(L, -2, 3);
+   lua_pushnumber(L, obj->rp->custom->description->color3.a);
+   lua_rawseti(L, -2, 4);
+   return 1;
+}
+
+static int
+_edje_lua_description_get_color_class(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Description *obj =
+      _edje_lua_checkudata(L, 1, &mDescription);
+   if (!obj->rp->custom) return 0;
+   lua_pushstring(L, obj->rp->custom->description->color_class);
+   return 1;
+}
+
+static int
+_edje_lua_description_get_rel1(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Description *obj =
+      _edje_lua_checkudata(L, 1, &mDescription);
+   if (!obj->rp->custom) return 0;
+   lua_createtable(L, 2, 0);
+   lua_pushnumber(L, TO_DOUBLE(obj->rp->custom->description->rel1.relative_x));
+   lua_rawseti(L, -2, 1);
+   lua_pushnumber(L, TO_DOUBLE(obj->rp->custom->description->rel1.relative_y));
+   lua_rawseti(L, -2, 2);
+   return 1;
+}
+
+static int
+_edje_lua_description_get_rel1_to(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Description *obj =
+      _edje_lua_checkudata(L, 1, &mDescription);
+   if (!obj->rp->custom) return 0;
+   lua_createtable(L, 2, 0);
+   lua_pushnumber(L, obj->rp->custom->description->rel1.id_x);
+   lua_rawseti(L, -2, 1);
+   lua_pushnumber(L, obj->rp->custom->description->rel1.id_y);
+   lua_rawseti(L, -2, 2);
+   return 1;
+}
+
+static int
+_edje_lua_description_get_rel1_offset(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Description *obj =
+      _edje_lua_checkudata(L, 1, &mDescription);
+   if (!obj->rp->custom) return 0;
+   lua_createtable(L, 2, 0);
+   lua_pushnumber(L, obj->rp->custom->description->rel1.offset_x);
+   lua_rawseti(L, -2, 1);
+   lua_pushnumber(L, obj->rp->custom->description->rel1.offset_y);
+   lua_rawseti(L, -2, 2);
+   return 1;
+}
+
+static int
+_edje_lua_description_get_rel2(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Description *obj =
+      _edje_lua_checkudata(L, 1, &mDescription);
+   if (!obj->rp->custom) return 0;
+   lua_createtable(L, 2, 0);
+   lua_pushnumber(L, TO_DOUBLE(obj->rp->custom->description->rel2.relative_x));
+   lua_rawseti(L, -2, 1);
+   lua_pushnumber(L, TO_DOUBLE(obj->rp->custom->description->rel2.relative_y));
+   lua_rawseti(L, -2, 2);
+   return 1;
+}
+
+static int
+_edje_lua_description_get_rel2_to(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Description *obj =
+      _edje_lua_checkudata(L, 1, &mDescription);
+   if (!obj->rp->custom) return 0;
+   lua_createtable(L, 2, 0);
+   lua_pushnumber(L, obj->rp->custom->description->rel2.id_x);
+   lua_rawseti(L, -2, 1);
+   lua_pushnumber(L, obj->rp->custom->description->rel2.id_y);
+   lua_rawseti(L, -2, 2);
+   return 1;
+}
+
+static int
+_edje_lua_description_get_rel2_offset(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Description *obj =
+      _edje_lua_checkudata(L, 1, &mDescription);
+   if (!obj->rp->custom) return 0;
+   lua_createtable(L, 2, 0);
+   lua_pushnumber(L, obj->rp->custom->description->rel2.offset_x);
+   lua_rawseti(L, -2, 1);
+   lua_pushnumber(L, obj->rp->custom->description->rel2.offset_y);
+   lua_rawseti(L, -2, 2);
+   return 1;
+}
+
+static int
+_edje_lua_description_get_image(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Description *obj =
+      _edje_lua_checkudata(L, 1, &mDescription);
+   if (!obj->rp->custom) return 0;
+   if ((obj->rp->part->type != EDJE_PART_TYPE_IMAGE))
+      return 0;
+   // TODO
+   return 0;
+}
+
+static int
+_edje_lua_description_get_border(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Description *obj =
+      _edje_lua_checkudata(L, 1, &mDescription);
+   if ((obj->rp->part->type != EDJE_PART_TYPE_IMAGE))
+      return 0;
+   if (!obj->rp->custom) return 0;
+   lua_createtable(L, 4, 0);
+   lua_pushnumber(L, obj->rp->custom->description->border.l);
+   lua_rawseti(L, -2, 1);
+   lua_pushnumber(L, obj->rp->custom->description->border.r);
+   lua_rawseti(L, -2, 2);
+   lua_pushnumber(L, obj->rp->custom->description->border.t);
+   lua_rawseti(L, -2, 3);
+   lua_pushnumber(L, obj->rp->custom->description->border.b);
+   lua_rawseti(L, -2, 4);
+   return 1;
+}
+
+static int
+_edje_lua_description_get_fill_smooth(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Description *obj =
+      _edje_lua_checkudata(L, 1, &mDescription);
+   if ((obj->rp->part->type != EDJE_PART_TYPE_IMAGE))
+      return 0;
+   if (!obj->rp->custom) return 0;
+   lua_pushboolean(L, obj->rp->custom->description->fill.smooth);
+   return 1;
+}
+
+static int
+_edje_lua_description_get_fill_pos(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Description *obj =
+      _edje_lua_checkudata(L, 1, &mDescription);
+   if ((obj->rp->part->type != EDJE_PART_TYPE_IMAGE))
+      return 0;
+   if (!obj->rp->custom) return 0;
+   lua_createtable(L, 4, 0);
+   lua_pushnumber(L, TO_DOUBLE(obj->rp->custom->description->fill.pos_rel_x));
+   lua_rawseti(L, -2, 1);
+   lua_pushnumber(L, TO_DOUBLE(obj->rp->custom->description->fill.pos_rel_y));
+   lua_rawseti(L, -2, 2);
+   lua_pushnumber(L, obj->rp->custom->description->fill.pos_abs_x);
+   lua_rawseti(L, -2, 3);
+   lua_pushnumber(L, obj->rp->custom->description->fill.pos_abs_y);
+   lua_rawseti(L, -2, 4);
+   return 1;
+}
+
+static int
+_edje_lua_description_get_fill_size(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Description *obj =
+      _edje_lua_checkudata(L, 1, &mDescription);
+   if ((obj->rp->part->type != EDJE_PART_TYPE_IMAGE))
+      return 0;
+   if (!obj->rp->custom) return 0;
+   lua_createtable(L, 4, 0);
+   lua_pushnumber(L, TO_DOUBLE(obj->rp->custom->description->fill.rel_x));
+   lua_rawseti(L, -2, 1);
+   lua_pushnumber(L, TO_DOUBLE(obj->rp->custom->description->fill.rel_y));
+   lua_rawseti(L, -2, 2);
+   lua_pushnumber(L, obj->rp->custom->description->fill.abs_x);
+   lua_rawseti(L, -2, 3);
+   lua_pushnumber(L, obj->rp->custom->description->fill.abs_y);
+   lua_rawseti(L, -2, 4);
+   return 1;
+}
+
+static int
+_edje_lua_description_get_text(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Description *obj =
+      _edje_lua_checkudata(L, 1, &mDescription);
+   if ((obj->rp->part->type != EDJE_PART_TYPE_TEXT)
+       && (obj->rp->part->type != EDJE_PART_TYPE_TEXTBLOCK))
+      return 0;
+   if (!obj->rp->custom) return 0;
+   lua_pushstring(L, obj->rp->custom->description->text.text);
+   return 1;
+}
+
+static int
+_edje_lua_description_get_text_class(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Description *obj =
+      _edje_lua_checkudata(L, 1, &mDescription);
+   if ((obj->rp->part->type != EDJE_PART_TYPE_TEXT)
+       && (obj->rp->part->type != EDJE_PART_TYPE_TEXTBLOCK))
+      return 0;
+   if (!obj->rp->custom) return 0;
+   lua_pushstring(L, obj->rp->custom->description->text.text_class);
+   return 1;
+}
+
+static int
+_edje_lua_description_get_text_font(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Description *obj =
+      _edje_lua_checkudata(L, 1, &mDescription);
+   if ((obj->rp->part->type != EDJE_PART_TYPE_TEXT))
+      return 0;
+   if (!obj->rp->custom) return 0;
+   lua_pushstring(L, obj->rp->custom->description->text.text_class);
+   return 1;
+}
+
+static int
+_edje_lua_description_get_text_style(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Description *obj =
+      _edje_lua_checkudata(L, 1, &mDescription);
+   if ((obj->rp->part->type != EDJE_PART_TYPE_TEXTBLOCK))
+      return 0;
+   if (!obj->rp->custom) return 0;
+   lua_pushstring(L, obj->rp->custom->description->text.style);
+   return 1;
+}
+
+static int
+_edje_lua_description_get_text_size(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Description *obj =
+      _edje_lua_checkudata(L, 1, &mDescription);
+   if ((obj->rp->part->type != EDJE_PART_TYPE_TEXT))
+      return 0;
+   if (!obj->rp->custom) return 0;
+   lua_pushnumber(L, obj->rp->custom->description->text.size);
+   return 1;
+}
+
+static int
+_edje_lua_description_get_text_fit(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Description *obj =
+      _edje_lua_checkudata(L, 1, &mDescription);
+   if ((obj->rp->part->type != EDJE_PART_TYPE_TEXT))
+      return 0;
+   if (!obj->rp->custom) return 0;
+   lua_createtable(L, 2, 0);
+   lua_pushboolean(L, obj->rp->custom->description->text.fit_x);
+   lua_rawseti(L, -2, 1);
+   lua_pushboolean(L, obj->rp->custom->description->text.fit_y);
+   lua_rawseti(L, -2, 2);
+   return 1;
+}
+
+static int
+_edje_lua_description_get_text_min(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Description *obj =
+      _edje_lua_checkudata(L, 1, &mDescription);
+   if ((obj->rp->part->type != EDJE_PART_TYPE_TEXT)
+       && (obj->rp->part->type != EDJE_PART_TYPE_TEXTBLOCK))
+      return 0;
+   if (!obj->rp->custom) return 0;
+   lua_createtable(L, 2, 0);
+   lua_pushnumber(L, obj->rp->custom->description->text.min_x);
+   lua_rawseti(L, -2, 1);
+   lua_pushnumber(L, obj->rp->custom->description->text.min_y);
+   lua_rawseti(L, -2, 2);
+   return 1;
+}
+
+static int
+_edje_lua_description_get_text_max(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Description *obj =
+      _edje_lua_checkudata(L, 1, &mDescription);
+   if ((obj->rp->part->type != EDJE_PART_TYPE_TEXT)
+       && (obj->rp->part->type != EDJE_PART_TYPE_TEXTBLOCK))
+      return 0;
+   if (!obj->rp->custom) return 0;
+   lua_createtable(L, 2, 0);
+   lua_pushnumber(L, obj->rp->custom->description->text.max_x);
+   lua_rawseti(L, -2, 1);
+   lua_pushnumber(L, obj->rp->custom->description->text.max_y);
+   lua_rawseti(L, -2, 2);
+   return 1;
+}
+
+static int
+_edje_lua_description_get_text_align(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Description *obj =
+      _edje_lua_checkudata(L, 1, &mDescription);
+   if ((obj->rp->part->type != EDJE_PART_TYPE_TEXT))
+      return 0;
+   if (!obj->rp->custom) return 0;
+   lua_createtable(L, 2, 0);
+   lua_pushnumber(L, TO_DOUBLE(obj->rp->custom->description->text.align.x));
+   lua_rawseti(L, -2, 1);
+   lua_pushnumber(L, TO_DOUBLE(obj->rp->custom->description->text.align.y));
+   lua_rawseti(L, -2, 2);
+   return 1;
+}
+
+static int
+_edje_lua_description_get_visible(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Description *obj =
+      _edje_lua_checkudata(L, 1, &mDescription);
+   if (!obj->rp->custom) return 0;
+   lua_pushboolean(L, obj->rp->custom->description->visible);
+   return 1;
+}
+
+/**
+@page luaref
+@attributes
+@li Description.alignment: (x,y)
+@li Description.min: (w,h)
+@li Description.max: (w,h)
+@li Description.step: (w,h)
+@li Description.aspect: (x,y)
+@li Description.aspect_pref
+@li Description.color: (r,g,b,a)
+@li Description.color2: (r,g,b,a)
+@li Description.color3: (r,g,b,a)
+@li Description.color_class
+@li Description.rel1: (x,y)
+@li Description.rel1_to: (to_x,to_y)
+@li Description.rel1_offset: (x,y)
+@li Description.rel2: (x,y)
+@li Description.rel2_to: (to_x,to_y)
+@li Description.rel2_offset: (x,y)
+@li Description.image (not yet implemented)
+@li Description.border: (l,r,t,b)
+@li Description.fill_smooth
+@li Description.fill_pos: (rel_x,rel_y,offset_x,offset_y)
+@li Description.fill_size: (rel_x,rel_y,offset_x,offset_y)
+@li Description.text
+@li Description.text_class
+@li Description.text_font
+@li Description.text_style
+@li Description.text_size
+@li Description.text_fit: (x,y)
+@li Description.text_min: (x,y)
+@li Description.text_max: (x,y)
+@li Description.text_align: (x,y)
+@li Description.visible
+*/
+const luaL_Reg lDescription_get[] = {
+   {"alignment", _edje_lua_description_get_alignment},
+   {"min", _edje_lua_description_get_min},
+   {"max", _edje_lua_description_get_max},
+   {"step", _edje_lua_description_get_step},
+   {"aspect", _edje_lua_description_get_aspect},
+   {"aspect_pref", _edje_lua_description_get_aspect_pref},
+   {"color", _edje_lua_description_get_color},
+   {"color2", _edje_lua_description_get_color2},
+   {"color3", _edje_lua_description_get_color3},
+   {"color_class", _edje_lua_description_get_color_class},
+   {"rel1", _edje_lua_description_get_rel1},
+   {"rel1_to", _edje_lua_description_get_rel1_to},
+   {"rel1_offset", _edje_lua_description_get_rel1_offset},
+   {"rel2", _edje_lua_description_get_rel2},
+   {"rel2_to", _edje_lua_description_get_rel2_to},
+   {"rel2_offset", _edje_lua_description_get_rel2_offset},
+   {"image", _edje_lua_description_get_image},
+   {"border", _edje_lua_description_get_border},
+   {"fill_smooth", _edje_lua_description_get_fill_smooth},
+   {"fill_pos", _edje_lua_description_get_fill_pos},
+   {"fill_size", _edje_lua_description_get_fill_size},
+   {"text", _edje_lua_description_get_text},
+   {"text_class", _edje_lua_description_get_text_class},
+   {"text_font", _edje_lua_description_get_text_font},
+   {"text_style", _edje_lua_description_get_text_style},
+   {"text_size", _edje_lua_description_get_text_size},
+   {"text_fit", _edje_lua_description_get_text_fit},
+   {"text_min", _edje_lua_description_get_text_min},
+   {"text_max", _edje_lua_description_get_text_max},
+   {"text_align", _edje_lua_description_get_text_align},
+   {"visible", _edje_lua_description_get_visible},
+   {NULL, NULL}                        // sentinel
+};
+
+static int
+_edje_lua_description_set_alignment(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Description *obj =
+      _edje_lua_checkudata(L, 1, &mDescription);
+   if (!obj->rp->custom) return 0;
+   luaL_checktype(L, 2, LUA_TTABLE);
+   lua_rawgeti(L, 2, 1);
+   lua_rawgeti(L, 2, 2);
+   obj->rp->custom->description->align.x = FROM_DOUBLE(luaL_checknumber(L, -2));
+   obj->rp->custom->description->align.y = FROM_DOUBLE(luaL_checknumber(L, -1));
+   return 0;
+}
+
+static int
+_edje_lua_description_set_min(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Description *obj =
+      _edje_lua_checkudata(L, 1, &mDescription);
+   if (!obj->rp->custom) return 0;
+   lua_rawgeti(L, 2, 1);
+   lua_rawgeti(L, 2, 2);
+   obj->rp->custom->description->min.w = luaL_checkint(L, -2);
+   obj->rp->custom->description->min.h = luaL_checkint(L, -1);
+   return 0;
+}
+
+static int
+_edje_lua_description_set_max(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Description *obj =
+      _edje_lua_checkudata(L, 1, &mDescription);
+   if (!obj->rp->custom) return 0;
+   lua_rawgeti(L, 2, 1);
+   lua_rawgeti(L, 2, 2);
+   obj->rp->custom->description->max.w = luaL_checkint(L, -2);
+   obj->rp->custom->description->max.h = luaL_checkint(L, -1);
+   return 0;
+}
+
+static int
+_edje_lua_description_set_step(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Description *obj =
+      _edje_lua_checkudata(L, 1, &mDescription);
+   if (!obj->rp->custom) return 0;
+   lua_rawgeti(L, 2, 1);
+   lua_rawgeti(L, 2, 2);
+   obj->rp->custom->description->step.x = luaL_checkint(L, -2);
+   obj->rp->custom->description->step.y = luaL_checkint(L, -1);
+   return 0;
+}
+
+static int
+_edje_lua_description_set_aspect(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Description *obj =
+      _edje_lua_checkudata(L, 1, &mDescription);
+   if (!obj->rp->custom) return 0;
+   lua_rawgeti(L, 2, 1);
+   lua_rawgeti(L, 2, 2);
+   obj->rp->custom->description->aspect.min = FROM_DOUBLE(luaL_checknumber(L, -2));
+   obj->rp->custom->description->aspect.max = FROM_DOUBLE(luaL_checknumber(L, -1));
+   return 0;
+
+}
+
+static int
+_edje_lua_description_set_aspect_pref(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Description *obj =
+      _edje_lua_checkudata(L, 1, &mDescription);
+   if (!obj->rp->custom) return 0;
+   obj->rp->custom->description->aspect.prefer = luaL_checknumber(L, 2);
+   return 0;
+
+}
+
+static int
+_edje_lua_description_set_color(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Description *obj =
+      _edje_lua_checkudata(L, 1, &mDescription);
+   if (!obj->rp->custom) return 0;
+   luaL_checktype(L, 2, LUA_TTABLE);
+   lua_rawgeti(L, 2, 1);
+   lua_rawgeti(L, 2, 2);
+   lua_rawgeti(L, 2, 3);
+   lua_rawgeti(L, 2, 4);
+   obj->rp->custom->description->color.r = luaL_checkint(L, -4);
+   obj->rp->custom->description->color.g = luaL_checkint(L, -3);
+   obj->rp->custom->description->color.b = luaL_checkint(L, -2);
+   obj->rp->custom->description->color.a = luaL_checkint(L, -1);
+   return 0;
+}
+
+static int
+_edje_lua_description_set_color2(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Description *obj =
+      _edje_lua_checkudata(L, 1, &mDescription);
+   if (!obj->rp->custom) return 0;
+   luaL_checktype(L, 2, LUA_TTABLE);
+   lua_rawgeti(L, 2, 1);
+   lua_rawgeti(L, 2, 2);
+   lua_rawgeti(L, 2, 3);
+   lua_rawgeti(L, 2, 4);
+   obj->rp->custom->description->color2.r = luaL_checkint(L, -4);
+   obj->rp->custom->description->color2.g = luaL_checkint(L, -3);
+   obj->rp->custom->description->color2.b = luaL_checkint(L, -2);
+   obj->rp->custom->description->color2.a = luaL_checkint(L, -1);
+   return 0;
+}
+
+static int
+_edje_lua_description_set_color3(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Description *obj =
+      _edje_lua_checkudata(L, 1, &mDescription);
+   if (!obj->rp->custom) return 0;
+   luaL_checktype(L, 2, LUA_TTABLE);
+   lua_rawgeti(L, 2, 1);
+   lua_rawgeti(L, 2, 2);
+   lua_rawgeti(L, 2, 3);
+   lua_rawgeti(L, 2, 4);
+   obj->rp->custom->description->color3.r = luaL_checkint(L, -4);
+   obj->rp->custom->description->color3.g = luaL_checkint(L, -3);
+   obj->rp->custom->description->color3.b = luaL_checkint(L, -2);
+   obj->rp->custom->description->color3.a = luaL_checkint(L, -1);
+   return 0;
+}
+
+static int
+_edje_lua_description_set_color_class(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Description *obj =
+      _edje_lua_checkudata(L, 1, &mDescription);
+   if (!obj->rp->custom) return 0;
+   obj->rp->custom->description->color_class = (char *)luaL_checkstring(L, 2);
+   return 0;
+}
+
+static int
+_edje_lua_description_set_rel1(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Description *obj =
+      _edje_lua_checkudata(L, 1, &mDescription);
+   if (!obj->rp->custom) return 0;
+   luaL_checktype(L, 2, LUA_TTABLE);
+   lua_rawgeti(L, 2, 1);
+   lua_rawgeti(L, 2, 2);
+   obj->rp->custom->description->rel1.relative_x = FROM_DOUBLE(luaL_checknumber(L, -2));
+   obj->rp->custom->description->rel1.relative_y = FROM_DOUBLE(luaL_checknumber(L, -1));
+   return 0;
+}
+
+static int
+_edje_lua_description_set_rel1_to(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Description *obj =
+      _edje_lua_checkudata(L, 1, &mDescription);
+   if (!obj->rp->custom) return 0;
+   luaL_checktype(L, 2, LUA_TTABLE);
+   lua_rawgeti(L, 2, 1);
+   lua_rawgeti(L, 2, 2);
+   obj->rp->custom->description->rel1.id_x = luaL_checknumber(L, -2);
+   obj->rp->custom->description->rel1.id_y = luaL_checknumber(L, -1);
+   if (obj->rp->param1.description->rel1.id_x >= 0)
+     obj->rp->param1.rel1_to_x = obj->ed->table_parts[obj->rp->param1.description->rel1.id_x % obj->ed->table_parts_size];
+   if (obj->rp->param1.description->rel1.id_y >= 0)
+     obj->rp->param1.rel1_to_y = obj->ed->table_parts[obj->rp->param1.description->rel1.id_y % obj->ed->table_parts_size];
+   return 0;
+}
+
+static int
+_edje_lua_description_set_rel1_offset(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Description *obj =
+      _edje_lua_checkudata(L, 1, &mDescription);
+   if (!obj->rp->custom) return 0;
+   luaL_checktype(L, 2, LUA_TTABLE);
+   lua_rawgeti(L, 2, 1);
+   lua_rawgeti(L, 2, 2);
+   obj->rp->custom->description->rel1.offset_x = luaL_checkint(L, -2);
+   obj->rp->custom->description->rel1.offset_y = luaL_checkint(L, -1);
+   return 0;
+}
+
+static int
+_edje_lua_description_set_rel2(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Description *obj =
+      _edje_lua_checkudata(L, 1, &mDescription);
+   if (!obj->rp->custom) return 0;
+   luaL_checktype(L, 2, LUA_TTABLE);
+   lua_rawgeti(L, 2, 1);
+   lua_rawgeti(L, 2, 2);
+   obj->rp->custom->description->rel2.relative_x = FROM_DOUBLE(luaL_checknumber(L, -2));
+   obj->rp->custom->description->rel2.relative_y = FROM_DOUBLE(luaL_checknumber(L, -1));
+   return 0;
+}
+
+static int
+_edje_lua_description_set_rel2_to(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Description *obj =
+      _edje_lua_checkudata(L, 1, &mDescription);
+   if (!obj->rp->custom) return 0;
+   luaL_checktype(L, 2, LUA_TTABLE);
+   lua_rawgeti(L, 2, 1);
+   lua_rawgeti(L, 2, 2);
+   obj->rp->custom->description->rel2.id_x = luaL_checknumber(L, -2);
+   obj->rp->custom->description->rel2.id_y = luaL_checknumber(L, -1);
+   if (obj->rp->param1.description->rel2.id_x >= 0)
+     obj->rp->param1.rel2_to_x = obj->ed->table_parts[obj->rp->param1.description->rel2.id_x % obj->ed->table_parts_size];
+   if (obj->rp->param1.description->rel2.id_y >= 0)
+     obj->rp->param1.rel2_to_y = obj->ed->table_parts[obj->rp->param1.description->rel2.id_y % obj->ed->table_parts_size];
+   return 0;
+}
+
+static int
+_edje_lua_description_set_rel2_offset(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Description *obj =
+      _edje_lua_checkudata(L, 1, &mDescription);
+   if (!obj->rp->custom) return 0;
+   luaL_checktype(L, 2, LUA_TTABLE);
+   lua_rawgeti(L, 2, 1);
+   lua_rawgeti(L, 2, 2);
+   obj->rp->custom->description->rel2.offset_x = luaL_checkint(L, -2);
+   obj->rp->custom->description->rel2.offset_y = luaL_checkint(L, -1);
+   return 0;
+}
+
+static int
+_edje_lua_description_set_image(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Description *obj =
+      _edje_lua_checkudata(L, 1, &mDescription);
+   if (!obj->rp->custom) return 0;
+   if ((obj->rp->part->type != EDJE_PART_TYPE_IMAGE))
+      return 0;
+   obj->rp->custom->description->image.id =
+      edje_edit_image_id_get(obj->ed->obj, (char *)luaL_checkstring(L, 2));
+   return 0;
+}
+
+static int
+_edje_lua_description_set_border(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Description *obj =
+      _edje_lua_checkudata(L, 1, &mDescription);
+   if ((obj->rp->part->type != EDJE_PART_TYPE_IMAGE))
+      return 0;
+   if (!obj->rp->custom) return 0;
+   luaL_checktype(L, 2, LUA_TTABLE);
+   lua_rawgeti(L, 2, 1);
+   lua_rawgeti(L, 2, 2);
+   lua_rawgeti(L, 2, 3);
+   lua_rawgeti(L, 2, 4);
+   obj->rp->custom->description->border.l = luaL_checkint(L, -2);
+   obj->rp->custom->description->border.r = luaL_checkint(L, -1);
+   obj->rp->custom->description->border.t = luaL_checkint(L, -2);
+   obj->rp->custom->description->border.b = luaL_checkint(L, -1);
+   return 0;
+}
+
+static int
+_edje_lua_description_set_fill_smooth(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Description *obj =
+      _edje_lua_checkudata(L, 1, &mDescription);
+   if ((obj->rp->part->type != EDJE_PART_TYPE_IMAGE))
+      return 0;
+   if (!obj->rp->custom) return 0;
+   obj->rp->custom->description->fill.smooth = lua_toboolean(L, 2);
+   return 0;
+}
+
+static int
+_edje_lua_description_set_fill_pos(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Description *obj =
+      _edje_lua_checkudata(L, 1, &mDescription);
+   if ((obj->rp->part->type != EDJE_PART_TYPE_IMAGE))
+      return 0;
+   if (!obj->rp->custom) return 0;
+   luaL_checktype(L, 2, LUA_TTABLE);
+   lua_rawgeti(L, 2, 1);
+   lua_rawgeti(L, 2, 2);
+   lua_rawgeti(L, 2, 3);
+   lua_rawgeti(L, 2, 4);
+   obj->rp->custom->description->fill.pos_rel_x = luaL_checkint(L, -2);
+   obj->rp->custom->description->fill.pos_rel_y = luaL_checkint(L, -1);
+   obj->rp->custom->description->fill.pos_abs_x = luaL_checkint(L, -2);
+   obj->rp->custom->description->fill.pos_abs_y = luaL_checkint(L, -1);
+   return 0;
+}
+
+static int
+_edje_lua_description_set_fill_size(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Description *obj =
+      _edje_lua_checkudata(L, 1, &mDescription);
+   if ((obj->rp->part->type != EDJE_PART_TYPE_IMAGE))
+      return 0;
+   if (!obj->rp->custom) return 0;
+   luaL_checktype(L, 2, LUA_TTABLE);
+   lua_rawgeti(L, 2, 1);
+   lua_rawgeti(L, 2, 2);
+   lua_rawgeti(L, 2, 3);
+   lua_rawgeti(L, 2, 4);
+   obj->rp->custom->description->fill.rel_x = luaL_checkint(L, -2);
+   obj->rp->custom->description->fill.rel_y = luaL_checkint(L, -1);
+   obj->rp->custom->description->fill.abs_x = luaL_checkint(L, -2);
+   obj->rp->custom->description->fill.abs_y = luaL_checkint(L, -1);
+   return 0;
+}
+
+static int
+_edje_lua_description_set_text(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Description *obj =
+      _edje_lua_checkudata(L, 1, &mDescription);
+   if ((obj->rp->part->type != EDJE_PART_TYPE_TEXT)
+       && (obj->rp->part->type != EDJE_PART_TYPE_TEXTBLOCK))
+      return 0;
+   if (!obj->rp->custom) return 0;
+   obj->rp->custom->description->text.text = (char *)luaL_checkstring(L, 2);
+   return 0;
+}
+
+static int
+_edje_lua_description_set_text_class(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Description *obj =
+      _edje_lua_checkudata(L, 1, &mDescription);
+   if ((obj->rp->part->type != EDJE_PART_TYPE_TEXT)
+       && (obj->rp->part->type != EDJE_PART_TYPE_TEXTBLOCK))
+      return 0;
+   if (!obj->rp->custom) return 0;
+   obj->rp->custom->description->text.text_class =
+      (char *)luaL_checkstring(L, 2);
+   return 0;
+}
+
+static int
+_edje_lua_description_set_text_font(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Description *obj =
+      _edje_lua_checkudata(L, 1, &mDescription);
+   if ((obj->rp->part->type != EDJE_PART_TYPE_TEXT))
+      return 0;
+   if (!obj->rp->custom) return 0;
+   obj->rp->custom->description->text.font = (char *)luaL_checkstring(L, 2);
+   return 0;
+}
+
+static int
+_edje_lua_description_set_text_style(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Description *obj =
+      _edje_lua_checkudata(L, 1, &mDescription);
+   if ((obj->rp->part->type != EDJE_PART_TYPE_TEXTBLOCK))
+      return 0;
+   if (!obj->rp->custom) return 0;
+   obj->rp->custom->description->text.style = (char *)luaL_checkstring(L, 2);
+   return 0;
+}
+
+static int
+_edje_lua_description_set_text_size(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Description *obj =
+      _edje_lua_checkudata(L, 1, &mDescription);
+   if ((obj->rp->part->type != EDJE_PART_TYPE_TEXT))
+      return 0;
+   if (!obj->rp->custom) return 0;
+   obj->rp->custom->description->text.size = luaL_checkint(L, 2);
+   return 0;
+}
+
+static int
+_edje_lua_description_set_text_fit(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Description *obj =
+      _edje_lua_checkudata(L, 1, &mDescription);
+   if (!obj->rp->custom) return 0;
+   luaL_checktype(L, 2, LUA_TTABLE);
+   lua_rawgeti(L, 2, 1);
+   lua_rawgeti(L, 2, 2);
+   obj->rp->custom->description->text.fit_x = lua_toboolean(L, -2);
+   obj->rp->custom->description->text.fit_y = lua_toboolean(L, -1);
+   return 0;
+}
+
+static int
+_edje_lua_description_set_text_min(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Description *obj =
+      _edje_lua_checkudata(L, 1, &mDescription);
+   if ((obj->rp->part->type != EDJE_PART_TYPE_TEXT)
+       && (obj->rp->part->type != EDJE_PART_TYPE_TEXTBLOCK))
+      return 0;
+   if (!obj->rp->custom) return 0;
+   luaL_checktype(L, 2, LUA_TTABLE);
+   lua_rawgeti(L, 2, 1);
+   lua_rawgeti(L, 2, 2);
+   obj->rp->custom->description->text.min_x = luaL_checkint(L, -2);
+   obj->rp->custom->description->text.min_y = luaL_checkint(L, -1);
+   return 0;
+}
+
+static int
+_edje_lua_description_set_text_max(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Description *obj =
+      _edje_lua_checkudata(L, 1, &mDescription);
+   if ((obj->rp->part->type != EDJE_PART_TYPE_TEXT)
+       && (obj->rp->part->type != EDJE_PART_TYPE_TEXTBLOCK))
+      return 0;
+   if (!obj->rp->custom) return 0;
+   luaL_checktype(L, 2, LUA_TTABLE);
+   lua_rawgeti(L, 2, 1);
+   lua_rawgeti(L, 2, 2);
+   obj->rp->custom->description->text.max_x = luaL_checkint(L, -2);
+   obj->rp->custom->description->text.max_y = luaL_checkint(L, -1);
+   return 0;
+}
+
+static int
+_edje_lua_description_set_text_align(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Description *obj =
+      _edje_lua_checkudata(L, 1, &mDescription);
+   if ((obj->rp->part->type != EDJE_PART_TYPE_TEXT))
+      return 0;
+   if (!obj->rp->custom) return 0;
+   luaL_checktype(L, 2, LUA_TTABLE);
+   lua_rawgeti(L, 2, 1);
+   lua_rawgeti(L, 2, 2);
+   obj->rp->custom->description->text.align.x = FROM_DOUBLE(luaL_checknumber(L, -2));
+   obj->rp->custom->description->text.align.y = FROM_DOUBLE(luaL_checknumber(L, -1));
+   return 0;
+}
+
+static int
+_edje_lua_description_set_visible(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Description *obj =
+      _edje_lua_checkudata(L, 1, &mDescription);
+   if (!obj->rp->custom) return 0;
+   obj->rp->custom->description->visible = lua_toboolean(L, 2);
+   return 0;
+}
+
+/**
+@page luaref
+@setters
+@li Description.alignment: (x,y)
+@li Description.min: (w,h)
+@li Description.max: (w,h)
+@li Description.step: (w,h)
+@li Description.aspect: (x,y)
+@li Description.aspect_pref
+@li Description.color: (r,g,b,a)
+@li Description.color2: (r,g,b,a)
+@li Description.color3: (r,g,b,a)
+@li Description.color_class
+@li Description.rel1: (x,y)
+@li Description.rel1_to: (to_x,to_y)
+@li Description.rel1_offset: (x,y)
+@li Description.rel2: (x,y)
+@li Description.rel2_to: (to_x,to_y)
+@li Description.rel2_offset: (x,y)
+@li Description.image
+@li Description.border: (l,r,t,b)
+@li Description.fill_smooth
+@li Description.fill_pos: (rel_x,rel_y,offset_x,offset_y)
+@li Description.fill_size: (rel_x,rel_y,offset_x,offset_y)
+@li Description.text
+@li Description.text_class
+@li Description.text_font
+@li Description.text_style
+@li Description.text_size
+@li Description.text_fit: (x,y)
+@li Description.text_min: (x,y)
+@li Description.text_max: (x,y)
+@li Description.text_align: (x,y)
+@li Description.visible
+*/
+const luaL_Reg lDescription_set[] = {
+   {"alignment", _edje_lua_description_set_alignment},
+   {"min", _edje_lua_description_set_min},
+   {"max", _edje_lua_description_set_max},
+   {"step", _edje_lua_description_set_step},
+   {"aspect", _edje_lua_description_set_aspect},
+   {"aspect_pref", _edje_lua_description_set_aspect_pref},
+   {"color", _edje_lua_description_set_color},
+   {"color2", _edje_lua_description_set_color2},
+   {"color3", _edje_lua_description_set_color3},
+   {"color_class", _edje_lua_description_set_color_class},
+   {"rel1", _edje_lua_description_set_rel1},
+   {"rel1_to", _edje_lua_description_set_rel1_to},
+   {"rel1_offset", _edje_lua_description_set_rel1_offset},
+   {"rel2", _edje_lua_description_set_rel2},
+   {"rel2_to", _edje_lua_description_set_rel2_to},
+   {"rel2_offset", _edje_lua_description_set_rel2_offset},
+   {"image", _edje_lua_description_set_image},
+   {"border", _edje_lua_description_set_border},
+   {"fill_smooth", _edje_lua_description_set_fill_smooth},
+   {"fill_pos", _edje_lua_description_set_fill_pos},
+   {"fill_size", _edje_lua_description_set_fill_size},
+   {"text", _edje_lua_description_set_text},
+   {"text_class", _edje_lua_description_set_text_class},
+   {"text_font", _edje_lua_description_set_text_font},
+   {"text_style", _edje_lua_description_set_text_style},
+   {"text_size", _edje_lua_description_set_text_size},
+   {"text_fit", _edje_lua_description_set_text_fit},
+   {"text_min", _edje_lua_description_set_text_min},
+   {"text_max", _edje_lua_description_set_text_max},
+   {"text_align", _edje_lua_description_set_text_align},
+   {"visible", _edje_lua_description_set_visible},
+   {NULL, NULL}                        // sentinel
+};
+
+/**
+@page luaref
+@luaclass{Part,Part Class}
+
+Parts are objects, that is, they inherit the methods from the @ref Object class.
+They also contain the following methods and attributes: 
+
+*/
+const luaL_Reg lPart_get[];
+
+const luaL_Reg lPart_set[];
+
+const luaL_Reg lPart_fn[];
+
+const Edje_Lua_Reg mPart = {
+   lNil,
+   lPart_get,
+   lPart_set,
+   lPart_fn
+};
+
+static void
+_edje_lua_edje_part_del_cb(void *data, Evas * e, Evas_Object * obj,
+                       void *event_info)
+{
+   //printf("_edje_lua_object_delete_cb\n");
+   lua_State *L = data;
+   _edje_lua_get_reg(L, obj);
+   Edje_Lua_Edje_Part_Object *udata = _edje_lua_checkudata(L, -1, &mPart);
+   lua_pop(L, 1);
+   _edje_lua_free_reg(L, udata); // created in _edje_lua_group_mt_index
+   _edje_lua_free_reg(L, obj); // created in _edje_lua_group_mt_index
+}
+
+const Edje_Lua_Reg *cPart[] = {
+   &mClass,
+   &mObject,
+   &mPart,
+   NULL                                // sentinel
+};
+
+static int
+_edje_lua_part_get_swallow(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Object *obj = _edje_lua_checkudata(L, 1, &mPart);
+   Evas_Object *swa = edje_object_part_swallow_get(obj->ed->obj, obj->key);
+   _edje_lua_get_reg(L, swa);
+   // TODO create object if it does not already exist?
+   return 1;
+}
+
+static int
+_edje_lua_part_get_type(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Object *obj = _edje_lua_checkudata(L, 1, &mPart);
+   lua_pushnumber(L, edje_edit_part_type_get(obj->ed->obj, obj->key));
+   return 1;
+}
+
+static int
+_edje_lua_part_get_effect(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Object *obj = _edje_lua_checkudata(L, 1, &mPart);
+   lua_pushnumber(L, edje_edit_part_effect_get(obj->ed->obj, obj->key));
+   return 1;
+}
+
+static int
+_edje_lua_part_get_mouse_events(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Object *obj = _edje_lua_checkudata(L, 1, &mPart);
+   lua_pushboolean(L, edje_edit_part_mouse_events_get(obj->ed->obj, obj->key));
+   return 1;
+}
+
+static int
+_edje_lua_part_get_repeat_events(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Object *obj = _edje_lua_checkudata(L, 1, &mPart);
+   lua_pushboolean(L, edje_edit_part_repeat_events_get(obj->ed->obj, obj->key));
+   return 1;
+}
+
+static int
+_edje_lua_part_get_states_list(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Object *obj = _edje_lua_checkudata(L, 1, &mPart);
+   Eina_List *slist = edje_edit_part_states_list_get(obj->ed->obj, obj->key);
+   Eina_List *ilist;
+   lua_newtable(L);
+   int i = 1;
+   for (ilist = slist; ilist; ilist = eina_list_next(ilist))
+     {
+       lua_pushstring(L, eina_list_data_get(ilist));
+       lua_rawseti(L, -2, i++);
+     }
+   edje_edit_string_list_free(slist);
+   return 1;
+};
+
+static int
+_edje_lua_part_get_state(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Object *obj = _edje_lua_checkudata(L, 1, &mPart);
+   const char *state;
+   double val;
+   state = edje_object_part_state_get(obj->ed->obj, obj->key, &val);
+   lua_createtable(L, 2, 0);
+   lua_pushstring(L, state);
+   lua_rawseti(L, -2, 1);
+   lua_pushnumber(L, val);
+   lua_rawseti(L, -2, 2);
+   return 1;
+};
+
+static int
+_edje_lua_part_get_text(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Object *obj = _edje_lua_checkudata(L, 1, &mPart);
+   lua_pushstring(L, edje_object_part_text_get(obj->ed->obj, obj->key));
+   return 1;
+};
+
+static int
+_edje_lua_part_get_text_selection(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Object *obj = _edje_lua_checkudata(L, 1, &mPart);
+   lua_pushstring(L,
+                 edje_object_part_text_selection_get(obj->ed->obj, obj->key));
+   return 1;
+};
+
+static int
+_edje_lua_part_get_drag_dir(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Object *obj = _edje_lua_checkudata(L, 1, &mPart);
+   lua_pushnumber(L, edje_object_part_drag_dir_get(obj->ed->obj, obj->key));
+   return 1;
+}
+
+static int
+_edje_lua_part_get_drag_value(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Object *obj = _edje_lua_checkudata(L, 1, &mPart);
+   double dx, dy;
+   edje_object_part_drag_value_get(obj->ed->obj, obj->key, &dx, &dy);
+   lua_createtable(L, 2, 0);
+   lua_pushnumber(L, dx);
+   lua_rawseti(L, -2, 1);
+   lua_pushnumber(L, dy);
+   lua_rawseti(L, -2, 2);
+   return 1;
+}
+
+static int
+_edje_lua_part_get_drag_size(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Object *obj = _edje_lua_checkudata(L, 1, &mPart);
+   double dx, dy;
+   edje_object_part_drag_size_get(obj->ed->obj, obj->key, &dx, &dy);
+   lua_createtable(L, 2, 0);
+   lua_pushnumber(L, dx);
+   lua_rawseti(L, -2, 1);
+   lua_pushnumber(L, dy);
+   lua_rawseti(L, -2, 2);
+   return 1;
+}
+
+static int
+_edje_lua_part_get_drag_step(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Object *obj = _edje_lua_checkudata(L, 1, &mPart);
+   double dx, dy;
+   edje_object_part_drag_step_get(obj->ed->obj, obj->key, &dx, &dy);
+   lua_createtable(L, 2, 0);
+   lua_pushnumber(L, dx);
+   lua_rawseti(L, -2, 1);
+   lua_pushnumber(L, dy);
+   lua_rawseti(L, -2, 2);
+   return 1;
+}
+
+static int
+_edje_lua_part_get_drag_page(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Object *obj = _edje_lua_checkudata(L, 1, &mPart);
+   double dx, dy;
+   edje_object_part_drag_page_get(obj->ed->obj, obj->key, &dx, &dy);
+   lua_createtable(L, 2, 0);
+   lua_pushnumber(L, dx);
+   lua_rawseti(L, -2, 1);
+   lua_pushnumber(L, dy);
+   lua_rawseti(L, -2, 2);
+   return 1;
+}
+
+static int
+_edje_lua_part_get_text_cursor_geometry(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Object *obj = _edje_lua_checkudata(L, 1, &mPart);
+   Evas_Coord x, y, w, h;
+   edje_object_part_text_cursor_geometry_get(obj->ed->obj, obj->key,
+                                            &x, &y, &w, &h);
+   lua_createtable(L, 4, 0);
+   lua_pushnumber(L, x);
+   lua_rawseti(L, -2, 1);
+   lua_pushnumber(L, y);
+   lua_rawseti(L, -2, 2);
+   lua_pushnumber(L, w);
+   lua_rawseti(L, -2, 3);
+   lua_pushnumber(L, h);
+   lua_rawseti(L, -2, 4);
+   return 1;
+}
+
+static int
+_edje_lua_part_get_geometry(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Object *obj = _edje_lua_checkudata(L, 1, &mPart);
+   Evas_Coord x, y, w, h;
+   edje_object_part_geometry_get(obj->ed->obj, obj->key, &x, &y, &w, &h);
+   lua_createtable(L, 4, 0);
+   lua_pushnumber(L, x);
+   lua_rawseti(L, -2, 1);
+   lua_pushnumber(L, y);
+   lua_rawseti(L, -2, 2);
+   lua_pushnumber(L, w);
+   lua_rawseti(L, -2, 3);
+   lua_pushnumber(L, h);
+   lua_rawseti(L, -2, 4);
+   return 1;
+}
+
+static int
+_edje_lua_part_get_table_col_row_size(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Object *obj = _edje_lua_checkudata(L, 1, &mPart);
+   int cols, rows;
+   edje_object_part_table_col_row_size_get(obj->ed->obj, obj->key, &cols, &rows);
+   lua_createtable(L, 2, 0);
+   lua_pushnumber(L, cols); lua_rawseti(L, -2, 1);
+   lua_pushnumber(L, rows); lua_rawseti(L, -2, 2);
+   return 1;
+}
+
+static int _edje_lua_part_fn_custom_state(lua_State *L);
+
+/**
+@page luaref
+@attributes
+@li @ref Object Part.swallow
+@li Part.drag_dir
+@li Part.drag_value: (dx,dy)
+@li Part.drag_size: (dx,dy)
+@li Part.drag_step: (dx,dy)
+@li Part.drag_page: (dx,dy)
+@li Part.type
+@li Part.effect
+@li Part.mouse_events
+@li Part.states_list
+@li Part.state: (state,value)
+@li Part.text
+@li Part.text_selection
+@li Part.text_cursor_geometry: (x,y,w,h)
+@li Part.geometry: (x,y,w,h)
+@li Part.part_col_row_size: (cols,rows)
+*/
+const luaL_Reg lPart_get[] = {
+   {"custom_state", _edje_lua_part_fn_custom_state},
+   {"Swallow", _edje_lua_part_get_swallow}, //TODO it the capital S correct?
+
+   {"drag_dir", _edje_lua_part_get_drag_dir},
+   {"drag_value", _edje_lua_part_get_drag_value},
+   {"drag_size", _edje_lua_part_get_drag_size},
+   {"drag_step", _edje_lua_part_get_drag_step},
+   {"drag_page", _edje_lua_part_get_drag_page},
+
+   {"type", _edje_lua_part_get_type},
+   {"effect", _edje_lua_part_get_effect},
+   {"mouse_events", _edje_lua_part_get_mouse_events},
+   {"repeat_events", _edje_lua_part_get_repeat_events},
+   {"states_list", _edje_lua_part_get_states_list},
+   {"state", _edje_lua_part_get_state},
+
+   {"text", _edje_lua_part_get_text},
+   {"text_selection", _edje_lua_part_get_text_selection},
+   {"text_cursor_geometry", _edje_lua_part_get_text_cursor_geometry},
+
+   {"geometry", _edje_lua_part_get_geometry},
+   {"part_col_row_size", _edje_lua_part_get_table_col_row_size},
+   {NULL, NULL}                        // sentinel
+};
+
+static int
+_edje_lua_part_set_effect(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Object *obj = _edje_lua_checkudata(L, 1, &mPart);
+   edje_edit_part_effect_set(obj->ed->obj, obj->key, luaL_checkint(L, 2));
+   return 0;
+}
+
+static int
+_edje_lua_part_set_mouse_events(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Object *obj = _edje_lua_checkudata(L, 1, &mPart);
+   edje_edit_part_mouse_events_set(obj->ed->obj, obj->key, lua_toboolean(L, 2));
+   return 0;
+}
+
+static int
+_edje_lua_part_set_repeat_events(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Object *obj = _edje_lua_checkudata(L, 1, &mPart);
+   edje_edit_part_repeat_events_set(obj->ed->obj, obj->key,
+                                   lua_toboolean(L, 2));
+   return 0;
+}
+
+static int
+_edje_lua_part_set_state(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Object *obj = _edje_lua_checkudata(L, 1, &mPart);
+   luaL_checktype(L, 2, LUA_TTABLE);
+   lua_rawgeti(L, 2, 1);
+   lua_rawgeti(L, 2, 2);
+   _edje_part_description_apply(obj->ed, obj->rp,
+                               luaL_checkstring(L, -2), luaL_checknumber(L, -1),
+                               NULL, 0.0);
+   _edje_part_pos_set(obj->ed, obj->rp, EDJE_TWEEN_MODE_LINEAR, ZERO);
+   _edje_recalc(obj->ed);
+   return 0;
+}
+
+static int
+_edje_lua_part_set_tween_state(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Object *obj = _edje_lua_checkudata(L, 1, &mPart);
+   luaL_checktype(L, 2, LUA_TTABLE);
+   lua_rawgeti(L, 2, 1);
+   lua_rawgeti(L, 2, 2);
+   lua_rawgeti(L, 2, 3);
+   lua_rawgeti(L, 2, 4);
+   lua_rawgeti(L, 2, 5);
+   _edje_part_description_apply(obj->ed, obj->rp,
+                               luaL_checkstring(L, -4), luaL_checknumber(L, -3),
+                               luaL_checkstring(L, -2), luaL_checknumber(L, -1));
+   _edje_part_pos_set(obj->ed, obj->rp, EDJE_TWEEN_MODE_LINEAR,
+                     FROM_DOUBLE(luaL_checknumber(L, -5)));
+   _edje_recalc(obj->ed);
+   return 0;
+}
+
+static int
+_edje_lua_part_set_text(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Object *obj = _edje_lua_checkudata(L, 1, &mPart);
+   edje_object_part_text_set(obj->ed->obj, obj->key, luaL_checkstring(L, 2));
+   return 0;
+}
+
+static int
+_edje_lua_part_set_drag_value(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Object *obj = _edje_lua_checkudata(L, 1, &mPart);
+   lua_rawgeti(L, 2, 1);
+   lua_rawgeti(L, 2, 2);
+   edje_object_part_drag_value_set(obj->ed->obj, obj->key,
+                                  luaL_checknumber(L, -2),
+                                  luaL_checknumber(L, -1));
+   return 0;
+}
+
+static int
+_edje_lua_part_set_drag_size(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Object *obj = _edje_lua_checkudata(L, 1, &mPart);
+   lua_rawgeti(L, 2, 1);
+   lua_rawgeti(L, 2, 2);
+   edje_object_part_drag_size_set(obj->ed->obj, obj->key,
+                                 luaL_checknumber(L, -2),
+                                 luaL_checknumber(L, -1));
+   return 0;
+}
+
+static int
+_edje_lua_part_set_drag_step(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Object *obj = _edje_lua_checkudata(L, 1, &mPart);
+   lua_rawgeti(L, 2, 1);
+   lua_rawgeti(L, 2, 2);
+   edje_object_part_drag_step_set(obj->ed->obj, obj->key,
+                                 luaL_checknumber(L, -2),
+                                 luaL_checknumber(L, -1));
+   return 0;
+}
+
+static int
+_edje_lua_part_set_drag_page(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Object *obj = _edje_lua_checkudata(L, 1, &mPart);
+   lua_rawgeti(L, 2, 1);
+   lua_rawgeti(L, 2, 2);
+   edje_object_part_drag_page_set(obj->ed->obj, obj->key,
+                                 luaL_checknumber(L, -2),
+                                 luaL_checknumber(L, -1));
+   return 0;
+}
+
+/**
+@page luaref
+@setters
+@li Part.drag_value: (dx,dy)
+@li Part.drag_size: (dx,dy)
+@li Part.drag_step: (dx,dy)
+@li Part.drag_page: (dx,dy)
+@li Part.effect
+@li Part.mouse_events
+@li Part.repeat_events
+@li Part.state: (state,value)
+@li Part.tween_state
+@li Part.text
+*/
+const luaL_Reg lPart_set[] = {
+   {"drag_value", _edje_lua_part_set_drag_value},
+   {"drag_size", _edje_lua_part_set_drag_size},
+   {"drag_step", _edje_lua_part_set_drag_step},
+   {"drag_page", _edje_lua_part_set_drag_page},
+
+   {"effect", _edje_lua_part_set_effect},
+   {"mouse_events", _edje_lua_part_set_mouse_events},
+   {"repeat_events", _edje_lua_part_set_repeat_events},
+   {"state", _edje_lua_part_set_state},
+   {"tween_state", _edje_lua_part_set_tween_state},
+   {"text", _edje_lua_part_set_text},
+   {NULL, NULL}                        // sentinel
+};
+
+static int
+_edje_lua_part_fn_swallow(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Object *obj = _edje_lua_checkudata(L, 1, &mPart);
+   Edje_Lua_Evas_Object *swa = _edje_lua_checkudata(L, 2, &mObject);
+   edje_object_part_swallow(obj->ed->obj, obj->key, swa->eo);
+   return 0;
+}
+
+static int
+_edje_lua_part_fn_unswallow(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Object *obj = _edje_lua_checkudata(L, 1, &mPart);
+   edje_object_part_unswallow(obj->ed->obj, obj->eo);
+   return 0;
+}
+
+static int
+_edje_lua_part_fn_text_select_none(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Object *obj = _edje_lua_checkudata(L, 1, &mPart);
+   edje_object_part_text_select_none(obj->ed->obj, obj->key);
+   return 0;
+}
+
+static int
+_edje_lua_part_fn_text_select_all(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Object *obj = _edje_lua_checkudata(L, 1, &mPart);
+   edje_object_part_text_select_all(obj->ed->obj, obj->key);
+   return 0;
+}
+
+static int
+_edje_lua_part_fn_text_insert(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Object *obj = _edje_lua_checkudata(L, 1, &mPart);
+   edje_object_part_text_insert(obj->ed->obj, obj->key, luaL_checkstring(L, 2));
+   return 0;
+}
+
+static int
+_edje_lua_part_fn_custom_state(lua_State *L)
+{
+   char *name;
+   float val;
+   Edje_Part_Description *parent;
+   Edje_Part_Image_Id *iid;
+   Eina_List *l;
+   Edje_Lua_Edje_Part_Object *obj = _edje_lua_checkudata(L, 1, &mPart);
+   /* check whether this part already has a "custom" state */
+   if (obj->rp->custom)
+     {
+       _edje_lua_get_reg(L, obj->rp->custom->description);
+       return 1;
+     }
+
+   name = (char *)luaL_checkstring(L, 2);      // state name
+   val = luaL_checknumber(L, 3);       // state val
+   if (!(parent = _edje_part_description_find(obj->ed, obj->rp, name, val)))
+     {
+       lua_pushnil(L);
+       return 1;
+     }
+   /* now create the custom state */
+   Edje_Lua_Edje_Part_Description *tar =
+      lua_newuserdata(L, sizeof(Edje_Lua_Edje_Part_Description));
+   tar->rp = obj->rp;
+   _edje_lua_set_class(L, -1, cDescription);
+   _edje_lua_new_reg(L, -1, tar); // freed in edje_load.c::_edje_file_del
+   if (!(tar->pd = calloc(1, sizeof(Edje_Part_Description))))
+     {
+       lua_pushnil(L);
+       return 1;
+     }
+   
+   obj->rp->custom = eina_mempool_malloc(_edje_real_part_state_mp, sizeof (Edje_Real_Part_State));
+   if (!obj->rp->custom)
+     {
+        free(tar->pd);
+        tar->pd = NULL;
+        lua_pushnil(L);
+        return 1;
+     }
+   
+   *(tar->pd) = *parent;
+   tar->pd->state.name = (char *)eina_stringshare_add("custom");
+   tar->pd->state.value = 0.0;
+   /* 
+    * make sure all the allocated memory is getting copied,
+    * not just referenced
+    */
+   tar->pd->image.tween_list = NULL;
+   EINA_LIST_FOREACH(parent->image.tween_list, l, iid)
+   {
+      Edje_Part_Image_Id *iid_new;
+      iid_new = calloc(1, sizeof(Edje_Part_Image_Id));
+      iid_new->id = iid->id;
+
+      tar->pd->image.tween_list =
+        eina_list_append(tar->pd->image.tween_list, iid_new);
+   }
+#define DUP(x) x ? (char *)eina_stringshare_add(x) : NULL
+   tar->pd->color_class = DUP(tar->pd->color_class);
+   tar->pd->text.text = DUP(tar->pd->text.text);
+   tar->pd->text.text_class = DUP(tar->pd->text.text_class);
+   tar->pd->text.font = DUP(tar->pd->text.font);
+   tar->pd->text.style = DUP(tar->pd->text.style);
+#undef DUP
+   obj->rp->custom->description = tar->pd;
+   _edje_lua_new_reg(L, -1, obj->rp->custom->description); // freed in edje_load.c::_edje_file_del
+   return 1;
+}
+
+static int
+_edje_lua_part_fn_table_pack(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Object *obj = _edje_lua_checkudata(L, 1, &mPart);
+   Edje_Lua_Evas_Object *tar = _edje_lua_checkudata(L, 2, &mObject);
+   lua_pushboolean(L,
+      edje_object_part_table_pack(obj->ed->obj, obj->key, tar->eo,
+        luaL_checkint(L, 3),
+        luaL_checkint(L, 4),
+        luaL_checkint(L, 5),
+        luaL_checkint(L, 6)));
+   return 1;
+}
+
+static int
+_edje_lua_part_fn_table_unpack(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Object *obj = _edje_lua_checkudata(L, 1, &mPart);
+   Edje_Lua_Evas_Object *tar = _edje_lua_checkudata(L, 2, &mObject);
+   lua_pushboolean(L,
+        edje_object_part_table_unpack(obj->ed->obj, obj->key, tar->eo));
+   return 1;
+}
+
+static int
+_edje_lua_part_fn_table_clear(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Object *obj = _edje_lua_checkudata(L, 1, &mPart);
+   lua_pushboolean(L,
+        edje_object_part_table_clear(obj->ed->obj, obj->key, lua_toboolean(L, 2)));
+   return 1;
+}
+
+static int
+_edje_lua_part_fn_box_append(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Object *obj = _edje_lua_checkudata(L, 1, &mPart);
+   Edje_Lua_Evas_Object *tar = _edje_lua_checkudata(L, 2, &mObject);
+   lua_pushboolean(L,
+        edje_object_part_box_append(obj->ed->obj, obj->key, tar->eo));
+   return 1;
+}
+
+static int
+_edje_lua_part_fn_box_prepend(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Object *obj = _edje_lua_checkudata(L, 1, &mPart);
+   Edje_Lua_Evas_Object *tar = _edje_lua_checkudata(L, 2, &mObject);
+   lua_pushboolean(L,
+        edje_object_part_box_prepend(obj->ed->obj, obj->key, tar->eo));
+   return 1;
+}
+
+static int
+_edje_lua_part_fn_box_insert_before(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Object *obj = _edje_lua_checkudata(L, 1, &mPart);
+   Edje_Lua_Evas_Object *tar = _edje_lua_checkudata(L, 2, &mObject);
+   Edje_Lua_Evas_Object *ref = _edje_lua_checkudata(L, 3, &mObject);
+   lua_pushboolean(L,
+        edje_object_part_box_insert_before(obj->ed->obj, obj->key, tar->eo, ref->eo));
+   return 1;
+}
+
+static int
+_edje_lua_part_fn_box_insert_at(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Object *obj = _edje_lua_checkudata(L, 1, &mPart);
+   Edje_Lua_Evas_Object *tar = _edje_lua_checkudata(L, 2, &mObject);
+   lua_pushboolean(L,
+        edje_object_part_box_insert_at(obj->ed->obj, obj->key, tar->eo, luaL_checkint(L, 3)));
+   return 1;
+}
+
+static int
+_edje_lua_part_fn_box_remove(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Object *obj = _edje_lua_checkudata(L, 1, &mPart);
+   Edje_Lua_Evas_Object *tar = _edje_lua_checkudata(L, 2, &mObject);
+   edje_object_part_box_remove(obj->ed->obj, obj->key, tar->eo);
+   lua_pushvalue(L, 2);
+   return 1;
+}
+
+static int
+_edje_lua_part_fn_box_remove_at(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Object *obj = _edje_lua_checkudata(L, 1, &mPart);
+   _edje_lua_get_reg(L, edje_object_part_box_remove_at(obj->ed->obj, obj->key, luaL_checkint(L, 2)));
+   return 1;
+}
+
+static int
+_edje_lua_part_fn_box_remove_all(lua_State *L)
+{
+   Edje_Lua_Edje_Part_Object *obj = _edje_lua_checkudata(L, 1, &mPart);
+   lua_pushboolean(L,
+        edje_object_part_box_remove_all(obj->ed->obj, obj->key, lua_toboolean(L, 2)));
+   return 1;
+}
+
+/**
+@page luaref
+@methods
+@li Part:swallow(obj)
+@li Part:unswallow()
+@li @ref PartDescription Part:custom_state(state_name, state_val)
+@li Part:text_select_none
+@li Part:text_select_all
+@li Part:text_insert(text)
+@li Part:table_pack(child, row, colspan, rowspan)
+@li Part:table_unpack(child)
+@li Part:table_clear(clear)
+@li Part:box_append(item)
+@li Part:box_prepend(item)
+@li Part:box_insert_before(item, before)
+@li Part:box_insert_at(item, index)
+@li Part:box_remove(item)
+@li Part:box_remove_at(item, index)
+@li Part:box_remove_all(clear)
+*/
+const luaL_Reg lPart_fn[] = {
+   {"swallow", _edje_lua_part_fn_swallow},
+   {"unswallow", _edje_lua_part_fn_unswallow},
+
+   {"custom_state", _edje_lua_part_fn_custom_state},
+
+   {"text_select_none", _edje_lua_part_fn_text_select_none},
+   {"text_select_all", _edje_lua_part_fn_text_select_all},
+   {"text_insert", _edje_lua_part_fn_text_insert},
+
+   {"table_pack", _edje_lua_part_fn_table_pack},
+   {"table_unpack", _edje_lua_part_fn_table_unpack},
+   {"table_clear", _edje_lua_part_fn_table_clear},
+
+   {"box_append", _edje_lua_part_fn_box_append},
+   {"box_prepend", _edje_lua_part_fn_box_prepend},
+   {"box_insert_before", _edje_lua_part_fn_box_insert_before},
+   {"box_insert_at", _edje_lua_part_fn_box_insert_at},
+   {"box_remove", _edje_lua_part_fn_box_remove},
+   {"box_remove_at", _edje_lua_part_fn_box_remove_at},
+   {"box_remove_all", _edje_lua_part_fn_box_remove_all},
+   {NULL, NULL}                        // sentinel
+};
+
+/**
+@page luaref
+@luaclass{Group,Group Class}
+
+Groups are objects, that is, they inherit the methods from the general
+@ref Object Class.
+They also contain the following methods and attributes:
+*/
+const luaL_Reg lGroup_mt[];
+
+const luaL_Reg lGroup_get[];
+
+const luaL_Reg lGroup_set[];
+
+const luaL_Reg lGroup_fn[];
+
+const Edje_Lua_Reg mGroup = {
+   lGroup_mt,
+   lGroup_get,
+   lGroup_set,
+   lGroup_fn
+};
+
+const Edje_Lua_Reg *cGroup[] = {
+   &mClass,
+   &mObject,
+   &mGroup,
+   NULL                                // sentinel
+};
+
+static int
+_edje_lua_group_mt_index(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mGroup);
+   lua_getmetatable(L, 1);
+   if (!_edje_lua_look_fn(L))
+     {
+       // look in lGroup_fn
+       if (!_edje_lua_look_get(L))
+         {
+            // look in lGroup_get
+            const char *key = luaL_checkstring(L, 2);
+            Edje *ed = _edje_fetch(obj->eo);
+            Edje_Real_Part *rp = _edje_real_part_recursive_get(ed, key);
+            if (rp)
+              {
+                 // check if lua userdata exists
+                 Evas_Object *part = (Evas_Object *) edje_object_part_object_get(obj->eo, key);
+                 _edje_lua_get_reg(L, part);
+                 if (lua_isnil(L, -1))
+                   {
+                      // create it
+                      lua_pop(L, 1);
+                      Edje_Lua_Edje_Part_Object *tar =
+                         lua_newuserdata(L, sizeof(Edje_Lua_Edje_Part_Object));
+                      tar->eo = part;
+                      tar->ed = ed;
+                      tar->key = key;
+                      tar->L = L;
+                      tar->rp = rp;
+                      _edje_lua_set_class(L, -1, cPart);
+                      _edje_lua_new_reg(L, -1, tar); // freed in _edje_lua_edje_part_del_cb
+                      _edje_lua_new_reg(L, -1, part); // freed in _edje_lua_edje_part_del_cb
+                      evas_object_event_callback_add(tar->eo,
+                                                     EVAS_CALLBACK_DEL,
+                                                     _edje_lua_edje_part_del_cb,
+                                                     L);
+                   }
+              }
+            else
+              {
+                 // look in obj environment table
+                 lua_getfenv(L, 1);
+                 lua_pushvalue(L, 2);  // key
+                 lua_rawget(L, -2);
+              }
+         }
+     }
+   return 1;
+}
+
+const luaL_Reg lGroup_mt[] = {
+   {"__index", _edje_lua_group_mt_index},
+   {NULL, NULL}                        // sentinel
+};
+
+static int
+_edje_lua_group_get_group(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mGroup);
+   const char *file, *group;
+   edje_object_file_get(obj->eo, &file, &group);
+   lua_pushstring(L, group);
+   return 1;
+}
+
+static int
+_edje_lua_group_get_mouse(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mGroup);
+   int x, y;
+   evas_pointer_canvas_xy_get(evas_object_evas_get(obj->eo), &x, &y);
+   x -= obj->ed->x;
+   y -= obj->ed->y;
+   lua_createtable(L, 2, 0);
+   lua_pushnumber(L, x);
+   lua_rawseti(L, -2, 1);
+   lua_pushnumber(L, y);
+   lua_rawseti(L, -2, 2);
+   return 1;
+}
+
+static int
+_edje_lua_group_get_mouse_buttons(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mGroup);
+   lua_pushnumber(L, evas_pointer_button_down_mask_get(obj->ed->evas));
+   return 1;
+}
+
+static int
+_edje_lua_group_get_size_min(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mGroup);
+   int w, h;
+   edje_object_size_min_get(obj->eo, &w, &h);
+   lua_createtable(L, 2, 0);
+   lua_pushnumber(L, w);
+   lua_rawseti(L, -2, 1);
+   lua_pushnumber(L, h);
+   lua_rawseti(L, -2, 2);
+   return 1;
+}
+
+static int
+_edje_lua_group_get_size_max(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mGroup);
+   int w, h;
+   edje_object_size_max_get(obj->eo, &w, &h);
+   lua_createtable(L, 2, 0);
+   lua_pushnumber(L, w);
+   lua_rawseti(L, -2, 1);
+   lua_pushnumber(L, h);
+   lua_rawseti(L, -2, 2);
+   return 1;
+}
+
+static int
+_edje_lua_group_get_scale(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mGroup);
+   lua_pushnumber(L, edje_object_scale_get(obj->eo));
+   return 1;
+}
+
+static int
+_edje_lua_group_get_load_error(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mGroup);
+   lua_pushnumber(L, edje_object_load_error_get(obj->eo));
+   return 1;
+}
+
+static int
+_edje_lua_group_get_load_error_str(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mGroup);
+   lua_pushstring(L, edje_load_error_str(edje_object_load_error_get(obj->eo)));
+   return 1;
+}
+
+static int
+_edje_lua_group_get_play(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mGroup);
+   lua_pushboolean(L, edje_object_play_get(obj->eo));
+   return 1;
+}
+
+static int
+_edje_lua_group_get_animation(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mGroup);
+   lua_pushboolean(L, edje_object_animation_get(obj->eo));
+   return 1;
+}
+
+static int
+_edje_lua_group_get_frametime(lua_State *L)
+{
+   lua_pushnumber(L, edje_frametime_get());
+   return 1;
+}
+
+/**
+@page luaref
+@attributes
+@li Group.group
+@li Group.mouse: (x,y)
+@li Group.mouse_buttons
+@li Group.size_min: (w,h)
+@li Group.size_max: (w,h)
+@li Group.scale
+@li Group.load_error
+@li Group.load_error_str
+@li Group.play
+@li Group.animation
+@li Group.frametime 
+*/
+const luaL_Reg lGroup_get[] = {
+   {"group", _edje_lua_group_get_group},
+   {"mouse", _edje_lua_group_get_mouse},
+   {"mouse_buttons", _edje_lua_group_get_mouse_buttons},
+   {"size_min", _edje_lua_group_get_size_min},
+   {"size_max", _edje_lua_group_get_size_max},
+   {"scale", _edje_lua_group_get_scale},
+   {"load_error", _edje_lua_group_get_load_error},
+   {"load_error_str", _edje_lua_group_get_load_error_str},
+   {"play", _edje_lua_group_get_play},
+   {"animation", _edje_lua_group_get_animation},
+   {"frametime", _edje_lua_group_get_frametime},
+   {NULL, NULL}                        // sentinel
+};
+
+static int
+_edje_lua_group_set_group(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mGroup);
+   edje_object_file_set(obj->eo, obj->ed->file->path, luaL_checkstring(L, 2));
+   return 0;
+}
+
+static int
+_edje_lua_group_set_size_min(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mGroup);
+
+   luaL_checktype(L, 2, LUA_TTABLE);
+   lua_rawgeti(L, 2, 1);
+   lua_rawgeti(L, 2, 2);
+   obj->ed->collection->prop.min.w = luaL_checkint(L, -2);
+   obj->ed->collection->prop.min.h = luaL_checkint(L, -1);
+   obj->ed->dirty = 1;
+   _edje_recalc(obj->ed);
+   return 0;
+}
+
+static int
+_edje_lua_group_set_size_max(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mGroup);
+   luaL_checktype(L, 2, LUA_TTABLE);
+   lua_rawgeti(L, 2, 1);
+   lua_rawgeti(L, 2, 2);
+   obj->ed->collection->prop.max.w = luaL_checkint(L, -2);
+   obj->ed->collection->prop.max.h = luaL_checkint(L, -1);
+   obj->ed->dirty = 1;
+   _edje_recalc(obj->ed);
+   return 0;
+}
+
+static int
+_edje_lua_group_set_scale(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mGroup);
+   edje_object_scale_set(obj->eo, luaL_checknumber(L, 2));
+   return 0;
+}
+
+static int
+_edje_lua_group_set_play(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mGroup);
+   edje_object_play_set(obj->eo, lua_toboolean(L, 2));
+   return 0;
+}
+
+static int
+_edje_lua_group_set_animation(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mGroup);
+   edje_object_animation_set(obj->eo, lua_toboolean(L, 2));
+   return 0;
+}
+
+static void
+_edje_lua_group_text_change_cb(void* data, Evas_Object *obj, const char* part)
+{
+   Edje_Lua_Ref *ref = data;
+   lua_State *L = ref->L;
+   int err_code;
+
+   _edje_lua_get_ref(L, ref);
+   _edje_lua_get_reg(L, obj);
+   lua_pushstring(L, part);
+
+   if ((err_code = lua_pcall(L, 2, 0, 0)))
+     _edje_lua_error(L, err_code);
+}
+
+static int
+_edje_lua_group_set_text_change_cb(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mGroup);
+   edje_object_text_change_cb_set(obj->eo, _edje_lua_group_text_change_cb, _edje_lua_new_ref(L, 2));
+   return 0;
+}
+
+static int
+_edje_lua_group_set_frametime(lua_State *L)
+{
+   edje_frametime_set(luaL_checknumber(L, 2));
+   return 0;
+}
+/**
+@page luaref
+@setters
+@li Group.group
+@li Group.size_min: (w,h)
+@li Group.size_max: (w,h)
+@li Group.scale
+@li Group.play
+@li Group.animation
+@li Group.text_change_cb
+@li Group.frametime
+*/
+const luaL_Reg lGroup_set[] = {
+   {"group", _edje_lua_group_set_group},
+   {"size_min", _edje_lua_group_set_size_min},
+   {"size_max", _edje_lua_group_set_size_max},
+   {"scale", _edje_lua_group_set_scale},
+   {"play", _edje_lua_group_set_play},
+   {"animation", _edje_lua_group_set_animation},
+   {"text_change_cb", _edje_lua_group_set_text_change_cb},
+   {"frametime", _edje_lua_group_set_frametime},
+   {NULL, NULL}                        // sentinel
+};
+
+static int
+_edje_lua_group_fn_timer(lua_State *L)
+{
+   Edje_Lua_Timer *tar = lua_newuserdata(L, sizeof(Edje_Lua_Timer));
+   
+   _edje_lua_set_class(L, -1, cTimer);
+   /* ^^^^^^^^^^^^^^^^(L, index, class)
+   lua_newtable(L);
+   if (index < 0)
+      lua_setfenv(L, index - 1);
+   else
+      lua_setfenv(L, index);
+
+   _edje_lua_get_metatable(L, class);
+   if (index < 0)
+      lua_setmetatable(L, index - 1);
+   else
+      lua_setmetatable(L, index);
+    */
+   
+   tar->et = ecore_timer_add(luaL_checknumber(L, 2), _edje_lua_timer_cb, tar);
+   tar->L = L;
+   
+   _edje_lua_new_reg(L, -1, tar); // freed in _edje_lua_timer_cb/del
+   /* ^^^^^^^^^^^^^^(L, index, ptr)   
+   lua_pushvalue(L, index);
+   lua_pushlightuserdata(L, ptr);
+   lua_insert(L, -2);
+   lua_rawset(L, LUA_REGISTRYINDEX); // freed in _edje_lua_free_reg
+    */
+   
+   tar->cb = _edje_lua_new_ref(L, 3); // freed in _edje_lua_timer_cb/del
+   /* ^^^^^^^^^^^^^^^^^^^^^^^^(L, index)
+   lua_pushvalue(L, index);
+   Edje_Lua_Ref *ref = malloc(sizeof(Edje_Lua_Ref));
+   ref->id = luaL_ref(L, LUA_REGISTRYINDEX);
+   ref->L = L;
+   return ref;
+    */
+   return 1;
+}
+
+static int
+_edje_lua_group_fn_animator(lua_State *L)
+{
+   Edje_Lua_Animator *tar = lua_newuserdata(L, sizeof(Edje_Lua_Animator));
+   _edje_lua_set_class(L, -1, cAnimator);
+   tar->ea = ecore_animator_add(_edje_lua_animator_cb, tar);
+   tar->L = L;
+   _edje_lua_new_reg(L, -1, tar); // freed in _edje_lua_animator_cb/del
+   tar->cb = _edje_lua_new_ref(L, 2); // freed in _edje_lua_animator_cb/del
+   return 1;
+}
+
+static int
+_edje_lua_group_fn_poller(lua_State *L)
+{
+   int interval;
+   Edje_Lua_Poller *tar;
+   tar = lua_newuserdata(L, sizeof(Edje_Lua_Poller));
+   _edje_lua_set_class(L, -1, cPoller);
+   
+   interval = luaL_checknumber(L, 2);
+   if ((interval <= 0) || ((interval & 1) != 0))
+     {
+       return 0;
+     }
+
+   // Only 1 type of poller currently implemented in ecore
+   tar->ep = ecore_poller_add(ECORE_POLLER_CORE, interval, 
+                          _edje_lua_poller_cb, tar);
+   tar->L = L;
+   _edje_lua_new_reg(L, -1, tar); // freed in _edje_lua_poller_cb/del
+   tar->cb = _edje_lua_new_ref(L, 3); // freed in _edje_lua_poller_cb/del
+
+   return 1;
+}
+
+static int
+_edje_lua_group_fn_transform(lua_State *L)
+{
+   Edje_Lua_Transform *tar = lua_newuserdata(L, sizeof(Edje_Lua_Transform));
+   evas_transform_identity_set (&(tar->et));
+   _edje_lua_set_class(L, -1, cTransform);
+   tar->L = L;
+   return 1;
+}
+
+static int
+_edje_lua_group_fn_signal_emit(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mGroup);
+   edje_object_signal_emit(obj->eo,
+                          luaL_checkstring(L, 2), luaL_checkstring(L, 3));
+   return 0;
+}
+
+static Edje_Program *
+_edje_lua_program_get_byname(Evas_Object * obj, const char *prog_name)
+{
+   Edje_Program *epr;
+   int i;
+   Edje *ed;
+   ed = _edje_fetch(obj);
+   if (!ed)
+      return NULL;
+   if (!prog_name)
+      return NULL;
+   for (i = 0; i < ed->table_programs_size; i++)
+     {
+       epr = ed->table_programs[i];
+       if ((epr->name) && (strcmp(epr->name, prog_name) == 0))
+          return epr;
+     }
+   return NULL;
+}
+
+static int
+_edje_lua_group_fn_program_run(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mGroup);
+   Edje_Program *pr =
+      _edje_lua_program_get_byname(obj->eo, luaL_checkstring(L, 2));
+   if (pr)
+      _edje_program_run(obj->ed, pr, 0, "", "");
+   return 0;
+}
+
+static int
+_edje_lua_group_fn_program_stop(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mGroup);
+   Edje_Program *pr =
+      _edje_lua_program_get_byname(obj->eo, luaL_checkstring(L, 2));
+   int program_id = pr->id;
+   Edje_Running_Program *runp;
+   Eina_List *l;
+   obj->ed->walking_actions = 1;
+   EINA_LIST_FOREACH(obj->ed->actions, l, runp)
+      if (program_id == runp->program->id)
+      _edje_program_end(obj->ed, runp);
+   obj->ed->walking_actions = 0;
+   return 0;
+}
+
+static int
+_edje_lua_group_fn_message_send(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mGroup);
+   int type = luaL_checkint(L, 2);
+   void *msg = NULL;
+   int i;
+   int size;
+   switch (type)
+     {
+     case EDJE_MESSAGE_NONE:
+       break;
+     case EDJE_MESSAGE_SIGNAL:
+       break;
+     case EDJE_MESSAGE_STRING:
+         {
+            Edje_Message_String *msg_string =
+               malloc(sizeof(Edje_Message_String));
+            msg_string->str = (char *)luaL_checkstring(L, 4);
+            msg = msg_string;
+         }
+       break;
+     case EDJE_MESSAGE_INT:
+         {
+            Edje_Message_Int *msg_int = malloc(sizeof(Edje_Message_Int));
+
+            msg_int->val = luaL_checkint(L, 4);
+            msg = msg_int;
+         }
+       break;
+     case EDJE_MESSAGE_FLOAT:
+         {
+            Edje_Message_Float *msg_float = malloc(sizeof(Edje_Message_Float));
+
+            msg_float->val = luaL_checknumber(L, 4);
+            msg = msg_float;
+         }
+       break;
+     case EDJE_MESSAGE_STRING_SET:
+         {
+            if (lua_type(L, 4) != LUA_TTABLE)
+              break;
+            size = lua_objlen(L, 4);
+            Edje_Message_String_Set *msg_string_set =
+               malloc(sizeof(Edje_Message_String_Set) +
+                     (size - 1) * sizeof(char *));
+            msg_string_set->count = size;
+            for (i = 0; i < size; i++)
+              {
+                 lua_rawgeti(L, 4, i + 1);
+                 msg_string_set->str[i] = (char *)luaL_checkstring(L, -1);
+                 lua_pop(L, 1);
+              }
+            msg = msg_string_set;
+         }
+       break;
+     case EDJE_MESSAGE_INT_SET:
+         {
+            if (lua_type(L, 4) != LUA_TTABLE)
+              break;
+            size = lua_objlen(L, 4);
+            Edje_Message_Int_Set *msg_int_set =
+               malloc(sizeof(Edje_Message_Int_Set) + (size - 1) * sizeof(int));
+            msg_int_set->count = size;
+            for (i = 0; i < size; i++)
+              {
+                 lua_rawgeti(L, 4, i + 1);
+                 msg_int_set->val[i] = luaL_checkint(L, -1);
+                 lua_pop(L, 1);
+              }
+            msg = msg_int_set;
+         }
+       break;
+     case EDJE_MESSAGE_FLOAT_SET:
+         {
+            if (lua_type(L, 4) != LUA_TTABLE)
+              break;
+            size = lua_objlen(L, 4);
+            Edje_Message_Float_Set *msg_float_set =
+               malloc(sizeof(Edje_Message_Float_Set) +
+                     (size - 1) * sizeof(double));
+            msg_float_set->count = size;
+            for (i = 0; i < size; i++)
+              {
+                 lua_rawgeti(L, 4, i + 1);
+                 msg_float_set->val[i] = luaL_checknumber(L, -1);
+                 lua_pop(L, 1);
+              }
+            msg = msg_float_set;
+         }
+       break;
+     case EDJE_MESSAGE_STRING_INT:
+         {
+            Edje_Message_String_Int *msg_string_int =
+               malloc(sizeof(Edje_Message_String_Int));
+            msg_string_int->str = (char *)luaL_checkstring(L, 4);
+            msg_string_int->val = luaL_checkint(L, 5);
+            msg = msg_string_int;
+         }
+       break;
+     case EDJE_MESSAGE_STRING_FLOAT:
+         {
+            Edje_Message_String_Float *msg_string_float =
+               malloc(sizeof(Edje_Message_String_Float));
+            msg_string_float->str = (char *)luaL_checkstring(L, 4);
+            msg_string_float->val = luaL_checknumber(L, 5);
+            msg = msg_string_float;
+         }
+       break;
+     case EDJE_MESSAGE_STRING_INT_SET:
+         {
+            if (lua_type(L, 5) != LUA_TTABLE)
+              break;
+            size = lua_objlen(L, 5);
+            Edje_Message_String_Int_Set *msg_string_int_set =
+               malloc(sizeof(Edje_Message_String_Int_Set) +
+                     (size - 1) * sizeof(int));
+            msg_string_int_set->str = (char *)luaL_checkstring(L, 4);
+            msg_string_int_set->count = size;
+            for (i = 0; i < size; i++)
+              {
+                 lua_rawgeti(L, 5, i + 1);
+                 msg_string_int_set->val[i] = luaL_checkint(L, -1);
+                 lua_pop(L, 1);
+              }
+            msg = msg_string_int_set;
+         }
+       break;
+     case EDJE_MESSAGE_STRING_FLOAT_SET:
+         {
+            if (lua_type(L, 5) != LUA_TTABLE)
+              break;
+            size = lua_objlen(L, 5);
+            Edje_Message_String_Float_Set *msg_string_float_set =
+               malloc(sizeof(Edje_Message_String_Float_Set) +
+                     (size - 1) * sizeof(double));
+            msg_string_float_set->str = (char *)luaL_checkstring(L, 4);
+            msg_string_float_set->count = size;
+            for (i = 0; i < size; i++)
+              {
+                 lua_rawgeti(L, 5, i + 1);
+                 msg_string_float_set->val[i] = luaL_checknumber(L, -1);
+                 lua_pop(L, 1);
+              }
+            msg = msg_string_float_set;
+         }
+       break;
+     default:
+       break;
+     }
+
+   if (msg)
+     {
+       edje_object_message_send(obj->eo, type, luaL_checkint(L, 3), msg);
+       free(msg);
+     }
+
+   return 0;
+}
+
+static void
+_edje_lua_group_signal_callback(void *data, Evas_Object * edj,
+                               const char *signal, const char *source)
+{
+   Edje_Lua_Ref *cb = data;
+   lua_State *L = cb->L;
+   _edje_lua_get_ref(L, cb);   // signal callback function
+   if (lua_isfunction(L, -1))
+     {
+       int err_code;
+
+       _edje_lua_get_reg(L, edj);
+       lua_pushstring(L, signal);      // signal
+       lua_pushstring(L, source);      // source
+
+        if ((err_code = lua_pcall(L, 3, 0, 0)))
+          _edje_lua_error(L, err_code);
+     }
+}
+
+static int
+_edje_lua_group_fn_signal_callback_add(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mGroup);
+   if (lua_type(L, 4) == LUA_TFUNCTION)
+     {
+       Edje_Lua_Ref *ref = _edje_lua_new_ref(L, 4);
+       obj->cb = eina_list_append(obj->cb, ref);
+       edje_object_signal_callback_add(obj->eo,
+                                       luaL_checkstring(L, 2),
+                                       luaL_checkstring(L, 3),
+                                       _edje_lua_group_signal_callback,
+                                       ref); // freed in _edje_lua_group_fn_signal_callback_del
+     }
+   return 0;
+}
+
+static int
+_edje_lua_group_fn_signal_callback_del(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mGroup);
+   Edje_Lua_Ref *ref = edje_object_signal_callback_del(obj->eo,
+                                  luaL_checkstring(L, 2),
+                                  luaL_checkstring(L, 3),
+                                  _edje_lua_group_signal_callback);
+   obj->cb = eina_list_remove(obj->cb, ref);
+   _edje_lua_free_ref(L, ref); // created in _edje_lua_group_fn_signal_callback_add
+   return 0;
+}
+
+static int
+_edje_lua_group_fn_freeze(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mGroup);
+   edje_object_freeze(obj->eo);
+   return 0;
+}
+
+static int
+_edje_lua_group_fn_thaw(lua_State *L)
+{
+   Edje_Lua_Evas_Object *obj = _edje_lua_checkudata(L, 1, &mGroup);
+   edje_object_thaw(obj->eo);
+   return 0;
+}
+
+/**
+@page luaref
+@methods
+@li @ref Timer Group:timer(secs, callback)
+@li @ref Animator Group:animator(func)
+@li @ref Poller Group:poller(interval, callback)
+@li @ref Transform Group:transform()
+@li Group:signal_emit(emission, source)
+@li Group:message_send(message_type, id, msg)
+@li Group:program_run(name)
+@li Group:program_stop(name)
+@li Group:signal_callback_add(emission, source, callback)
+@li Group:signal_callback_del(emission, source)
+@li Group:freeze()
+@li Group:thaw()
+*/
+const luaL_Reg lGroup_fn[] = {
+   {"timer", _edje_lua_group_fn_timer},
+   {"animator", _edje_lua_group_fn_animator},
+   {"poller", _edje_lua_group_fn_poller},
+   {"transform", _edje_lua_group_fn_transform},
+   {"signal_emit", _edje_lua_group_fn_signal_emit},
+   {"message_send", _edje_lua_group_fn_message_send},
+   {"program_run", _edje_lua_group_fn_program_run},
+   {"program_stop", _edje_lua_group_fn_program_stop},
+   {"signal_callback_add", _edje_lua_group_fn_signal_callback_add},
+   {"signal_callback_del", _edje_lua_group_fn_signal_callback_del},
+   {"freeze", _edje_lua_group_fn_freeze},
+   {"thaw", _edje_lua_group_fn_thaw},
+   {NULL, NULL}                        // sentinel
+};
+
+/*
+ * Lua bindings
+ */
+
+const luaL_Reg lScript_get[];
+
+const luaL_Reg lScript_set[];
+
+const luaL_Reg lScript_fn[];
+
+const Edje_Lua_Reg mScript = {
+   lNil,
+   lScript_get,
+   lScript_set,
+   lScript_fn
+};
+
+const Edje_Lua_Reg *cScript[] = {
+   &mClass,
+   &mObject,
+   &mGroup,
+   &mScript,
+   NULL                                // sentinel
+};
+
+/*
+ * macro for adding an evas_object in the lua_script_only object
+ */
+#define _EDJE_LUA_SCRIPT_FN_ADD(DEF, CLASS, FUNC)                      \
+  static int                                                           \
+  DEF (lua_State *L)                                                   \
+  {                                                                    \
+     int set = lua_gettop (L) == 2;                                    \
+     Edje_Lua_Evas_Object *obj = _edje_lua_checkudata (L, 1, &mScript); \
+     Edje_Lua_Evas_Object *tar = lua_newuserdata (L, sizeof (Edje_Lua_Evas_Object)); \
+     _edje_lua_set_class (L, -1, CLASS);                               \
+     tar->eo = FUNC (obj->ed->evas);                                   \
+     tar->ed = obj->ed;                                                        \
+     tar->L = L;                                                       \
+     tar->cb = NULL;                                                   \
+     evas_object_move (tar->eo, obj->ed->x, obj->ed->y);               \
+     _edje_lua_new_reg (L, -1, tar); /* freed in _edje_lua_object_del_cb */ \
+     _edje_lua_new_reg (L, -1, tar->eo); /* freed in _edje_lua_object_del_cb */ \
+     evas_object_smart_member_add (tar->eo, obj->eo);                  \
+     evas_object_clip_set (tar->eo, obj->ed->clipper);                 \
+     evas_object_event_callback_add (tar->eo, EVAS_CALLBACK_DEL, _edje_lua_object_del_cb, L); \
+     if (set)                                                          \
+       {                                                               \
+         int err_code;                                                 \
+         lua_getfield (L, -1, "set");                                  \
+         lua_pushvalue (L, -2);                                        \
+         lua_pushvalue (L, 2);                                         \
+          if ((err_code = lua_pcall (L, 2, 0, 0)))                     \
+            _edje_lua_error (L, err_code);                             \
+       }                                                               \
+     return 1;                                                         \
+  }
+
+_EDJE_LUA_SCRIPT_FN_ADD(_edje_lua_script_fn_rectangle,
+                       cRectangle,
+                       evas_object_rectangle_add)
+_EDJE_LUA_SCRIPT_FN_ADD(_edje_lua_script_fn_image,
+                       cImage,
+                       evas_object_image_add)
+_EDJE_LUA_SCRIPT_FN_ADD(_edje_lua_script_fn_table,
+                       cTable,
+                       evas_object_table_add)
+_EDJE_LUA_SCRIPT_FN_ADD(_edje_lua_script_fn_line,
+                       cLine,
+                       evas_object_line_add)
+_EDJE_LUA_SCRIPT_FN_ADD(_edje_lua_script_fn_polygon,
+                       cPolygon,
+                       evas_object_polygon_add)
+_EDJE_LUA_SCRIPT_FN_ADD(_edje_lua_script_fn_group, cGroup, edje_object_add)
+
+const luaL_Reg lScript_fn[] = {
+   {"rectangle", _edje_lua_script_fn_rectangle},
+   {"image", _edje_lua_script_fn_image},
+   {"table", _edje_lua_script_fn_table},
+   {"line", _edje_lua_script_fn_line},
+   {"polygon", _edje_lua_script_fn_polygon},
+   {"group", _edje_lua_script_fn_group},
+   {NULL, NULL}                        // sentinel
+};
+
+const luaL_Reg lScript_get[] = {
+   {NULL, NULL}                        // sentinel
+};
+
+const luaL_Reg lScript_set[] = {
+   {NULL, NULL}                        // sentinel
+};
+
+/*
+ * creates and exports a lua_script_only object
+ */
+void
+_edje_lua_script_fn_new(Edje * ed)
+{
+   lua_State *L = ed->L;
+   Edje_Lua_Evas_Object *tar = lua_newuserdata(L, sizeof(Edje_Lua_Evas_Object));
+   _edje_lua_set_class(L, -1, cScript);
+   tar->eo = ed->obj;
+   tar->ed = ed;
+   tar->L = L;
+   tar->cb = NULL;
+   _edje_lua_new_reg(L, -1, tar); // freed in _edje_lua_object_del_cb
+   _edje_lua_new_reg(L, -1, ed); // freed in edje_load.c::_edje_file_del
+   _edje_lua_new_reg(L, -1, ed->obj); // freed in _edje_lua_object_del_cb
+   evas_object_event_callback_add(tar->eo, EVAS_CALLBACK_DEL,
+                                 _edje_lua_object_del_cb, L);
+}
+
+/*
+ * creates and exports an Edje group with associated Lua scripts in the parts and programs sections
+ */
+void
+_edje_lua_group_fn_new(Edje * ed)
+{
+   lua_State *L = ed->L;
+   Edje_Lua_Evas_Object *tar = lua_newuserdata(L, sizeof(Edje_Lua_Evas_Object));
+   _edje_lua_set_class(L, -1, cGroup);
+   tar->eo = ed->obj;
+   tar->ed = ed;
+   tar->L = L;
+   tar->cb = NULL;
+   _edje_lua_new_reg(L, -1, tar); // freed in _edje_lua_object_del_cb
+   _edje_lua_new_reg(L, -1, ed); // freed in edje_load.c::_edje_file_del
+   _edje_lua_new_reg(L, -1, ed->obj); // freed in _edje_lua_object_del_cb
+   evas_object_event_callback_add(tar->eo, EVAS_CALLBACK_DEL,
+                                 _edje_lua_object_del_cb, L);
+}
+
+/*
+ * this function loads all the Lua bindings into the global Lua state
+ */
+static void
+_edje_lua_open(lua_State *L)
+{
+   /*
+    * export classes
+    */
+   _edje_lua_new_class(L, cTimer);
+   _edje_lua_new_class(L, cAnimator);
+   _edje_lua_new_class(L, cPoller);
+   _edje_lua_new_class(L, cTransform);
+   _edje_lua_new_class(L, cRectangle);
+   _edje_lua_new_class(L, cImage);
+   _edje_lua_new_class(L, cTable);
+   _edje_lua_new_class(L, cLine);
+   _edje_lua_new_class(L, cPolygon);
+   _edje_lua_new_class(L, cGroup);
+   _edje_lua_new_class(L, cDescription);
+   _edje_lua_new_class(L, cPart);
+   _edje_lua_new_class(L, cScript);
+
+   /*
+    * export constants
+    */
+   _edje_lua_new_const(L, "MESSAGE_NONE", EDJE_MESSAGE_NONE);
+   _edje_lua_new_const(L, "MESSAGE_SIGNAL", EDJE_MESSAGE_SIGNAL);
+   _edje_lua_new_const(L, "MESSAGE_STRING", EDJE_MESSAGE_STRING);
+   _edje_lua_new_const(L, "MESSAGE_INT", EDJE_MESSAGE_INT);
+   _edje_lua_new_const(L, "MESSAGE_FLOAT", EDJE_MESSAGE_FLOAT);
+   _edje_lua_new_const(L, "MESSAGE_STRING_SET", EDJE_MESSAGE_STRING_SET);
+   _edje_lua_new_const(L, "MESSAGE_INT_SET", EDJE_MESSAGE_INT_SET);
+   _edje_lua_new_const(L, "MESSAGE_FLOAT_SET", EDJE_MESSAGE_FLOAT_SET);
+   _edje_lua_new_const(L, "MESSAGE_STRING_INT", EDJE_MESSAGE_STRING_INT);
+   _edje_lua_new_const(L, "MESSAGE_STRING_FLOAT", EDJE_MESSAGE_STRING_FLOAT);
+   _edje_lua_new_const(L, "MESSAGE_STRING_INT_SET", EDJE_MESSAGE_STRING_INT_SET);
+   _edje_lua_new_const(L, "MESSAGE_STRING_FLOAT_SET", EDJE_MESSAGE_STRING_FLOAT_SET);
+
+   _edje_lua_new_const(L, "PART_TYPE_NONE", EDJE_PART_TYPE_NONE);
+   _edje_lua_new_const(L, "PART_TYPE_RECTANGLE", EDJE_PART_TYPE_RECTANGLE);
+   _edje_lua_new_const(L, "PART_TYPE_TEXT", EDJE_PART_TYPE_TEXT);
+   _edje_lua_new_const(L, "PART_TYPE_IMAGE", EDJE_PART_TYPE_IMAGE);
+   _edje_lua_new_const(L, "PART_TYPE_SWALLOW", EDJE_PART_TYPE_SWALLOW);
+   _edje_lua_new_const(L, "PART_TYPE_TEXTBLOCK", EDJE_PART_TYPE_TEXTBLOCK);
+   _edje_lua_new_const(L, "PART_TYPE_GRADIENT", EDJE_PART_TYPE_GRADIENT);
+   _edje_lua_new_const(L, "PART_TYPE_GROUP", EDJE_PART_TYPE_GROUP);
+   _edje_lua_new_const(L, "PART_TYPE_BOX", EDJE_PART_TYPE_BOX);
+
+   _edje_lua_new_const(L, "TEXT_EFFECT_NONE", EDJE_TEXT_EFFECT_NONE);
+   _edje_lua_new_const(L, "TEXT_EFFECT_PLAIN", EDJE_TEXT_EFFECT_PLAIN);
+   _edje_lua_new_const(L, "TEXT_EFFECT_OUTLINE", EDJE_TEXT_EFFECT_OUTLINE);
+   _edje_lua_new_const(L, "TEXT_EFFECT_OTLINE", EDJE_TEXT_EFFECT_SOFT_OUTLINE);
+   _edje_lua_new_const(L, "TEXT_EFFECT_SHADOW", EDJE_TEXT_EFFECT_SHADOW);
+   _edje_lua_new_const(L, "TEXT_EFFECT_SOFT_SHADOW", EDJE_TEXT_EFFECT_SOFT_SHADOW);
+   _edje_lua_new_const(L, "TEXT_EFFECT_OUTLINE_SHADOW", EDJE_TEXT_EFFECT_OUTLINE_SHADOW);
+   _edje_lua_new_const(L, "TEXT_EFFECT_OUTLINE_SOFT_SHADOW", EDJE_TEXT_EFFECT_OUTLINE_SOFT_SHADOW);
+   _edje_lua_new_const(L, "TEXT_EFFECT_FAR_SHADOW", EDJE_TEXT_EFFECT_FAR_SHADOW);
+   _edje_lua_new_const(L, "TEXT_EFFECT_FAR_SOFT_SHADOW", EDJE_TEXT_EFFECT_FAR_SOFT_SHADOW);
+   _edje_lua_new_const(L, "TEXT_EFFECT_GLOW", EDJE_TEXT_EFFECT_GLOW);
+
+   _edje_lua_new_const(L, "RENDER_BLEND", EVAS_RENDER_BLEND);
+   _edje_lua_new_const(L, "RENDER_BLEND_REL", EVAS_RENDER_BLEND_REL);
+   _edje_lua_new_const(L, "RENDER_COPY", EVAS_RENDER_COPY);
+   _edje_lua_new_const(L, "RENDER_COPY_REL", EVAS_RENDER_COPY_REL);
+   _edje_lua_new_const(L, "RENDER_ADD", EVAS_RENDER_ADD);
+   _edje_lua_new_const(L, "RENDER_ADD_REL", EVAS_RENDER_ADD_REL);
+   _edje_lua_new_const(L, "RENDER_SUB", EVAS_RENDER_SUB);
+   _edje_lua_new_const(L, "RENDER_SUB_REL", EVAS_RENDER_SUB_REL);
+   _edje_lua_new_const(L, "RENDER_TINT", EVAS_RENDER_TINT);
+   _edje_lua_new_const(L, "RENDER_TINT_REL", EVAS_RENDER_TINT_REL);
+   _edje_lua_new_const(L, "RENDER_MASK", EVAS_RENDER_MASK);
+   _edje_lua_new_const(L, "RENDER_MUL", EVAS_RENDER_MUL);
+
+   _edje_lua_new_const(L, "BORDER_FILL_NONE", EVAS_BORDER_FILL_NONE);
+   _edje_lua_new_const(L, "BORDER_FILL_DEFAULT", EVAS_BORDER_FILL_DEFAULT);
+   _edje_lua_new_const(L, "BORDER_FILL_SOLID", EVAS_BORDER_FILL_SOLID);
+
+   _edje_lua_new_const(L, "POINTER_MODE_AUTOGRAB", EVAS_OBJECT_POINTER_MODE_AUTOGRAB);
+   _edje_lua_new_const(L, "POINTER_MODE_NOGRAB", EVAS_OBJECT_POINTER_MODE_NOGRAB);
+
+   _edje_lua_new_const(L, "ASPECT_CONTROL_NEITHER", EVAS_ASPECT_CONTROL_NEITHER);
+   _edje_lua_new_const(L, "ASPECT_CONTROL_HORIZONTAL", EVAS_ASPECT_CONTROL_HORIZONTAL);
+   _edje_lua_new_const(L, "ASPECT_CONTROL_VERTICAL", EVAS_ASPECT_CONTROL_VERTICAL);
+   _edje_lua_new_const(L, "ASPECT_CONTROL_BOTH", EVAS_ASPECT_CONTROL_BOTH);
+
+   _edje_lua_new_const(L, "CALLBACK_RENEW", ECORE_CALLBACK_RENEW);
+   _edje_lua_new_const(L, "CALLBACK_CANCEL", ECORE_CALLBACK_CANCEL);
+}
+
+/*
+ * main Lua state
+ * created by edje_init ()
+ * closed by edje_shutdown ()
+ * any other private Lua state inherits from this global state
+ */
+static lua_State *Ledje = NULL;
+
+lua_State *
+_edje_lua_state_get ()
+{
+   return Ledje;
+}
+
+/*
+ * custom memory allocation function
+ * raises an error, if memory usage is above the given maximum
+ */
+static void *
+_edje_lua_alloc(void *ud, void *ptr, size_t osize, size_t nsize)
+{
+   Edje_Lua_Alloc *ela = ud;
+   void *ptr2;
+   
+   ela->cur += nsize - osize;
+   if (ela->cur > ela->max)
+     {
+        ERR("Edje Lua memory limit of %zu bytes reached (%zu allocated)",
+           ela->max, ela->cur);
+       return NULL;
+     }
+   if (nsize == 0)
+     {
+       free(ptr); /* ANSI requires that free(NULL) has no effect */
+       return NULL;
+     }
+
+   /* ANSI requires that realloc(NULL, size) == malloc(size) */
+   ptr2 = realloc(ptr, nsize);
+   if (ptr2) return ptr2;
+   ERR("Edje Lua cannot re-allocate %zu bytes\n", nsize);
+   return ptr2;
+}
+
+void
+_edje_lua_init()
+{
+   if (Ledje != NULL) return;
+   /*
+    * create main Lua state with the custom memory allocation function
+    */
+   static Edje_Lua_Alloc ela = { 1e7, 0 };     // TODO make the memory limit configurable?
+   Ledje = lua_newstate(_edje_lua_alloc, &ela);
+   if (!Ledje)
+     {
+       ERR("Lua error: Lua state could not be initialized");
+       exit(-1);
+     }
+
+   lua_atpanic(Ledje, _edje_lua_custom_panic);
+   
+   /*
+    * configure Lua garbage collector
+    * TODO optimize garbage collector for typical edje use or make it configurable
+    */
+   lua_gc(Ledje, LUA_GCSETPAUSE, 200);
+   lua_gc(Ledje, LUA_GCSETSTEPMUL, 200);
+
+   /*
+    * sandbox Lua
+    * no access to io, os and package routines
+    * no loading and execution of files
+    * no loading and execution of strings
+    * no access to the OS environment
+    */
+   luaopen_base(Ledje);
+   luaopen_table(Ledje);
+   luaopen_string(Ledje);
+   luaopen_math(Ledje);
+   luaopen_os(Ledje);
+
+   /*
+    * FIXME
+    * this is just for debug purposes
+    * remove it in the final version
+    */
+   lua_pushnil(Ledje);
+   lua_setglobal(Ledje, "load");
+   lua_pushnil(Ledje);
+   lua_setglobal(Ledje, "loadfile");
+   lua_pushnil(Ledje);
+   lua_setglobal(Ledje, "loadstring");
+   lua_pushnil(Ledje);
+   lua_setglobal(Ledje, "dofile");
+   lua_pushnil(Ledje);
+   lua_setglobal(Ledje, "dostring");
+
+   lua_getglobal(Ledje, "os");
+   lua_pushnil(Ledje);
+   lua_setfield(Ledje, -2, "exit");
+   lua_pushnil(Ledje);
+   lua_setfield(Ledje, -2, "setlocale");
+   lua_pushnil(Ledje);
+   lua_setfield(Ledje, -2, "getenv");
+   lua_pushnil(Ledje);
+   lua_setfield(Ledje, -2, "remove");
+   lua_pushnil(Ledje);
+   lua_setfield(Ledje, -2, "tmpname");
+   lua_pushnil(Ledje);
+   lua_setfield(Ledje, -2, "rename");
+   lua_pushnil(Ledje);
+   lua_setfield(Ledje, -2, "execute");
+   lua_pushnil(Ledje);
+
+   /*
+    * we need a weak value registry
+    * so that deleted and unused objects can be garbage collected
+    */
+   lua_createtable(Ledje, 1, 0);
+   //lua_pushstring(Ledje, "v"); 
+   lua_pushstring(Ledje, "");
+   lua_setfield(Ledje, -2, "__mode");
+   lua_setmetatable(Ledje, LUA_REGISTRYINDEX);
+
+   /*
+    * load Lua Evas/Edje bindings
+    */
+   _edje_lua_open(Ledje);
+}
+
+void
+_edje_lua_shutdown()
+{
+   if (Ledje == NULL) return;
+   lua_close(Ledje);
+   Ledje = NULL;
+}
diff --git a/src/lib/edje_lua2.c b/src/lib/edje_lua2.c
new file mode 100644 (file)
index 0000000..b18fd3a
--- /dev/null
@@ -0,0 +1,434 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <string.h>
+
+#ifdef HAVE_ALLOCA_H
+# include <alloca.h>
+#elif defined __GNUC__
+# define alloca __builtin_alloca
+#elif defined _AIX
+# define alloca __alloca
+#elif defined _MSC_VER
+# include <malloc.h>
+# define alloca _alloca
+#else
+# include <stddef.h>
+# ifdef  __cplusplus
+extern "C"
+# endif
+  void *alloca(size_t);
+#endif
+
+#include "edje_private.h"
+
+//--------------------------------------------------------------------------//
+#ifdef LUA2
+#define MAX_LUA_MEM (4 * (1024 * 1024))
+
+
+//--------------------------------------------------------------------------//
+typedef struct _Edje_Lua_Alloc Edje_Lua_Alloc;
+typedef struct _Edje_Lua_Obj   Edje_Lua_Obj;
+typedef struct _Edje_Lua_Timer Edje_Lua_Timer;
+typedef struct _Edje_Lua_Anim  Edje_Lua_Anim;
+
+//--------------------------------------------------------------------------//
+struct _Edje_Lua_Alloc
+{
+   size_t max, cur;
+};
+
+struct _Edje_Lua_Obj
+{
+   EINA_INLIST;
+   
+   Edje         *ed;
+   void        (*free_func) (void *obj);
+};
+  
+struct _Edje_Lua_Timer
+{
+   Edje_Lua_Obj     obj;
+   Ecore_Timer     *timer;
+   int              fn_ref;
+};
+
+struct _Edje_Lua_Anim
+{
+   Edje_Lua_Obj     obj;
+   Ecore_Animator  *anim;
+   int              fn_ref;
+};
+
+
+//--------------------------------------------------------------------------//
+static int _elua_obj_gc(lua_State *L);
+static int _elua_obj_del(lua_State *L);
+
+static int _elua_echo(lua_State *L);
+
+static int _elua_timer(lua_State *L);
+static int _elua_anim(lua_State *L);
+
+
+//--------------------------------------------------------------------------//
+static lua_State *lstate = NULL;
+
+static const struct luaL_reg _elua_edje_api [] =
+{
+     {"echo",  _elua_echo}, // test func - echo (i know we have print. test)
+   
+     {"del", _elua_obj_del}, // generic del any object created for edje
+   
+     {"timer", _elua_timer}, // add timer
+     {"anim",  _elua_anim}, // add animator (not done yet)
+   
+     {NULL, NULL} // end
+};
+static const struct luaL_reg _elua_edje_meta [] =
+{
+     {"__gc", _elua_obj_gc}, // garbage collector func for edje objects
+   
+     {NULL, NULL} // end
+};
+static const luaL_Reg _elua_libs[] =
+{
+     {"", luaopen_base},
+//     {LUA_LOADLIBNAME, luaopen_package}, // disable this lib - don't want
+     {LUA_TABLIBNAME, luaopen_table},
+//     {LUA_IOLIBNAME, luaopen_io}, // disable this lib - don't want
+     {LUA_OSLIBNAME, luaopen_os},
+     {LUA_STRLIBNAME, luaopen_string},
+     {LUA_MATHLIBNAME, luaopen_math},
+//     {LUA_DBLIBNAME, luaopen_debug}, // disable this lib - don't want
+
+     {NULL, NULL} // end
+};
+static const char *_elua_key = "key";
+
+
+//--------------------------------------------------------------------------//
+static void *
+_elua_alloc(void *ud, void *ptr, size_t osize, size_t nsize)
+{
+   Edje_Lua_Alloc *ela = ud;
+   void *ptr2;
+   
+   ela->cur += nsize - osize;
+   if (ela->cur > ela->max)
+     {
+        ERR("Edje Lua memory limit of %zu bytes reached (%zu allocated)",
+            ela->max, ela->cur);
+        return NULL;
+     }
+   if (nsize == 0)
+     {
+        free(ptr);
+        return NULL;
+     }
+   
+   ptr2 = realloc(ptr, nsize);
+   if (ptr2) return ptr2;
+   ERR("Edje Lua cannot re-allocate %i bytes\n", nsize);
+   return ptr2;
+}
+
+static int
+_elua_custom_panic(lua_State *L)
+{
+   ERR("Lua Panic!!!!");
+   return 1;
+}
+
+
+//-------------
+void
+_edje_lua2_error_full(const char *file, const char *fnc, int line,
+                      lua_State *L, int err_code)
+{
+   char *err_type;
+   
+   switch (err_code)
+     {
+     case LUA_ERRRUN:
+        err_type = "runtime";
+        break;
+     case LUA_ERRSYNTAX:
+        err_type = "syntax";
+        break;
+     case LUA_ERRMEM:
+        err_type = "memory allocation";
+        break;
+     case LUA_ERRERR:
+        err_type = "error handler";
+        break;
+     default:
+        err_type = "unknown";
+        break;
+     }
+   eina_log_print
+     (_edje_default_log_dom, EINA_LOG_LEVEL_ERR,  file, fnc, line,
+      "Lua %s error: %s", err_type, lua_tostring(L, -1));
+}
+
+static void
+_elua_init(void)
+{
+   static Edje_Lua_Alloc ela = { MAX_LUA_MEM, 0 };
+   const luaL_Reg *l;
+   
+   if (lstate) return;
+   lstate = lua_newstate(_elua_alloc, &ela); //0
+   lua_atpanic(lstate, _elua_custom_panic); //0
+
+// FIXME: figure out optimal gc settings later   
+//   lua_gc(lstate, LUA_GCSETPAUSE, 200); //0
+//   lua_gc(lstate, LUA_GCSETSTEPMUL, 200); //0
+
+   for (l = _elua_libs; l->func; l++)
+     {
+        lua_pushcfunction(lstate, l->func);
+        lua_pushstring(lstate, l->name);
+        lua_call(lstate, 1, 0);
+     }
+   
+   luaL_register(lstate, "edje", _elua_edje_api); //+1
+   
+   luaL_newmetatable(lstate, "edje"); //+1
+   
+   luaL_register(lstate, 0, _elua_edje_meta); //0
+   
+   lua_pushliteral(lstate, "__index"); //+1
+   lua_pushvalue(lstate, -3); //+1
+   lua_rawset(lstate, -3); //-2
+   lua_pop(lstate, 2);
+}
+
+
+//-------------
+static void
+_elua_table_ptr_set(lua_State *L, const void *key, const void *val)
+{
+   lua_pushlightuserdata(L, (void *)key); //+1
+   lua_pushlightuserdata(L, (void *)val); //+1
+   lua_settable(L, LUA_REGISTRYINDEX); //-2
+}
+
+static const void *
+_elua_table_ptr_get(lua_State *L, const void *key)
+{
+   const void *ptr;
+   lua_pushlightuserdata(L, (void *)key); //+1
+   lua_gettable(L, LUA_REGISTRYINDEX); //0
+   ptr = lua_topointer(L, -1); //0
+   lua_pop(L, 1);
+   return ptr;
+}
+
+static void
+_elua_table_ptr_del(lua_State *L, const void *key)
+{
+   lua_pushlightuserdata(L, (void *)key); //+1
+   lua_pushnil(L); //+1
+   lua_settable(L, LUA_REGISTRYINDEX); //-2
+}
+
+static void
+_elua_gc(lua_State *L)
+{
+   lua_gc(L, LUA_GCCOLLECT, 0); //0
+}
+
+//-------------
+static Edje_Lua_Obj *
+_elua_obj_new(lua_State *L, Edje *ed, int size)
+{
+   Edje_Lua_Obj *obj;
+   
+   obj = (Edje_Lua_Obj *)lua_newuserdata(L, size); //+1
+   memset(obj, 0, size);
+   ed->lua_objs = eina_inlist_append(ed->lua_objs, EINA_INLIST_GET(obj));
+   luaL_getmetatable(L, "edje"); //+1
+   lua_setmetatable(L, -2); //-1
+   obj->ed = ed;
+   return obj;
+}
+
+static void
+_elua_obj_free(lua_State *L, Edje_Lua_Obj *obj)
+{
+   if (!obj->free_func) return;
+   obj->free_func(obj);
+   obj->ed->lua_objs = eina_inlist_remove(obj->ed->lua_objs, EINA_INLIST_GET(obj));
+   obj->free_func = NULL;
+   obj->ed = NULL;
+}
+
+//-------------
+static int
+_elua_obj_gc(lua_State *L)
+{
+   Edje_Lua_Obj *obj = (Edje_Lua_Obj *)lua_touserdata(L, 1);
+   if (!obj) return 0;
+   _elua_obj_free(L, obj);
+   return 0;
+}
+
+static int
+_elua_obj_del(lua_State *L)
+{
+   return _elua_obj_gc(L);
+}
+
+//-------------
+static int
+_elua_echo(lua_State *L)
+{
+   const char *string = luaL_checkstring(L, 1); //0
+   printf("%s\n", string);
+   return 1;
+}
+
+
+//-------------
+static int
+_elua_timer_cb(void *data)
+{
+   Edje_Lua_Timer *elt = data;
+   int ret = 0;
+   int err;
+   
+   if (!elt->obj.ed) return 0;
+   lua_rawgeti(lstate, LUA_REGISTRYINDEX, elt->fn_ref); //+1
+   if ((err = lua_pcall(lstate, 0, 1, 0))) //+1
+     {
+        _edje_lua2_error(lstate, err); //0
+        _elua_obj_free(lstate, (Edje_Lua_Obj *)elt);
+        _elua_gc(lstate);
+        return 0;
+     }
+   ret = luaL_checkint(lstate, -1); //0
+   lua_pop(lstate, 1);
+   if (ret == 0)
+     _elua_obj_free(lstate, (Edje_Lua_Obj *)elt);
+   _elua_gc(lstate);
+   return ret;
+}
+
+static void
+_elua_timer_free(void *obj)
+{
+   Edje_Lua_Timer *elt = (Edje_Lua_Timer *)obj;
+   luaL_unref(lstate, LUA_REGISTRYINDEX, elt->fn_ref); //0
+   elt->fn_ref  = 0;
+   ecore_timer_del(elt->timer);
+   elt->timer = NULL;
+}
+
+static int
+_elua_timer(lua_State *L)
+{
+   Edje *ed = (Edje *)_elua_table_ptr_get(L, _elua_key);
+   Edje_Lua_Timer *elt;
+   double val;
+   
+   val = luaL_checknumber(L, 1);
+   luaL_checkany(L, 2);
+  
+   elt = (Edje_Lua_Timer *)_elua_obj_new(L, ed, sizeof(Edje_Lua_Timer)); //+1
+   elt->obj.free_func = _elua_timer_free;
+   elt->timer = ecore_timer_add(val, _elua_timer_cb, elt);
+   lua_pushvalue(L, 2); //+1
+   elt->fn_ref = luaL_ref(L, LUA_REGISTRYINDEX);
+//   lua_pop(ed->L, 2); // don't pop - return back to lua
+   _elua_gc(lstate);
+   return 1;
+}
+
+
+//-------------
+static int
+_elua_anim(lua_State *L)
+{
+   // xxxxx
+   // not done yet - but do like timer (but 1 arg only - no timeout val)
+   // xxxxx
+   Edje *ed = (Edje *)_elua_table_ptr_get(L, _elua_key);
+   return 1;
+}
+
+
+//-------------
+void
+_edje_lua2_script_init(Edje *ed)
+{
+   if (ed->L) return;
+   _elua_init();
+   ed->L = lstate;
+
+   lua_newtable(ed->L); //+1
+   ed->lua_ref = luaL_ref(ed->L, LUA_REGISTRYINDEX); //+1
+//   lua_pushvalue(ed->L, LUA_GLOBALSINDEX);
+//   lua_setfield(ed->L, -2, "__index");
+//   lua_setmetatable(ed->L, -2);
+//   lua_setfenv(ed->L, -2);
+   
+   _elua_table_ptr_set(ed->L, _elua_key, ed); //0
+//   lua_pop(ed->L, 1); // our current script stack anyway
+}
+
+void
+_edje_lua2_script_shutdown(Edje *ed)
+{
+   if (!ed->L) return;
+   lua_getfenv(ed->L, -1);
+   lua_pushnil(ed->L);
+   luaL_unref(ed->L, LUA_REGISTRYINDEX, ed->lua_ref); //0
+   lua_gc(ed->L, LUA_GCCOLLECT, 0); //0
+   
+   while (ed->lua_objs)
+     {
+        Edje_Lua_Obj *obj = (Edje_Lua_Obj *)ed->lua_objs;
+        if (obj->free_func)
+          {
+             ERR("uncollected Lua object %p", obj);
+             _elua_obj_free(ed->L, obj);
+          }
+        else
+          {
+             ERR("dangling Lua object %p", obj);
+             ed->lua_objs = eina_inlist_remove(ed->lua_objs, ed->lua_objs);
+          }
+     }
+   
+   ed->L = NULL;
+}
+
+void
+_edje_lua2_script_load(Edje_Part_Collection *edc, void *data, int size)
+{
+   int err;
+   
+   _elua_init();
+   
+   err = luaL_loadbuffer(lstate, data, size, "edje_lua_script"); //+1
+   if (err)
+     {
+        if (err == LUA_ERRSYNTAX)
+          ERR("lua load syntax error: %s", lua_tostring(lstate, -1)); //0
+        else if (err == LUA_ERRMEM)
+          ERR("lua load memory allocation error: %s", lua_tostring(lstate, -1)); //0
+     }
+   if ((err = lua_pcall(lstate, 0, 0, 0))) //0
+     _edje_lua2_error(lstate, err); //0
+}
+
+void
+_edje_lua2_script_unload(Edje_Part_Collection *edc)
+{
+   lua_gc(lstate, LUA_GCCOLLECT, 0); //0
+}
+
+#endif
diff --git a/src/lib/edje_lua_script_only.c b/src/lib/edje_lua_script_only.c
new file mode 100644 (file)
index 0000000..52ea6c4
--- /dev/null
@@ -0,0 +1,344 @@
+/*
+ * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef HAVE_ALLOCA_H
+# include <alloca.h>
+#elif defined __GNUC__
+# define alloca __builtin_alloca
+#elif defined _AIX
+# define alloca __alloca
+#elif defined _MSC_VER
+# include <malloc.h>
+# define alloca _alloca
+#else
+# include <stddef.h>
+# ifdef  __cplusplus
+extern "C"
+# endif
+void *alloca(size_t);
+#endif
+
+#include "edje_private.h"
+
+Eina_Bool
+_edje_lua_script_only(Edje *ed)
+{
+   if ((ed->collection) && (ed->collection->lua_script_only))
+      return EINA_TRUE;
+   return EINA_FALSE;
+}
+
+void
+_edje_lua_script_only_init(Edje *ed)
+{
+   if (ed->collection)
+     {
+#ifdef LUA2
+        int err;
+        
+        _edje_lua2_script_init(ed);
+        if (ed->L)
+          {
+             lua_getglobal(ed->L, "init");
+             if (!lua_isnil(ed->L, -1))
+               {
+                  if ((err = lua_pcall(ed->L, 0, 0, 0)))
+                    _edje_lua2_error(ed->L, err);
+               }
+             else
+               lua_pop(ed->L, 1);
+          }
+#else        
+        ed->L = _edje_lua_new_thread(ed, _edje_lua_state_get()); // freed in _edje_lua_script_only_shutdown
+        _edje_lua_new_reg(ed->L, -1, ed->L); // freed in _edje_lua_script_only_shutdown
+        lua_pop(ed->L, 1); /* thread */
+
+        lua_State *L = ed->L;
+        _edje_lua_script_fn_new(ed);
+        lua_pop(L, 1); /* script */
+
+        lua_getglobal(L, "init");
+        if (!lua_isnil (L, -1))
+          {
+             int err_code;
+
+             lua_pushvalue(L, LUA_GLOBALSINDEX); /* set function environment from collection thread to edje object thread */
+             lua_setfenv(L, -2);
+             _edje_lua_get_reg(L, ed);
+
+              if ((err_code = lua_pcall(L, 1, 0, 0)))
+                _edje_lua_error(L, err_code);
+          }
+        else
+          lua_pop(L, 1);
+#endif        
+     }
+}
+
+void
+_edje_lua_script_only_shutdown(Edje *ed)
+{
+   if (ed->collection && ed->L)
+     {
+#ifdef LUA2
+        int err;
+        
+        if (ed->L)
+          {
+             lua_getglobal(ed->L, "shutdown");
+             if (!lua_isnil(ed->L, -1))
+               {
+                  if ((err = lua_pcall(ed->L, 0, 0, 0)))
+                    _edje_lua2_error(ed->L, err);
+               }
+             else
+               lua_pop(ed->L, 1);
+          }
+        _edje_lua2_script_shutdown(ed);
+#else        
+       lua_State *L = ed->L;
+       lua_getglobal(L, "shutdown");
+       if (!lua_isnil (L, -1))
+         {
+            int err_code;
+
+            lua_pushvalue(L, LUA_GLOBALSINDEX);
+            lua_setfenv(L, -2);
+            _edje_lua_get_reg(L, ed);
+
+             if ((err_code = lua_pcall(L, 1, 0, 0)))
+               _edje_lua_error(L, err_code);
+         }
+       else
+         lua_pop (L, 1);
+#endif        
+     }
+}
+
+void
+_edje_lua_script_only_show(Edje * ed)
+{
+#ifdef LUA2
+#else        
+   if (ed->collection && ed->L)
+     {
+       lua_State *L = ed->L;
+       lua_getglobal(L, "show");
+       if (!lua_isnil (L, -1))
+         {
+            int err_code;
+
+            lua_pushvalue(L, LUA_GLOBALSINDEX);
+            lua_setfenv(L, -2);
+            _edje_lua_get_reg(L, ed);
+
+             if ((err_code = lua_pcall(L, 1, 0, 0)))
+               _edje_lua_error(L, err_code);
+         }
+       else
+         lua_pop (L, 1);
+     }
+#endif
+}
+
+void
+_edje_lua_script_only_hide(Edje * ed)
+{
+#ifdef LUA2
+#else        
+   if (ed->collection && ed->L)
+     {
+       lua_State *L = ed->L;
+       lua_getglobal(L, "hide");
+       if (!lua_isnil (L, -1))
+         {
+            int err_code;
+
+            lua_pushvalue(L, LUA_GLOBALSINDEX);
+            lua_setfenv(L, -2);
+            _edje_lua_get_reg(L, ed);
+
+             if ((err_code = lua_pcall(L, 1, 0, 0)))
+               _edje_lua_error(L, err_code);
+         }
+       else
+         lua_pop (L, 1);
+     }
+#endif   
+}
+
+void
+_edje_lua_script_only_move(Edje * ed)
+{
+#ifdef LUA2
+#else        
+   if (ed->collection && ed->L)
+     {
+       lua_State *L = ed->L;
+       lua_getglobal(L, "move");
+       if (!lua_isnil (L, -1))
+         {
+            int err_code;
+
+            lua_pushvalue(L, LUA_GLOBALSINDEX);
+            lua_setfenv(L, -2);
+            _edje_lua_get_reg(L, ed);
+            lua_pushnumber(L, ed->x);
+            lua_pushnumber(L, ed->y);
+
+             if ((err_code = lua_pcall(L, 3, 0, 0)))
+               _edje_lua_error(L, err_code);
+         }
+       else
+         lua_pop (L, 1);
+     }
+#endif   
+}
+
+void
+_edje_lua_script_only_resize(Edje * ed)
+{
+#ifdef LUA2
+#else        
+   if (ed->collection && ed->L)
+     {
+       lua_State *L = ed->L;
+       lua_getglobal(L, "resize");
+       if (!lua_isnil (L, -1))
+         {
+            int err_code;
+
+            lua_pushvalue(L, LUA_GLOBALSINDEX);
+            lua_setfenv(L, -2);
+            _edje_lua_get_reg(L, ed);
+            lua_pushnumber(L, ed->w);
+            lua_pushnumber(L, ed->h);
+
+             if ((err_code = lua_pcall(L, 3, 0, 0)))
+               _edje_lua_error(L, err_code);
+         }
+       else
+         lua_pop (L, 1);
+     }
+#endif   
+}
+
+void
+_edje_lua_script_only_message(Edje * ed, Edje_Message * em)
+{
+#ifdef LUA2
+#else        
+   if (ed->collection && ed->L)
+     {
+       lua_State *L = ed->L;
+       lua_getglobal(L, "message");
+       if (!lua_isnil (L, -1))
+         {
+            int nargs = 3;
+            int err_code;
+            int count;
+            int i;
+
+            lua_pushvalue(L, LUA_GLOBALSINDEX);
+            lua_setfenv(L, -2);
+            _edje_lua_get_reg(L, ed);
+            lua_pushnumber(L, em->type);
+            lua_pushnumber(L, em->id);
+            switch (em->type)
+              {
+               case EDJE_MESSAGE_NONE:
+                  break;
+               case EDJE_MESSAGE_SIGNAL:
+                  break;
+               case EDJE_MESSAGE_STRING:
+                  lua_pushstring(L, ((Edje_Message_String *) em->msg)->str);
+                  nargs += 1;
+                  break;
+               case EDJE_MESSAGE_INT:
+                  lua_pushnumber(L, ((Edje_Message_Int *) em->msg)->val);
+                  nargs += 1;
+                  break;
+               case EDJE_MESSAGE_FLOAT:
+                  lua_pushnumber(L, ((Edje_Message_Float *) em->msg)->val);
+                  nargs += 1;
+                  break;
+               case EDJE_MESSAGE_STRING_SET:
+                  count = ((Edje_Message_String_Set *) em->msg)->count;
+                  lua_createtable(L, count, 0);
+                  for (i = 0; i < count; i++)
+                    {
+                       lua_pushstring(L, ((Edje_Message_String_Set *) em->msg)->str[i]);
+                       lua_rawseti(L, -2, i + 1);
+                    }
+                  nargs += 1;
+                  break;
+               case EDJE_MESSAGE_INT_SET:
+                  count = ((Edje_Message_Int_Set *) em->msg)->count;
+                  lua_createtable(L, count, 0);
+                  for (i = 0; i < count; i++)
+                    {
+                       lua_pushnumber(L, ((Edje_Message_Int_Set *) em->msg)->val[i]);
+                       lua_rawseti(L, -2, i + 1);
+                    }
+                  nargs += 1;
+                  break;
+               case EDJE_MESSAGE_FLOAT_SET:
+                  count = ((Edje_Message_Float_Set *) em->msg)->count;
+                  lua_createtable(L, count, 0);
+                  for (i = 0; i < count; i++)
+                    {
+                       lua_pushnumber(L, ((Edje_Message_Float_Set *) em->msg)->val[i]);
+                       lua_rawseti(L, -2, i + 1);
+                    }
+                  nargs += 1;
+                  break;
+               case EDJE_MESSAGE_STRING_INT:
+                  lua_pushstring(L, ((Edje_Message_String_Int *) em->msg)->str);
+                  lua_pushnumber(L, ((Edje_Message_String_Int *) em->msg)->val);
+                  nargs += 2;
+                  break;
+               case EDJE_MESSAGE_STRING_FLOAT:
+                  lua_pushstring(L, ((Edje_Message_String_Float *) em->msg)->str);
+                  lua_pushnumber(L, ((Edje_Message_String_Float *) em->msg)->val);
+                  nargs += 2;
+                  break;
+               case EDJE_MESSAGE_STRING_INT_SET:
+                  lua_pushstring(L, ((Edje_Message_String_Int_Set *) em->msg)->str);
+                  count = ((Edje_Message_String_Int_Set *) em->msg)->count;
+                  lua_createtable(L, count, 0);
+                  for (i = 0; i < count; i++)
+                    {
+                       lua_pushnumber(L, ((Edje_Message_String_Int_Set *) em->msg)->val[i]);
+                       lua_rawseti(L, -2, i + 1);
+                    }
+                  nargs += 2;
+                  break;
+               case EDJE_MESSAGE_STRING_FLOAT_SET:
+                  lua_pushstring(L, ((Edje_Message_String_Float_Set *) em->msg)->str);
+                  count = ((Edje_Message_String_Float_Set *) em->msg)->count;
+                  lua_createtable(L, count, 0);
+                  for (i = 0; i < count; i++)
+                    {
+                       lua_pushnumber(L, ((Edje_Message_String_Float_Set *) em->msg)->val[i]);
+                       lua_rawseti(L, -2, i + 1);
+                    }
+                  nargs += 2;
+                  break;
+               default:
+                  break;
+              }
+
+             if ((err_code = lua_pcall(L, nargs, 0, 0)))
+               _edje_lua_error(L, err_code);
+         }
+       else
+         lua_pop (L, 1);
+     }
+#endif   
+}
+
diff --git a/src/lib/edje_main.c b/src/lib/edje_main.c
new file mode 100644 (file)
index 0000000..dbbeb0d
--- /dev/null
@@ -0,0 +1,297 @@
+/*
+ * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
+ */
+
+#include <time.h>
+
+#include "edje_private.h"
+
+static int _edje_init_count = 0;
+int _edje_default_log_dom = -1;
+Eina_Mempool *_edje_real_part_mp = NULL;
+Eina_Mempool *_edje_real_part_state_mp = NULL;
+
+
+
+/*============================================================================*
+ *                                   API                                      *
+ *============================================================================*/
+
+/**
+ * @addtogroup Edje_main_Group Main
+ *
+ * @brief These functions provide an abstraction layer between the
+ * application code and the interface, while allowing extremely
+ * flexible dynamic layouts and animations.
+ *
+ * @{
+ */
+
+/**
+ * @brief Initialize the edje library.
+ *
+ * @return The new init count. The initial value is zero.
+ *
+ * This function initializes the ejde library, making the propers
+ * calls to initialization functions. It makes calls to functions
+ * eina_init(), ecore_init(), embryo_init() and eet_init() so
+ * there is no need to call those functions again in your code. To
+ * shutdown edje there is a function edje_shutdown().
+ *
+ * @see edje_shutdown()
+ * @see eina_init()
+ * @see ecore_init()
+ * @see embryo_init()
+ * @see eet_init()
+ *
+ */
+
+EAPI int
+edje_init(void)
+{
+   if (++_edje_init_count != 1)
+     return _edje_init_count;
+
+   srand(time(NULL));
+
+   if (!eina_init())
+     {
+       fprintf(stderr, "Edje: Eina init failed");
+       return --_edje_init_count;
+     }
+
+   _edje_default_log_dom = eina_log_domain_register("Edje", EDJE_DEFAULT_LOG_COLOR);
+   if (_edje_default_log_dom < 0)
+     {
+       EINA_LOG_ERR("Edje Can not create a general log domain.");
+       goto shutdown_eina;
+     }
+
+   if (!ecore_init())
+     {
+       ERR("Edje: Ecore init failed");
+       goto unregister_log_domain;
+     }
+
+   if (!embryo_init())
+     {
+       ERR("Edje: Embryo init failed");
+       goto shutdown_ecore;
+     }
+
+   if (!eet_init())
+     {
+       ERR("Edje: Eet init failed");
+       goto shutdown_embryo;
+     }
+
+   _edje_scale = FROM_DOUBLE(1.0);
+
+   _edje_edd_init();
+   _edje_text_init();
+   _edje_box_init();
+   _edje_external_init();
+   _edje_module_init();
+   _edje_lua_init();
+   _edje_message_init();
+
+   _edje_real_part_mp = eina_mempool_add("chained_mempool",
+                                        "Edje_Real_Part", NULL,
+                                        sizeof (Edje_Real_Part), 128);
+   if (!_edje_real_part_mp)
+     {
+       ERR("Mempool for Edje_Real_Part cannot be allocated.");
+       goto shutdown_eet;
+     }
+
+   _edje_real_part_state_mp = eina_mempool_add("chained_mempool",
+                                              "Edje_Real_Part_State", NULL,
+                                              sizeof (Edje_Real_Part_State), 256);
+   if (!_edje_real_part_state_mp)
+     {
+       ERR("Mempool for Edje_Real_Part_State cannot be allocated.");
+       goto shutdown_eet;
+     }
+
+   return _edje_init_count;
+
+ shutdown_eet:
+   eina_mempool_del(_edje_real_part_state_mp);
+   eina_mempool_del(_edje_real_part_mp);
+   _edje_real_part_state_mp = NULL;
+   _edje_real_part_mp = NULL;
+   _edje_message_shutdown();
+   _edje_lua_shutdown();
+   _edje_module_shutdown();
+   _edje_external_shutdown();
+   _edje_box_shutdown();
+   _edje_text_class_members_free();
+   _edje_text_class_hash_free();
+   _edje_edd_shutdown();
+   eet_shutdown();
+ shutdown_embryo:
+   embryo_shutdown();
+ shutdown_ecore:
+   ecore_shutdown();
+ unregister_log_domain:
+   eina_log_domain_unregister(_edje_default_log_dom);
+   _edje_default_log_dom = -1;
+ shutdown_eina:
+   eina_shutdown();
+   return --_edje_init_count;
+}
+
+/**
+ * @brief Shutdown the edje library.
+ *
+ * @return The number of times the library has been initialised without being
+ *         shutdown.
+ *
+ * This function shuts down the edje library. It calls the functions
+ * eina_shutdown(), ecore_shutdown(), embryo_shutdown() and
+ * eet_shutdown(), so there is no need to call these functions again
+ * in your code.
+ *
+ * @see edje_init()
+ * @see eina_shutdown()
+ * @see ecore_shutdown()
+ * @see embryo_shutdown()
+ * @see eet_shutdown()
+ *
+ */
+
+EAPI int
+edje_shutdown(void)
+{
+   if (--_edje_init_count != 0)
+     return _edje_init_count;
+
+   if (_edje_timer)
+     ecore_animator_del(_edje_timer);
+   _edje_timer = NULL;
+
+   _edje_file_cache_shutdown();
+   _edje_color_class_members_free();
+   _edje_color_class_hash_free();
+
+   eina_mempool_del(_edje_real_part_state_mp);
+   eina_mempool_del(_edje_real_part_mp);
+   _edje_real_part_state_mp = NULL;
+   _edje_real_part_mp = NULL;
+
+   _edje_message_shutdown();
+   _edje_lua_shutdown();
+   _edje_module_shutdown();
+   _edje_external_shutdown();
+   _edje_box_shutdown();
+   _edje_text_class_members_free();
+   _edje_text_class_hash_free();
+   _edje_edd_shutdown();
+
+   eet_shutdown();
+   embryo_shutdown();
+   ecore_shutdown();
+   eina_log_domain_unregister(_edje_default_log_dom);
+   _edje_default_log_dom = -1;
+   eina_shutdown();
+
+   return _edje_init_count;
+}
+
+/* Private Routines */
+
+void
+_edje_del(Edje *ed)
+{
+   if (ed->processing_messages)
+     {
+       ed->delete_me = 1;
+       return;
+     }
+   _edje_message_del(ed);
+   _edje_callbacks_patterns_clean(ed);
+   _edje_file_del(ed);
+   if (ed->path) eina_stringshare_del(ed->path);
+   if (ed->group) eina_stringshare_del(ed->group);
+   if (ed->parent) eina_stringshare_del(ed->parent);
+   ed->path = NULL;
+   ed->group = NULL;
+   if ((ed->actions) || (ed->pending_actions))
+     {
+       _edje_animators = eina_list_remove(_edje_animators, ed);
+     }
+   while (ed->actions)
+     {
+       Edje_Running_Program *runp;
+
+       runp = eina_list_data_get(ed->actions);
+       ed->actions = eina_list_remove(ed->actions, runp);
+       free(runp);
+     }
+   while (ed->pending_actions)
+     {
+       Edje_Pending_Program *pp;
+
+       pp = eina_list_data_get(ed->pending_actions);
+       ed->pending_actions = eina_list_remove(ed->pending_actions, pp);
+       free(pp);
+     }
+   while (ed->callbacks)
+     {
+       Edje_Signal_Callback *escb;
+
+       escb = eina_list_data_get(ed->callbacks);
+       ed->callbacks = eina_list_remove(ed->callbacks, escb);
+       if (escb->signal) eina_stringshare_del(escb->signal);
+       if (escb->source) eina_stringshare_del(escb->source);
+       free(escb);
+     }
+   while (ed->color_classes)
+     {
+       Edje_Color_Class *cc;
+
+       cc = eina_list_data_get(ed->color_classes);
+       ed->color_classes = eina_list_remove(ed->color_classes, cc);
+       if (cc->name) eina_stringshare_del(cc->name);
+       free(cc);
+     }
+   while (ed->text_classes)
+     {
+       Edje_Text_Class *tc;
+
+       tc = eina_list_data_get(ed->text_classes);
+       ed->text_classes = eina_list_remove(ed->text_classes, tc);
+       if (tc->name) eina_stringshare_del(tc->name);
+       if (tc->font) eina_stringshare_del(tc->font);
+       free(tc);
+     }
+   free(ed);
+}
+
+void
+_edje_clean_objects(Edje *ed)
+{
+   evas_object_del(ed->clipper);
+   ed->evas = NULL;
+   ed->obj = NULL;
+   ed->clipper = NULL;
+}
+
+void
+_edje_ref(Edje *ed)
+{
+   if (ed->references <= 0) return;
+   ed->references++;
+}
+
+void
+_edje_unref(Edje *ed)
+{
+   ed->references--;
+   if (ed->references == 0) _edje_del(ed);
+}
+
+/**
+ *
+ * @}
+ */
diff --git a/src/lib/edje_match.c b/src/lib/edje_match.c
new file mode 100644 (file)
index 0000000..b7752dd
--- /dev/null
@@ -0,0 +1,712 @@
+/*
+ * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
+ */
+
+#include <string.h>
+
+#include "edje_private.h"
+
+/* States manipulations. */
+
+typedef struct _Edje_State      Edje_State;
+struct _Edje_State
+{
+  size_t        idx;
+  size_t        pos;
+};
+
+struct _Edje_States
+{
+  size_t         size;
+  Edje_State    *states;
+  _Bool         *has;
+};
+
+static void
+_edje_match_states_free(Edje_States      *states,
+                        size_t            states_size)
+{
+   (void) states_size;
+   free(states);
+}
+
+#define ALIGN(Size)                             \
+  {                                             \
+     Size--;                                    \
+     Size |= sizeof (void*) - 1;                \
+     Size++;                                    \
+  };
+
+static int
+_edje_match_states_alloc(Edje_Patterns *ppat, int n)
+{
+   Edje_States *l;
+
+   const size_t patterns_size = ppat->patterns_size;
+   const size_t patterns_max_length = ppat->max_length;
+
+   const size_t array_len = (patterns_max_length + 1) * patterns_size;
+
+   size_t       states_size;
+   size_t       has_size;
+   size_t       states_has_size;
+   size_t       struct_size;
+
+   unsigned char        *states;
+   unsigned char        *has;
+
+   int          i;
+
+   states_size = sizeof (*l->states) * array_len;
+   ALIGN(states_size);
+
+   has_size = sizeof (*l->has) * array_len;
+   ALIGN(has_size);
+
+   states_has_size = states_size + has_size;
+
+   struct_size = sizeof (*l);
+   ALIGN(struct_size);
+   struct_size += states_has_size;
+
+   l = malloc(n * struct_size);
+   if (!l) return 0;
+
+   ppat->states = l;
+   ppat->states->size = 0;
+
+   states = (unsigned char *) (l + n);
+   has = states + states_size;
+
+   for (i = 0; i < n; ++i)
+     {
+        l[i].states = (Edje_State *) states;
+        l[i].has = (_Bool *) has;
+
+       memset(l[i].has, 0, has_size);
+
+        states += states_has_size;
+        has += states_has_size;
+     }
+
+   return 1;
+}
+
+static void
+_edje_match_states_insert(Edje_States    *list,
+                          size_t          patterns_max_length,
+                          size_t          idx,
+                          size_t          pos)
+{
+   size_t i;
+
+   i = (idx * (patterns_max_length + 1)) + pos;
+   
+   if (i < list->size)
+     {
+       if (list->has[i]) return;
+     }
+   list->has[i] = 1;
+   
+   i = list->size;
+   list->states[i].idx = idx;
+   list->states[i].pos = pos;
+   list->has[i] = 0;
+   list->size++;
+}
+
+static void
+_edje_match_states_clear(Edje_States *list,
+                         __UNUSED__ size_t patterns_size,
+                         __UNUSED__ size_t patterns_max_length)
+{
+   list->size = 0;
+}
+
+/* Token manipulation. */
+
+enum status
+{
+   patterns_not_found          = 0,
+   patterns_found              = 1,
+   patterns_syntax_error       = 2
+};
+
+static size_t
+_edje_match_patterns_exec_class_token(enum status      *status,
+                                      const char       *cl_tok,
+                                      char              c)
+{
+  if (! *cl_tok)
+    {
+      *status = patterns_syntax_error;
+      return 0;
+    }
+  else if (cl_tok[1] == '-' && cl_tok[2] != ']')
+    {
+      if (*cl_tok <= c && c <= cl_tok[2])
+       *status = patterns_found;
+      return 3;
+    }
+  else
+    {
+      if (c == *cl_tok)
+       *status = patterns_found;
+      return 1;
+    }
+}
+
+static Edje_Match_Error
+_edje_match_patterns_exec_class_complement(const char *cl_tok, size_t *ret)
+{
+  switch (*cl_tok)
+    {
+     case 0:
+        return EDJE_MATCH_SYNTAX_ERROR;
+
+     case '!':
+        *ret = 1;
+        return EDJE_MATCH_OK;
+
+    default:
+       *ret = 0;
+       return EDJE_MATCH_OK;
+    }
+}
+
+static Edje_Match_Error
+_edje_match_patterns_exec_class(const char     *cl,
+                                char            c,
+                                size_t          *ret)
+{
+   enum status status = patterns_not_found;
+   int         pos = 1;
+   size_t       neg;
+
+   if (_edje_match_patterns_exec_class_complement(cl + 1, &neg) != EDJE_MATCH_OK)
+     return EDJE_MATCH_SYNTAX_ERROR;
+
+   pos += neg;
+
+   do
+     pos += _edje_match_patterns_exec_class_token(&status, cl + pos, c);
+   while (cl[pos] && cl[pos] != ']');
+
+   if (status == patterns_syntax_error || ! cl[pos])
+     return EDJE_MATCH_SYNTAX_ERROR;
+
+   if (status == patterns_found)
+     *ret = neg ? 0 : pos + 1;
+   else
+     *ret = neg ? pos + 1 : 0;
+
+   return EDJE_MATCH_OK;
+}
+
+static Edje_Match_Error
+_edje_match_patterns_exec_token(const char     *tok,
+                                char            c,
+                                size_t          *ret)
+{
+  switch (*tok)
+    {
+    case '\\':
+      if (tok[1])
+        {
+           *ret = tok[1] == c ? 2 : 0;
+           return EDJE_MATCH_OK;
+        }
+      return EDJE_MATCH_SYNTAX_ERROR;
+
+    case '?':
+      *ret = 1;
+      return EDJE_MATCH_OK;
+
+    case '[':
+       return _edje_match_patterns_exec_class(tok, c, ret);
+
+    default:
+       *ret = *tok == c ? 1 : 0;
+       return EDJE_MATCH_OK;
+    }
+}
+
+static void
+_edje_match_patterns_exec_init_states(Edje_States       *states,
+                                      size_t            patterns_size,
+                                      size_t             patterns_max_length)
+{
+   size_t       i;
+
+   states->size = patterns_size;
+
+   for (i = 0; i < patterns_size; ++i)
+     {
+        states->states[i].idx = i;
+        states->states[i].pos = 0;
+        states->has[i * (patterns_max_length + 1)] = 1;
+     }
+}
+
+/* Exported function. */
+
+#define EDJE_MATCH_INIT(Func, Type, Source, Show)               \
+  Edje_Patterns*                                                \
+  Func(Eina_List *lst)                                          \
+  {                                                             \
+     Edje_Patterns      *r;                                     \
+     size_t              i;                                     \
+                                                                \
+     if (!lst || eina_list_count(lst) <= 0)                     \
+       return NULL;                                             \
+                                                                \
+     r = malloc(sizeof (Edje_Patterns) +                        \
+                eina_list_count(lst)                            \
+                * sizeof(*r->finals)                            \
+                * sizeof(*r->patterns));                        \
+     if (!r) return NULL;                                       \
+                                                                \
+     r->ref = 1;                                               \
+     r->delete_me = 0;                                         \
+     r->patterns_size = eina_list_count(lst);                   \
+     r->max_length = 0;                                         \
+     r->patterns = (const char **) r->finals + r->patterns_size + 1;    \
+                                                                \
+     for (i = 0; lst; ++i)                                      \
+       {                                                        \
+          const char    *str;                                   \
+          Type          *data;                                  \
+          size_t         j;                                     \
+                                                                \
+          data = eina_list_data_get(lst);                       \
+          if (!data)                                            \
+            {                                                   \
+               free(r);                                         \
+               return NULL;                                     \
+            }                                                   \
+                                                                \
+          str = data->Source;                                   \
+          if (!str) str = "";                                   \
+          r->patterns[i] = str;                                 \
+                                                                \
+          if (Show)                                             \
+            INF("%lu [%s]", (unsigned long)i, str);            \
+                                                                \
+          r->finals[i] = 0;                                     \
+          for (j = 0; str[j]; ++j)                              \
+            if (str[j] != '*')                                  \
+              r->finals[i] = j + 1;                             \
+                                                                \
+          if (j > r->max_length)                                \
+            r->max_length = j;                                  \
+                                                                \
+          lst = eina_list_next(lst);                            \
+       }                                                        \
+                                                                \
+     if (!_edje_match_states_alloc(r, 2))                       \
+       {                                                        \
+          free(r);                                              \
+          return NULL;                                          \
+       }                                                        \
+                                                                \
+     return r;                                                  \
+  }
+
+EDJE_MATCH_INIT(edje_match_collection_dir_init,
+                Edje_Part_Collection_Directory_Entry,
+                entry, 0);
+EDJE_MATCH_INIT(edje_match_programs_signal_init,
+                Edje_Program,
+                signal, 0);
+EDJE_MATCH_INIT(edje_match_programs_source_init,
+                Edje_Program,
+                source, 0);
+EDJE_MATCH_INIT(edje_match_callback_signal_init,
+                Edje_Signal_Callback,
+                signal, 0);
+EDJE_MATCH_INIT(edje_match_callback_source_init,
+                Edje_Signal_Callback,
+                source, 0);
+
+static Eina_Bool
+_edje_match_collection_dir_exec_finals(const size_t      *finals,
+                                       const Edje_States *states)
+{
+   size_t       i;
+
+   for (i = 0; i < states->size; ++i)
+     if (states->states[i].pos >= finals[states->states[i].idx])
+       return EINA_TRUE;
+   return EINA_FALSE;
+}
+
+static Eina_Bool
+edje_match_programs_exec_check_finals(const size_t      *signal_finals,
+                                      const size_t      *source_finals,
+                                      const Edje_States *signal_states,
+                                      const Edje_States *source_states,
+                                      Eina_List         *programs,
+                                      Eina_Bool (*func)(Edje_Program *pr, void *data),
+                                      void              *data)
+{
+   size_t       i;
+   size_t       j;
+
+   for (i = 0; i < signal_states->size; ++i)
+     if (signal_states->states[i].pos >= signal_finals[signal_states->states[i].idx])
+       for (j = 0; j < source_states->size; ++j)
+         if (signal_states->states[i].idx == source_states->states[j].idx
+             && source_states->states[j].pos >= source_finals[source_states->states[j].idx])
+           {
+              Edje_Program  *pr;
+
+              pr = eina_list_nth(programs, signal_states->states[i].idx);
+              if (pr)
+                {
+                   if (func(pr, data))
+                     return EINA_FALSE;
+                }
+       }
+
+   return EINA_TRUE;
+}
+
+static int
+edje_match_callback_exec_check_finals(const Edje_Patterns *singal_ppat,
+                                      const Edje_Patterns *source_ppat,
+                                      const size_t      *signal_finals,
+                                      const size_t      *source_finals,
+                                      const Edje_States *signal_states,
+                                      const Edje_States *source_states,
+                                      const char        *signal,
+                                      const char        *source,
+                                      Eina_List         *callbacks,
+                                      Edje              *ed)
+{
+   size_t       i;
+   size_t       j;
+   int          r = 1;
+
+   for (i = 0; i < signal_states->size; ++i)
+     if (signal_states->states[i].pos >= signal_finals[signal_states->states[i].idx])
+       for (j = 0; j < source_states->size; ++j)
+         if (signal_states->states[i].idx == source_states->states[j].idx
+             && source_states->states[j].pos >= source_finals[source_states->states[j].idx])
+           {
+              Edje_Signal_Callback      *escb;
+
+              escb = eina_list_nth(callbacks, signal_states->states[i].idx);
+              if (escb)
+                {
+                   if ((!escb->just_added)
+                       && (!escb->delete_me))
+                     {
+                        escb->func(escb->data, ed->obj, signal, source);
+                        r = 2;
+                     }
+                   if (_edje_block_break(ed))
+                     return 0;
+                   if ((singal_ppat->delete_me) || (source_ppat->delete_me))
+                     return 0;
+                }
+       }
+
+   return r;
+}
+
+
+static Edje_States*
+_edje_match_fn(const Edje_Patterns      *ppat,
+               const char               *string,
+               Edje_States              *states)
+{
+   Edje_States  *new_states = states + 1;
+   const char   *c;
+
+   for (c = string; *c && states->size; ++c)
+     {
+        size_t  i;
+
+        _edje_match_states_clear(new_states, ppat->patterns_size, ppat->max_length);
+
+        for (i = 0; i < states->size; ++i)
+          {
+             const size_t       idx = states->states[i].idx;
+             const size_t       pos = states->states[i].pos;
+
+             if (!ppat->patterns[idx][pos])
+               continue;
+             else if (ppat->patterns[idx][pos] == '*')
+               {
+                  _edje_match_states_insert(states, ppat->max_length, idx, pos + 1);
+                  _edje_match_states_insert(new_states, ppat->max_length, idx, pos);
+               }
+             else
+               {
+                  size_t        m;
+
+                  if (_edje_match_patterns_exec_token(ppat->patterns[idx] + pos,
+                                                      *c,
+                                                      &m) != EDJE_MATCH_OK)
+                    return NULL;
+
+                  if (m)
+                    _edje_match_states_insert(new_states, ppat->max_length, idx, pos + m);
+               }
+          }
+        {
+           Edje_States  *tmp = states;
+
+           states = new_states;
+           new_states = tmp;
+        }
+     }
+
+   return states;
+}
+
+Eina_Bool
+edje_match_collection_dir_exec(const Edje_Patterns      *ppat,
+                               const char               *string)
+{
+   Edje_States  *result;
+   Eina_Bool     r = EINA_FALSE;
+
+   _edje_match_patterns_exec_init_states(ppat->states, ppat->patterns_size, ppat->max_length);
+
+   result = _edje_match_fn(ppat, string, ppat->states);
+
+   if (result)
+     r = _edje_match_collection_dir_exec_finals(ppat->finals, result);
+
+   return r;
+}
+
+Eina_Bool
+edje_match_programs_exec(const Edje_Patterns    *ppat_signal,
+                         const Edje_Patterns    *ppat_source,
+                         const char             *signal,
+                         const char             *source,
+                         Eina_List              *programs,
+                         Eina_Bool (*func)(Edje_Program *pr, void *data),
+                         void                   *data)
+{
+   Edje_States  *signal_result;
+   Edje_States  *source_result;
+   Eina_Bool     r = EINA_FALSE;
+
+   _edje_match_patterns_exec_init_states(ppat_signal->states,
+                                         ppat_signal->patterns_size,
+                                         ppat_signal->max_length);
+   _edje_match_patterns_exec_init_states(ppat_source->states,
+                                         ppat_source->patterns_size,
+                                         ppat_source->max_length);
+
+   signal_result = _edje_match_fn(ppat_signal, signal, ppat_signal->states);
+   source_result = _edje_match_fn(ppat_source, source, ppat_source->states);
+
+   if (signal_result && source_result)
+     r = edje_match_programs_exec_check_finals(ppat_signal->finals,
+                                               ppat_source->finals,
+                                               signal_result,
+                                               source_result,
+                                               programs,
+                                               func,
+                                               data);
+   return r;
+}
+
+int
+edje_match_callback_exec(Edje_Patterns          *ppat_signal,
+                         Edje_Patterns          *ppat_source,
+                         const char             *signal,
+                         const char             *source,
+                         Eina_List              *callbacks,
+                         Edje                   *ed)
+{
+   Edje_States  *signal_result;
+   Edje_States  *source_result;
+   int           r = 0;
+
+   ppat_signal->ref++;
+   ppat_source->ref++;
+   _edje_match_patterns_exec_init_states(ppat_signal->states,
+                                         ppat_signal->patterns_size,
+                                         ppat_signal->max_length);
+   _edje_match_patterns_exec_init_states(ppat_source->states,
+                                         ppat_source->patterns_size,
+                                         ppat_source->max_length);
+
+   signal_result = _edje_match_fn(ppat_signal, signal, ppat_signal->states);
+   source_result = _edje_match_fn(ppat_source, source, ppat_source->states);
+
+   if (signal_result && source_result)
+     r = edje_match_callback_exec_check_finals(ppat_signal,
+                                               ppat_source,
+                                               ppat_signal->finals,
+                                               ppat_source->finals,
+                                               signal_result,
+                                               source_result,
+                                               signal,
+                                               source,
+                                               callbacks,
+                                               ed);
+   ppat_signal->ref--;
+   ppat_source->ref--;
+   if (ppat_signal->ref <= 0) edje_match_patterns_free(ppat_signal);
+   if (ppat_source->ref <= 0) edje_match_patterns_free(ppat_source);
+   return r;
+}
+
+void
+edje_match_patterns_free(Edje_Patterns *ppat)
+{
+   ppat->delete_me = 1;
+   ppat->ref--;
+   if (ppat->ref > 0) return;
+   _edje_match_states_free(ppat->states, 2);
+   free(ppat);
+}
+
+void
+_edje_signals_sources_patterns_clean(Edje_Signals_Sources_Patterns *ssp)
+{
+   if (!ssp->signals_patterns)
+     return;
+
+   edje_match_patterns_free(ssp->signals_patterns);
+   edje_match_patterns_free(ssp->sources_patterns);
+   ssp->signals_patterns = NULL;
+   ssp->sources_patterns = NULL;
+}
+
+static Eina_Rbtree_Direction
+_edje_signal_source_node_cmp(const Edje_Signal_Source_Char *n1,
+                            const Edje_Signal_Source_Char *n2,
+                            __UNUSED__ void *data)
+{
+   int cmp;
+
+   cmp = strcmp(n1->signal, n2->signal);
+   if (cmp) return cmp < 0 ? EINA_RBTREE_LEFT : EINA_RBTREE_RIGHT;
+
+   return strcmp(n1->source, n2->source) < 0 ? EINA_RBTREE_LEFT : EINA_RBTREE_RIGHT;
+}
+
+static int
+_edje_signal_source_key_cmp(const Edje_Signal_Source_Char *node,
+                           const char *signal,
+                           __UNUSED__ int length,
+                           const char *source)
+{
+   int cmp;
+
+   cmp = strcmp(node->signal, signal);
+   if (cmp) return cmp;
+
+   return strcmp(node->source, source);
+}
+
+
+Eina_List *
+edje_match_program_hash_build(const Eina_List *callbacks,
+                             Eina_Rbtree **tree)
+{
+   Eina_List *result = NULL;
+   Eina_Rbtree *new = NULL;
+   Edje_Program *program;
+   const Eina_List *l;
+
+   EINA_LIST_FOREACH(callbacks, l, program)
+     {
+       if (program->signal && strpbrk(program->signal, "*?[\\") == NULL
+           && program->source && strpbrk(program->source, "*?[\\") == NULL)
+         {
+            Edje_Signal_Source_Char *item;
+
+            item = (Edje_Signal_Source_Char*) eina_rbtree_inline_lookup(new, program->signal, 0,
+                                                                        EINA_RBTREE_CMP_KEY_CB(_edje_signal_source_key_cmp), program->source);
+            if (!item)
+              {
+                 item = malloc(sizeof (Edje_Signal_Source_Char));
+                 if (!item) continue;
+
+                 item->signal = program->signal;
+                 item->source = program->source;
+                 item->list = NULL;
+
+                 new = eina_rbtree_inline_insert(new, EINA_RBTREE_GET(item),
+                                                 EINA_RBTREE_CMP_NODE_CB(_edje_signal_source_node_cmp), NULL);
+              }
+
+            item->list = eina_list_prepend(item->list, program);
+         }
+       else
+         result = eina_list_prepend(result, program);
+     }
+
+   *tree = new;
+   return result;
+}
+
+Eina_List *
+edje_match_callback_hash_build(const Eina_List *callbacks,
+                              Eina_Rbtree **tree)
+{
+   Eina_List *result = NULL;
+   Eina_Rbtree *new = NULL;
+   Edje_Signal_Callback *callback;
+   const Eina_List *l;
+
+   EINA_LIST_FOREACH(callbacks, l, callback)
+     {
+       if (callback->signal && strpbrk(callback->signal, "*?[\\") == NULL
+           && callback->source && strpbrk(callback->source, "*?[\\") == NULL)
+         {
+            Edje_Signal_Source_Char *item;
+
+            item = (Edje_Signal_Source_Char*) eina_rbtree_inline_lookup(new, callback->signal, 0,
+                                                                        EINA_RBTREE_CMP_KEY_CB(_edje_signal_source_key_cmp), callback->source);
+            if (!item)
+              {
+                 item = malloc(sizeof (Edje_Signal_Source_Char));
+                 if (!item) continue;
+
+                 item->signal = callback->signal;
+                 item->source = callback->source;
+                 item->list = NULL;
+
+                 new = eina_rbtree_inline_insert(new, EINA_RBTREE_GET(item),
+                                                 EINA_RBTREE_CMP_NODE_CB(_edje_signal_source_node_cmp), NULL);
+              }
+
+            item->list = eina_list_prepend(item->list, callback);
+         }
+       else
+         result = eina_list_prepend(result, callback);
+     }
+
+   *tree = new;
+   return result;
+}
+
+const Eina_List *
+edje_match_signal_source_hash_get(const char *signal,
+                                 const char *source,
+                                 const Eina_Rbtree *tree)
+{
+   Edje_Signal_Source_Char *lookup;
+
+   lookup = (Edje_Signal_Source_Char*) eina_rbtree_inline_lookup(tree, signal, 0,
+                                                                EINA_RBTREE_CMP_KEY_CB(_edje_signal_source_key_cmp), source);
+
+   if (lookup) return lookup->list;
+   return NULL;
+}
+
+void
+edje_match_signal_source_free(Edje_Signal_Source_Char *key, __UNUSED__ void *data)
+{
+   eina_list_free(key->list);
+   free(key);
+}
diff --git a/src/lib/edje_message_queue.c b/src/lib/edje_message_queue.c
new file mode 100644 (file)
index 0000000..f207be3
--- /dev/null
@@ -0,0 +1,781 @@
+/*
+ * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
+ */
+
+#include <string.h>
+
+#include "edje_private.h"
+
+static Ecore_Job *job = NULL;
+static Ecore_Timer *job_loss_timer = NULL;
+
+static Eina_List *msgq = NULL;
+static Eina_List *tmp_msgq = NULL;
+
+/*============================================================================*
+ *                                   API                                      *
+ *============================================================================*/
+
+/**
+ * @addtogroup Edje_message_queue_Group Message_Queue
+ *
+ * @brief These functions provide an abstraction layer between the
+ * application code and the interface, while allowing extremely
+ * flexible dynamic layouts and animations.
+ *
+ * @{
+ */
+
+/**
+ * @brief Send message to object.
+ *
+ * @param obj The edje object reference.
+ * @param type The type of message to send.
+ * @param id A identification number for the message.
+ * @param msg The message to be send.
+ *
+ *
+ * This function sends messages to this object and to all of its child
+ * objects, if applicable. The function that handles messages arriving
+ * at this edje object is is set with
+ * edje_object_message_handler_set().
+ *
+ * @see edje_object_message_handler_set()
+ *
+ */
+
+EAPI void
+edje_object_message_send(Evas_Object *obj, Edje_Message_Type type, int id, void *msg)
+{
+   Edje *ed;
+   int i;
+
+   ed = _edje_fetch(obj);
+   if (!ed) return;
+   _edje_message_send(ed, EDJE_QUEUE_SCRIPT, type, id, msg);
+
+   for (i = 0; i < ed->table_parts_size; i++)
+     {
+       Edje_Real_Part *rp = ed->table_parts[i];
+       if ((rp->part->type == EDJE_PART_TYPE_GROUP) && (rp->swallowed_object))
+         edje_object_message_send(rp->swallowed_object, type, id, msg);
+     }
+}
+
+/**
+ * @brief Set the message handler function for this an object.
+ *
+ * @param obj The edje object reference.
+ * @param func The function to handle messages.
+ * @param data The data to be associated to the message handler.
+ *
+ *
+ * This function associates a message handler function and data to the
+ * edje object.
+ *
+ */
+
+EAPI void
+edje_object_message_handler_set(Evas_Object *obj, void (*func) (void *data, Evas_Object *obj, Edje_Message_Type type, int id, void *msg), void *data)
+{
+   Edje *ed;
+
+   ed = _edje_fetch(obj);
+   if (!ed) return;
+   _edje_message_cb_set(ed, func, data);
+}
+
+/**
+ * @brief Process an object's message queue.
+ *
+ * @param obj The edje object reference.
+ *
+ * This function goes through the object message queue processing the
+ * pending messages for *this* specific edje object. Normally they'd
+ * be processed only at idle time.
+ *
+ */
+
+EAPI void
+edje_object_message_signal_process(Evas_Object *obj)
+{
+   Eina_List *l, *tmpq = NULL;
+   Edje *ed;
+   Edje_Message *em;
+   const void *data;
+
+   ed = _edje_fetch(obj);
+   if (!ed) return;
+
+   EINA_LIST_FOREACH(msgq, l, em)
+     if (em->edje == ed)
+       tmpq = eina_list_append(tmpq, em);
+   /* now remove them from the old queue */
+   EINA_LIST_FOREACH(tmpq, l, data)
+     msgq = eina_list_remove(msgq, data);
+   /* a temporary message queue */
+   if (tmp_msgq)
+     {
+       while (tmpq)
+         {
+            tmp_msgq = eina_list_append(tmp_msgq, tmpq->data);
+            tmpq = eina_list_remove_list(tmpq, tmpq);
+         }
+     }
+   else
+     {
+       tmp_msgq = tmpq;
+       tmpq = NULL;
+     }
+
+   while (tmp_msgq)
+     {
+       Edje_Message *em;
+
+       em = tmp_msgq->data;
+       tmp_msgq = eina_list_remove_list(tmp_msgq, tmp_msgq);
+       em->edje->message.num--;
+       _edje_message_process(em);
+       _edje_message_free(em);
+     }
+}
+
+/**
+ * @brief Process all queued up edje messages.
+ *
+ * This function triggers the processing of messages addressed to any
+ * (alive) edje objects.
+ *
+ */
+
+EAPI void
+edje_message_signal_process(void)
+{
+   _edje_message_queue_process();
+}
+
+
+static int
+_edje_dummy_timer(void *data __UNUSED__)
+{
+   return 0;
+}
+
+static void
+_edje_job(void *data __UNUSED__)
+{
+   if (job_loss_timer)
+     {
+       ecore_timer_del(job_loss_timer);
+       job_loss_timer = NULL;
+     }
+   _edje_message_queue_process();
+   job = NULL;
+}
+
+static int
+_edje_job_loss_timer(void *data __UNUSED__)
+{
+   job_loss_timer = NULL;
+   if (job) job = NULL;
+   return 0;
+}
+
+void
+_edje_message_init(void)
+{
+}
+
+void
+_edje_message_shutdown(void)
+{
+   _edje_message_queue_clear();
+   if (job_loss_timer)
+     ecore_timer_del(job_loss_timer);
+   job = NULL;
+   job_loss_timer = NULL;
+}
+
+void
+_edje_message_cb_set(Edje *ed, void (*func) (void *data, Evas_Object *obj, Edje_Message_Type type, int id, void *msg), void *data)
+{
+   ed->message.func = func;
+   ed->message.data = data;
+}
+
+Edje_Message *
+_edje_message_new(Edje *ed, Edje_Queue queue, Edje_Message_Type type, int id)
+{
+   Edje_Message *em;
+
+   em = calloc(1, sizeof(Edje_Message));
+   if (!em) return NULL;
+   em->edje = ed;
+   em->queue = queue;
+   em->type = type;
+   em->id = id;
+   em->edje->message.num++;
+   return em;
+}
+
+void
+_edje_message_free(Edje_Message *em)
+{
+   if (em->msg)
+     {
+       int i;
+
+       switch (em->type)
+         {
+          case EDJE_MESSAGE_STRING:
+              {
+                 Edje_Message_String *emsg;
+
+                 emsg = (Edje_Message_String *)em->msg;
+                 free(emsg->str);
+                 free(emsg);
+              }
+            break;
+          case EDJE_MESSAGE_INT:
+              {
+                 Edje_Message_Int *emsg;
+
+                 emsg = (Edje_Message_Int *)em->msg;
+                 free(emsg);
+              }
+            break;
+          case EDJE_MESSAGE_FLOAT:
+              {
+                 Edje_Message_Float *emsg;
+
+                 emsg = (Edje_Message_Float *)em->msg;
+                 free(emsg);
+              }
+            break;
+          case EDJE_MESSAGE_INT_SET:
+              {
+                 Edje_Message_Int_Set *emsg;
+
+                 emsg = (Edje_Message_Int_Set *)em->msg;
+                 free(emsg);
+              }
+            break;
+          case EDJE_MESSAGE_FLOAT_SET:
+              {
+                 Edje_Message_Float_Set *emsg;
+
+                 emsg = (Edje_Message_Float_Set *)em->msg;
+                 free(emsg);
+              }
+            break;
+          case EDJE_MESSAGE_STRING_FLOAT:
+              {
+                 Edje_Message_String_Float *emsg;
+
+                 emsg = (Edje_Message_String_Float *)em->msg;
+                 free(emsg->str);
+                 free(emsg);
+              }
+            break;
+          case EDJE_MESSAGE_STRING_INT:
+              {
+                 Edje_Message_String_Int *emsg;
+
+                 emsg = (Edje_Message_String_Int *)em->msg;
+                 free(emsg->str);
+                 free(emsg);
+              }
+            break;
+          case EDJE_MESSAGE_STRING_FLOAT_SET:
+              {
+                 Edje_Message_String_Float_Set *emsg;
+
+                 emsg = (Edje_Message_String_Float_Set *)em->msg;
+                 free(emsg->str);
+                 free(emsg);
+              }
+            break;
+          case EDJE_MESSAGE_STRING_INT_SET:
+              {
+                 Edje_Message_String_Int_Set *emsg;
+
+                 emsg = (Edje_Message_String_Int_Set *)em->msg;
+                 free(emsg->str);
+                 free(emsg);
+              }
+            break;
+          case EDJE_MESSAGE_SIGNAL:
+              {
+                 Edje_Message_Signal *emsg;
+
+                 emsg = (Edje_Message_Signal *)em->msg;
+                 if (emsg->sig) eina_stringshare_del(emsg->sig);
+                 if (emsg->src) eina_stringshare_del(emsg->src);
+                 free(emsg);
+              }
+            break;
+          case EDJE_MESSAGE_STRING_SET:
+              {
+                 Edje_Message_String_Set *emsg;
+
+                 emsg = (Edje_Message_String_Set *)em->msg;
+                 for (i = 0; i < emsg->count; i++)
+                   free(emsg->str[i]);
+                 free(emsg);
+              }
+            break;
+          case EDJE_MESSAGE_NONE:
+          default:
+            break;
+         }
+     }
+   free(em);
+}
+
+void
+_edje_message_send(Edje *ed, Edje_Queue queue, Edje_Message_Type type, int id, void *emsg)
+{
+   /* FIXME: check all malloc & strdup fails and gracefully unroll and exit */
+   Edje_Message *em;
+   int i;
+   unsigned char *msg = NULL;
+
+   if (!job)
+     {
+       job = ecore_job_add(_edje_job, NULL);
+       if (job_loss_timer) ecore_timer_del(job_loss_timer);
+       job_loss_timer = ecore_timer_add(0.05, _edje_job_loss_timer, NULL);
+     }
+   em = _edje_message_new(ed, queue, type, id);
+   if (!em) return;
+   switch (em->type)
+     {
+      case EDJE_MESSAGE_NONE:
+       break;
+      case EDJE_MESSAGE_SIGNAL:
+         {
+            Edje_Message_Signal *emsg2, *emsg3;
+
+            emsg2 = (Edje_Message_Signal *)emsg;
+            emsg3 = calloc(1, sizeof(Edje_Message_Signal));
+            if (emsg2->sig) emsg3->sig = eina_stringshare_add(emsg2->sig);
+            if (emsg2->src) emsg3->src = eina_stringshare_add(emsg2->src);
+            msg = (unsigned char *)emsg3;
+         }
+       break;
+      case EDJE_MESSAGE_STRING:
+         {
+            Edje_Message_String *emsg2, *emsg3;
+
+            emsg2 = (Edje_Message_String *)emsg;
+            emsg3 = malloc(sizeof(Edje_Message_String));
+            emsg3->str = strdup(emsg2->str);
+            msg = (unsigned char *)emsg3;
+         }
+       break;
+      case EDJE_MESSAGE_INT:
+         {
+            Edje_Message_Int *emsg2, *emsg3;
+
+            emsg2 = (Edje_Message_Int *)emsg;
+            emsg3 = malloc(sizeof(Edje_Message_Int));
+            emsg3->val = emsg2->val;
+            msg = (unsigned char *)emsg3;
+         }
+       break;
+      case EDJE_MESSAGE_FLOAT:
+         {
+            Edje_Message_Float *emsg2, *emsg3;
+
+            emsg2 = (Edje_Message_Float *)emsg;
+            emsg3 = malloc(sizeof(Edje_Message_Float));
+            emsg3->val = emsg2->val;
+            msg = (unsigned char *)emsg3;
+         }
+       break;
+      case EDJE_MESSAGE_STRING_SET:
+         {
+            Edje_Message_String_Set *emsg2, *emsg3;
+
+            emsg2 = (Edje_Message_String_Set *)emsg;
+            emsg3 = malloc(sizeof(Edje_Message_String_Set) + ((emsg2->count - 1) * sizeof(char *)));
+            emsg3->count = emsg2->count;
+            for (i = 0; i < emsg3->count; i++)
+              emsg3->str[i] = strdup(emsg2->str[i]);
+            msg = (unsigned char *)emsg3;
+         }
+       break;
+      case EDJE_MESSAGE_INT_SET:
+         {
+            Edje_Message_Int_Set *emsg2, *emsg3;
+
+            emsg2 = (Edje_Message_Int_Set *)emsg;
+            emsg3 = malloc(sizeof(Edje_Message_Int_Set) + ((emsg2->count - 1) * sizeof(int)));
+            emsg3->count = emsg2->count;
+            for (i = 0; i < emsg3->count; i++)
+              emsg3->val[i] = emsg2->val[i];
+            msg = (unsigned char *)emsg3;
+         }
+       break;
+      case EDJE_MESSAGE_FLOAT_SET:
+         {
+            Edje_Message_Float_Set *emsg2, *emsg3;
+
+            emsg2 = (Edje_Message_Float_Set *)emsg;
+            emsg3 = malloc(sizeof(Edje_Message_Float_Set) + ((emsg2->count - 1) * sizeof(double)));
+            emsg3->count = emsg2->count;
+            for (i = 0; i < emsg3->count; i++)
+              emsg3->val[i] = emsg2->val[i];
+            msg = (unsigned char *)emsg3;
+         }
+       break;
+      case EDJE_MESSAGE_STRING_INT:
+         {
+            Edje_Message_String_Int *emsg2, *emsg3;
+
+            emsg2 = (Edje_Message_String_Int *)emsg;
+            emsg3 = malloc(sizeof(Edje_Message_String_Int));
+            emsg3->str = strdup(emsg2->str);
+            emsg3->val = emsg2->val;
+            msg = (unsigned char *)emsg3;
+         }
+       break;
+      case EDJE_MESSAGE_STRING_FLOAT:
+         {
+            Edje_Message_String_Float *emsg2, *emsg3;
+
+            emsg2 = (Edje_Message_String_Float *)emsg;
+            emsg3 = malloc(sizeof(Edje_Message_String_Float));
+            emsg3->str = strdup(emsg2->str);
+            emsg3->val = emsg2->val;
+            msg = (unsigned char *)emsg3;
+         }
+       break;
+      case EDJE_MESSAGE_STRING_INT_SET:
+         {
+            Edje_Message_String_Int_Set *emsg2, *emsg3;
+
+            emsg2 = (Edje_Message_String_Int_Set *)emsg;
+            emsg3 = malloc(sizeof(Edje_Message_String_Int_Set) + ((emsg2->count - 1) * sizeof(int)));
+            emsg3->str = strdup(emsg2->str);
+            emsg3->count = emsg2->count;
+            for (i = 0; i < emsg3->count; i++)
+              emsg3->val[i] = emsg2->val[i];
+            msg = (unsigned char *)emsg3;
+         }
+       break;
+      case EDJE_MESSAGE_STRING_FLOAT_SET:
+         {
+            Edje_Message_String_Float_Set *emsg2, *emsg3;
+
+            emsg2 = (Edje_Message_String_Float_Set *)emsg;
+            emsg3 = malloc(sizeof(Edje_Message_String_Float_Set) + ((emsg2->count - 1) * sizeof(double)));
+            emsg3->str = strdup(emsg2->str);
+            emsg3->count = emsg2->count;
+            for (i = 0; i < emsg3->count; i++)
+              emsg3->val[i] = emsg2->val[i];
+            msg = (unsigned char *)emsg3;
+         }
+       break;
+      default:
+       break;
+     }
+
+   em->msg = msg;
+   msgq = eina_list_append(msgq, em);
+}
+
+void
+_edje_message_parameters_push(Edje_Message *em)
+{
+   int i;
+   
+   /* these params ALWAYS go on */
+   /* first param is the message type - always */
+   embryo_parameter_cell_push(em->edje->collection->script,
+                             (Embryo_Cell)em->type);
+   /* 2nd param is the integer of the event id - always there */
+   embryo_parameter_cell_push(em->edje->collection->script,
+                             (Embryo_Cell)em->id);
+   /* the rest is varags of whatever is in the msg */
+   switch (em->type)
+     {
+      case EDJE_MESSAGE_NONE:
+       break;
+      case EDJE_MESSAGE_STRING:
+       embryo_parameter_string_push(em->edje->collection->script,
+                                    ((Edje_Message_String *)em->msg)->str);
+       break;
+      case EDJE_MESSAGE_INT:
+         {
+            Embryo_Cell v;
+
+            v = (Embryo_Cell)((Edje_Message_Int *)em->msg)->val;
+            embryo_parameter_cell_array_push(em->edje->collection->script, &v, 1);
+         }
+       break;
+      case EDJE_MESSAGE_FLOAT:
+         {
+            Embryo_Cell v;
+            float fv;
+
+            fv = ((Edje_Message_Float *)em->msg)->val;
+            v = EMBRYO_FLOAT_TO_CELL(fv);
+            embryo_parameter_cell_array_push(em->edje->collection->script, &v, 1);
+         }
+       break;
+      case EDJE_MESSAGE_STRING_SET:
+       for (i = 0; i < ((Edje_Message_String_Set *)em->msg)->count; i++)
+         embryo_parameter_string_push(em->edje->collection->script,
+                                      ((Edje_Message_String_Set *)em->msg)->str[i]);
+       break;
+      case EDJE_MESSAGE_INT_SET:
+       for (i = 0; i < ((Edje_Message_Int_Set *)em->msg)->count; i++)
+         {
+            Embryo_Cell v;
+
+            v = (Embryo_Cell)((Edje_Message_Int_Set *)em->msg)->val[i];
+            embryo_parameter_cell_array_push(em->edje->collection->script, &v, 1);
+         }
+       break;
+      case EDJE_MESSAGE_FLOAT_SET:
+       for (i = 0; i < ((Edje_Message_Float_Set *)em->msg)->count; i++)
+         {
+            Embryo_Cell v;
+            float fv;
+
+            fv = ((Edje_Message_Float_Set *)em->msg)->val[i];
+            v = EMBRYO_FLOAT_TO_CELL(fv);
+            embryo_parameter_cell_array_push(em->edje->collection->script, &v, 1);
+         }
+       break;
+      case EDJE_MESSAGE_STRING_INT:
+       embryo_parameter_string_push(em->edje->collection->script,
+                                    ((Edje_Message_String_Int *)em->msg)->str);
+         {
+            Embryo_Cell v;
+
+            v = (Embryo_Cell)((Edje_Message_String_Int *)em->msg)->val;
+            embryo_parameter_cell_array_push(em->edje->collection->script, &v, 1);
+         }
+       break;
+      case EDJE_MESSAGE_STRING_FLOAT:
+       embryo_parameter_string_push(em->edje->collection->script,
+                                    ((Edje_Message_String_Float *)em->msg)->str);
+         {
+            Embryo_Cell v;
+            float fv;
+
+            fv = ((Edje_Message_String_Float *)em->msg)->val;
+            v = EMBRYO_FLOAT_TO_CELL(fv);
+            embryo_parameter_cell_array_push(em->edje->collection->script, &v, 1);
+         }
+       break;
+      case EDJE_MESSAGE_STRING_INT_SET:
+       embryo_parameter_string_push(em->edje->collection->script,
+                                    ((Edje_Message_String_Int_Set *)em->msg)->str);
+       for (i = 0; i < ((Edje_Message_String_Int_Set *)em->msg)->count; i++)
+         {
+            Embryo_Cell v;
+
+            v = (Embryo_Cell)((Edje_Message_String_Int_Set *)em->msg)->val[i];
+            embryo_parameter_cell_array_push(em->edje->collection->script, &v, 1);
+         }
+       break;
+      case EDJE_MESSAGE_STRING_FLOAT_SET:
+       embryo_parameter_string_push(em->edje->collection->script,
+                                    ((Edje_Message_String_Float_Set *)em->msg)->str);
+       for (i = 0; i < ((Edje_Message_String_Float_Set *)em->msg)->count; i++)
+         {
+            Embryo_Cell v;
+            float fv;
+
+            fv = ((Edje_Message_String_Float_Set *)em->msg)->val[i];
+            v = EMBRYO_FLOAT_TO_CELL(fv);
+            embryo_parameter_cell_array_push(em->edje->collection->script, &v, 1);
+         }
+       break;
+      default:
+       break;
+     }
+}
+
+void
+_edje_message_process(Edje_Message *em)
+{
+   Embryo_Function fn;
+   void *pdata;
+
+   /* signals are only handled one way */
+   if (em->type == EDJE_MESSAGE_SIGNAL)
+     {
+       _edje_emit_handle(em->edje,
+                         ((Edje_Message_Signal *)em->msg)->sig,
+                         ((Edje_Message_Signal *)em->msg)->src);
+       return;
+     }
+   /* if this has been queued up for the app then just call the callback */
+   if (em->queue == EDJE_QUEUE_APP)
+     {
+       if (em->edje->message.func)
+         em->edje->message.func(em->edje->message.data, em->edje->obj,
+                                em->type, em->id, em->msg);
+       return;
+     }
+   /* now this message is destined for the script message handler fn */
+   if (!(em->edje->collection)) return;
+   if ((em->edje->collection->script) && _edje_script_only (em->edje))
+     {
+       _edje_script_only_message(em->edje, em);
+       return;
+     }
+   if (em->edje->L)
+     {
+       _edje_lua_script_only_message(em->edje, em);
+       return;
+     }
+   fn = embryo_program_function_find(em->edje->collection->script, "message");
+   if (fn == EMBRYO_FUNCTION_NONE) return;
+   /* reset the engine */
+   _edje_embryo_script_reset(em->edje);
+   
+   _edje_message_parameters_push(em);
+   
+   embryo_program_vm_push(em->edje->collection->script);
+   _edje_embryo_globals_init(em->edje);
+   pdata = embryo_program_data_get(em->edje->collection->script);
+   embryo_program_data_set(em->edje->collection->script, em->edje);
+   embryo_program_max_cycle_run_set(em->edje->collection->script, 5000000);
+   embryo_program_run(em->edje->collection->script, fn);
+   embryo_program_data_set(em->edje->collection->script, pdata);
+   embryo_program_vm_pop(em->edje->collection->script);
+}
+
+void
+_edje_message_queue_process(void)
+{
+   int i;
+
+   if (msgq == NULL) return;
+
+   /* allow the message queue to feed itself up to 8 times before forcing */
+   /* us to go back to normal processing and let a 0 timeout deal with it */
+   for (i = 0; (i < 8) && (msgq); i++)
+     {
+       /* a temporary message queue */
+       if (tmp_msgq)
+         {
+            while (msgq)
+              {
+                 tmp_msgq = eina_list_append(tmp_msgq, msgq->data);
+                 msgq = eina_list_remove_list(msgq, msgq);
+              }
+         }
+       else
+         {
+            tmp_msgq = msgq;
+            msgq = NULL;
+         }
+
+       while (tmp_msgq)
+         {
+            Edje_Message *em;
+            Edje *ed;
+
+            em = tmp_msgq->data;
+            ed = em->edje;
+            tmp_msgq = eina_list_remove_list(tmp_msgq, tmp_msgq);
+            em->edje->message.num--;
+            if (!ed->delete_me)
+              {
+                 ed->processing_messages++;
+                 _edje_message_process(em);
+                 _edje_message_free(em);
+                 ed->processing_messages--;
+              }
+            else
+              _edje_message_free(em);
+            if (ed->processing_messages == 0)
+              {
+                 if (ed->delete_me) _edje_del(ed);
+              }
+         }
+     }
+
+   /* if the message queue filled again set a timer to expire in 0.0 sec */
+   /* to get the idle enterer to be run again */
+   if (msgq)
+     {
+       ecore_timer_add(0.0, _edje_dummy_timer, NULL);
+     }
+}
+
+void
+_edje_message_queue_clear(void)
+{
+   while (msgq)
+     {
+       Edje_Message *em;
+
+       em = msgq->data;
+       msgq = eina_list_remove_list(msgq, msgq);
+       em->edje->message.num--;
+       _edje_message_free(em);
+     }
+   while (tmp_msgq)
+     {
+       Edje_Message *em;
+
+       em = tmp_msgq->data;
+       tmp_msgq = eina_list_remove_list(tmp_msgq, tmp_msgq);
+       em->edje->message.num--;
+       _edje_message_free(em);
+     }
+}
+
+void
+_edje_message_del(Edje *ed)
+{
+   Eina_List *l;
+
+   if (ed->message.num <= 0) return;
+   /* delete any messages on the main queue for this edje object */
+   for (l = msgq; l; )
+     {
+       Edje_Message *em;
+       Eina_List *lp;
+
+       em = eina_list_data_get(l);
+       lp = l;
+       l = eina_list_next(l);
+       if (em->edje == ed)
+         {
+            msgq = eina_list_remove_list(msgq, lp);
+            em->edje->message.num--;
+            _edje_message_free(em);
+         }
+       if (ed->message.num <= 0) return;
+     }
+   /* delete any on the processing queue */
+   for (l = tmp_msgq; l; )
+     {
+       Edje_Message *em;
+       Eina_List *lp;
+
+       em = eina_list_data_get(l);
+       lp = l;
+       l = eina_list_next(l);
+       if (em->edje == ed)
+         {
+            tmp_msgq = eina_list_remove_list(tmp_msgq, lp);
+            em->edje->message.num--;
+            _edje_message_free(em);
+         }
+       if (ed->message.num <= 0) return;
+     }
+}
+
+/**
+ *
+ * @}
+ */
diff --git a/src/lib/edje_misc.c b/src/lib/edje_misc.c
new file mode 100644 (file)
index 0000000..32a4dd1
--- /dev/null
@@ -0,0 +1 @@
+#include "edje_private.h"
diff --git a/src/lib/edje_module.c b/src/lib/edje_module.c
new file mode 100644 (file)
index 0000000..1828e7c
--- /dev/null
@@ -0,0 +1,154 @@
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_ALLOCA_H
+# include <alloca.h>
+#elif defined __GNUC__
+# define alloca __builtin_alloca
+#elif defined _AIX
+# define alloca __alloca
+#elif defined _MSC_VER
+# include <malloc.h>
+# define alloca _alloca
+#else
+# include <stddef.h>
+# ifdef  __cplusplus
+extern "C"
+# endif
+void *alloca (size_t);
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <libgen.h>
+
+#ifdef HAVE_EVIL
+# include <Evil.h>
+#endif
+
+#include <Eina.h>
+#include <Ecore_File.h>
+
+#include "Edje.h"
+
+#define LOG_COLOR "\033[36m"
+
+Eina_Hash *_registered_modules = NULL;
+Eina_Array *_available_modules = NULL;
+Eina_List *_modules_name = NULL;
+static int _edje_modules_log_dom = -1;
+
+const char *
+_edje_module_name_get(Eina_Module *m)
+{
+   const char *name;
+   ssize_t len;
+
+   name = ecore_file_file_get(eina_module_file_get(m));
+   len = strlen(name);
+   len -= sizeof(SHARED_LIB_SUFFIX) - 1;
+   if (len <= 0) return NULL;
+   return eina_stringshare_add_length(name, len);
+}
+
+EAPI Eina_Bool
+edje_module_load(const char *module)
+{
+   Eina_Module *m;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(module, EINA_FALSE);
+
+   if (eina_hash_find(_registered_modules, module))
+     return EINA_TRUE;
+
+   m = eina_module_find(_available_modules, module);
+
+   if (!m)
+     {
+       EINA_LOG_ERR("Could not find the module %s", module);
+       return EINA_FALSE;
+     }
+
+   if (!eina_module_load(m))
+     {
+       EINA_LOG_ERR("Could not load the module %s", module);
+       return EINA_TRUE;
+     }
+
+   return !!eina_hash_add(_registered_modules, module, m);
+}
+
+void
+_edje_module_init(void)
+{
+   unsigned int i;
+   Eina_Array_Iterator it;
+   Eina_Module *m;
+
+   _edje_modules_log_dom = eina_log_domain_register("edje_module", LOG_COLOR);
+
+   if (_edje_modules_log_dom < 0)
+     {
+       EINA_LOG_ERR("Could not register log domain: edje_module");
+       return;
+     }
+
+   _registered_modules = eina_hash_string_small_new(NULL);
+   _available_modules = eina_module_list_get(_available_modules,
+           PACKAGE_LIB_DIR "/edje", 0, NULL, NULL);
+
+   if (!_available_modules)
+     {
+       eina_hash_free(_registered_modules);
+       return;
+     }
+
+   EINA_ARRAY_ITER_NEXT(_available_modules, i, m, it)
+     {
+       const char *name;
+
+       name = _edje_module_name_get(m);
+       _modules_name = eina_list_append(_modules_name, name);
+     }
+
+}
+
+void
+_edje_module_shutdown(void)
+{
+   Eina_List *l;
+   const char *data;
+
+   eina_module_list_free(_available_modules);
+   if (_available_modules)
+     {
+       eina_array_free(_available_modules);
+       _available_modules = NULL;
+     }
+
+   if (_registered_modules)
+     {
+       eina_hash_free(_registered_modules);
+       _registered_modules = NULL;
+     }
+
+   if (_modules_name)
+     {
+       EINA_LIST_FOREACH(_modules_name, l, data)
+         {
+           eina_stringshare_del(data);
+         }
+       _modules_name = NULL;
+     }
+
+   eina_log_domain_unregister(_edje_modules_log_dom);
+   _edje_modules_log_dom = -1;
+}
+
+EAPI const Eina_List *
+edje_available_modules_get(void)
+{
+   return _modules_name;
+}
diff --git a/src/lib/edje_private.h b/src/lib/edje_private.h
new file mode 100644 (file)
index 0000000..46d0c99
--- /dev/null
@@ -0,0 +1,1609 @@
+#ifndef _EDJE_PRIVATE_H
+#define _EDJE_PRIVATE_H
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef HAVE_EVIL
+# include <Evil.h>
+#endif
+
+#include <Eina.h>
+#include <Evas.h>
+#include <Ecore.h>
+#ifdef HAVE_ECORE_IMF
+# include <Ecore_IMF.h>
+#endif
+#include <Eet.h>
+#include <Embryo.h>
+#include <time.h>
+
+#include "Edje.h"
+#include "Edje_Edit.h"
+
+#include <lua.h>
+#include <lualib.h>
+#include <lauxlib.h>
+#include <setjmp.h>
+
+EAPI extern int _edje_default_log_dom ; 
+
+#ifdef EDJE_DEFAULT_LOG_COLOR
+# undef EDJE_DEFAULT_LOG_COLOR
+#endif
+#define EDJE_DEFAULT_LOG_COLOR EINA_COLOR_CYAN
+#ifdef ERR
+# undef ERR
+#endif
+#define ERR(...) EINA_LOG_DOM_ERR(_edje_default_log_dom, __VA_ARGS__)
+#ifdef INF
+# undef INF
+#endif
+#define INF(...) EINA_LOG_DOM_INFO(_edje_default_log_dom, __VA_ARGS__)
+#ifdef WRN
+# undef WRN
+#endif
+#define WRN(...) EINA_LOG_DOM_WARN(_edje_default_log_dom, __VA_ARGS__)
+#ifdef CRIT
+# undef CRIT
+#endif
+#define CRIT(...) EINA_LOG_DOM_CRIT(_edje_default_log_dom, __VA_ARGS__)
+#ifdef __GNUC__
+# if __GNUC__ >= 4
+// BROKEN in gcc 4 on amd64
+//#  pragma GCC visibility push(hidden)
+# endif
+#endif
+
+#ifndef ABS
+#define ABS(x) ((x) < 0 ? -(x) : (x))
+#endif
+
+#ifndef CLAMP
+#define CLAMP(x, min, max) (((x) > (max)) ? (max) : (((x) < (min)) ? (min) : (x)))
+#endif
+
+#ifndef MIN
+#define MIN(a, b) (((a) < (b)) ? (a) : (b))
+#endif
+
+
+#ifdef BUILD_EDJE_FP
+
+#define FLOAT_T Eina_F32p32
+#define EDJE_T_FLOAT EET_T_F32P32
+#define MUL(a, b) eina_f32p32_mul(a, b)
+#define SCALE(a, b) eina_f32p32_scale(a, b)
+#define DIV(a, b) eina_f32p32_div(a, b)
+#define DIV2(a) ((a) >> 1)
+#define ADD(a, b) eina_f32p32_add(a, b)
+#define SUB(a, b) eina_f32p32_sub(a, b)
+#define SQRT(a) eina_f32p32_sqrt(a)
+#define TO_DOUBLE(a) eina_f32p32_double_to(a)
+#define FROM_DOUBLE(a) eina_f32p32_double_from(a)
+#define FROM_INT(a) eina_f32p32_int_from(a)
+#define TO_INT(a) eina_f32p32_int_to(a)
+#define ZERO 0
+#define COS(a) eina_f32p32_cos(a)
+#define SIN(a) eina_f32p32_sin(a)
+#define PI EINA_F32P32_PI
+
+#else
+
+#define FLOAT_T double
+#define EDJE_T_FLOAT EET_T_DOUBLE
+#define MUL(a, b) ((a) * (b))
+#define SCALE(a, b) ((a) * (double)(b))
+#define DIV(a, b) ((a) / (b))
+#define DIV2(a) ((a) / 2.0)
+#define ADD(a, b) ((a) + (b))
+#define SUB(a, b) ((a) - (b))
+#define SQRT(a) sqrt(a)
+#define TO_DOUBLE(a) (double)(a)
+#define FROM_DOUBLE(a) (a)
+#define FROM_INT(a) (double)(a)
+#define TO_INT(a) (int)(a)
+#define ZERO 0.0
+#define COS(a) cos(a)
+#define SIN(a) sin(a)
+#define PI 3.14159265358979323846
+
+#endif
+
+/* Inheritable Edje Smart API. For now private so only Edje Edit makes
+ * use of this, but who knows what will be possible in the future */
+#define EDJE_SMART_API_VERSION 1
+
+typedef struct _Edje_Smart_Api Edje_Smart_Api;
+
+struct _Edje_Smart_Api
+{
+   Evas_Smart_Class base;
+   int version;
+   Eina_Bool (*file_set)(Evas_Object *obj, const char *file, const char *group);
+};
+
+/* Basic macro to init the Edje Smart API */
+#define EDJE_SMART_API_INIT(smart_class_init) {smart_class_init, EDJE_SMART_API_VERSION, NULL}
+
+#define EDJE_SMART_API_INIT_NULL EDJE_SMART_API_INIT(EVAS_SMART_CLASS_INIT_NULL)
+#define EDJE_SMART_API_INIT_VERSION EDJE_SMART_API_INIT(EVAS_SMART_CLASS_INIT_VERSION)
+#define EDJE_SMART_API_INIT_NAME_VERSION(name) EDJE_SMART_API_INIT(EVAS_SMART_CLASS_INIT_NAME_VERSION(name))
+
+/* increment this when the EET data descriptors have changed and old
+ * EETs cannot be loaded/used correctly anymore.
+ */
+#define EDJE_FILE_VERSION 2
+
+/* FIXME:
+ *
+ * More example Edje files
+ *
+ * ? programs can do multiple actions from one signal
+ * ? add containering (hbox, vbox, table, wrapping multi-line hbox & vbox)
+ * ? text entry widget (single line only)
+ * ? reduce linked list walking and list_nth calls
+ *
+ * ? recursions, unsafe callbacks outside Edje etc. with freeze, ref/unref and block/unblock and break_programs needs to be redesigned & fixed
+ * ? all unsafe calls that may result in callbacks must be marked and dealt with
+ */
+
+struct _Edje_Perspective
+{
+   Evas_Object *obj;
+   Evas        *e;
+   Evas_Coord   px, py, z0, foc;
+   Eina_List   *users;
+   Eina_Bool    global : 1;
+};
+
+struct _Edje_Position_Scale
+{
+   FLOAT_T x, y;
+};
+
+struct _Edje_Position
+{
+   int x, y;
+};
+
+struct _Edje_Size
+{
+   int w, h;
+};
+
+struct _Edje_Rectangle
+{
+   int x, y, w, h;
+};
+
+struct _Edje_Color
+{
+   unsigned char  r, g, b, a;
+};
+
+struct _Edje_Aspect_Prefer
+{
+   FLOAT_T min, max;
+   enum {
+     EDJE_ASPECT_PREFER_NONE,
+     EDJE_ASPECT_PREFER_VERTICAL,
+     EDJE_ASPECT_PREFER_HORIZONTAL,
+     EDJE_ASPECT_PREFER_BOTH
+   } prefer;
+};
+
+struct _Edje_Aspect
+{
+   int w, h;
+   Edje_Aspect_Control mode;
+};
+
+typedef struct _Edje_Position_Scale                  Edje_Alignment;
+typedef struct _Edje_Position_Scale                  Edje_Position_Scale;
+typedef struct _Edje_Position                        Edje_Position;
+typedef struct _Edje_Size                            Edje_Size;
+typedef struct _Edje_Rectangle                       Edje_Rectangle;
+typedef struct _Edje_Color                           Edje_Color;
+typedef struct _Edje_Aspect_Prefer                   Edje_Aspect_Prefer;
+typedef struct _Edje_Aspect                          Edje_Aspect;
+
+typedef struct _Edje_File                            Edje_File;
+typedef struct _Edje_Style                           Edje_Style;
+typedef struct _Edje_Style_Tag                       Edje_Style_Tag;
+typedef struct _Edje_Data                            Edje_Data;
+typedef struct _Edje_External_Directory              Edje_External_Directory;
+typedef struct _Edje_External_Directory_Entry        Edje_External_Directory_Entry;
+typedef struct _Edje_Font_Directory                  Edje_Font_Directory;
+typedef struct _Edje_Font_Directory_Entry            Edje_Font_Directory_Entry;
+typedef struct _Edje_Image_Directory                 Edje_Image_Directory;
+typedef struct _Edje_Image_Directory_Entry           Edje_Image_Directory_Entry;
+typedef struct _Edje_Spectrum_Directory              Edje_Spectrum_Directory;
+typedef struct _Edje_Spectrum_Directory_Entry        Edje_Spectrum_Directory_Entry;
+typedef struct _Edje_Program                         Edje_Program;
+typedef struct _Edje_Program_Target                  Edje_Program_Target;
+typedef struct _Edje_Program_After                   Edje_Program_After;
+typedef struct _Edje_Part_Collection_Directory       Edje_Part_Collection_Directory;
+typedef struct _Edje_Part_Collection_Directory_Entry Edje_Part_Collection_Directory_Entry;
+typedef struct _Edje_Pack_Element                    Edje_Pack_Element;
+typedef struct _Edje_Part_Collection                 Edje_Part_Collection;
+typedef struct _Edje_Part                            Edje_Part;
+typedef struct _Edje_Part_Image_Id                   Edje_Part_Image_Id;
+typedef struct _Edje_Part_Description                Edje_Part_Description;
+typedef struct _Edje_Spectrum_Color                  Edje_Spectrum_Color;
+typedef struct _Edje_Patterns                        Edje_Patterns;
+
+#define EDJE_INF_MAX_W 100000
+#define EDJE_INF_MAX_H 100000
+
+#define EDJE_IMAGE_SOURCE_TYPE_NONE           0
+#define EDJE_IMAGE_SOURCE_TYPE_INLINE_PERFECT 1
+#define EDJE_IMAGE_SOURCE_TYPE_INLINE_LOSSY   2
+#define EDJE_IMAGE_SOURCE_TYPE_EXTERNAL       3
+#define EDJE_IMAGE_SOURCE_TYPE_LAST           4
+
+#define EDJE_VAR_NONE   0
+#define EDJE_VAR_INT    1
+#define EDJE_VAR_FLOAT  2
+#define EDJE_VAR_STRING 3
+#define EDJE_VAR_LIST   4
+#define EDJE_VAR_HASH   5
+
+#define EDJE_VAR_MAGIC_BASE 0x12fe84ba
+
+#define EDJE_STATE_PARAM_NONE            0
+#define EDJE_STATE_PARAM_ALIGNMENT       1
+#define EDJE_STATE_PARAM_MIN             2
+#define EDJE_STATE_PARAM_MAX             3
+#define EDJE_STATE_PARAM_STEP            4
+#define EDJE_STATE_PARAM_ASPECT          5
+#define EDJE_STATE_PARAM_ASPECT_PREF     6
+#define EDJE_STATE_PARAM_COLOR           7
+#define EDJE_STATE_PARAM_COLOR2          8
+#define EDJE_STATE_PARAM_COLOR3          9
+#define EDJE_STATE_PARAM_COLOR_CLASS    10
+#define EDJE_STATE_PARAM_REL1           11
+#define EDJE_STATE_PARAM_REL1_TO        12
+#define EDJE_STATE_PARAM_REL1_OFFSET    13
+#define EDJE_STATE_PARAM_REL2           14
+#define EDJE_STATE_PARAM_REL2_TO        15
+#define EDJE_STATE_PARAM_REL2_OFFSET    16
+#define EDJE_STATE_PARAM_IMAGE          17
+#define EDJE_STATE_PARAM_BORDER         18
+#define EDJE_STATE_PARAM_FILL_SMOOTH    19
+#define EDJE_STATE_PARAM_FILL_POS       20
+#define EDJE_STATE_PARAM_FILL_SIZE      21
+#define EDJE_STATE_PARAM_TEXT           22
+#define EDJE_STATE_PARAM_TEXT_CLASS     23
+#define EDJE_STATE_PARAM_TEXT_FONT      24
+#define EDJE_STATE_PARAM_TEXT_STYLE     25
+#define EDJE_STATE_PARAM_TEXT_SIZE      26
+#define EDJE_STATE_PARAM_TEXT_FIT       27
+#define EDJE_STATE_PARAM_TEXT_MIN       28
+#define EDJE_STATE_PARAM_TEXT_MAX       29
+#define EDJE_STATE_PARAM_TEXT_ALIGN     30
+#define EDJE_STATE_PARAM_VISIBLE        31
+#define EDJE_STATE_PARAM_MAP_OM         32
+#define EDJE_STATE_PARAM_MAP_PERSP      33
+#define EDJE_STATE_PARAM_MAP_LIGNT      34
+#define EDJE_STATE_PARAM_MAP_ROT_CENTER 35
+#define EDJE_STATE_PARAM_MAP_ROT_X      36
+#define EDJE_STATE_PARAM_MAP_ROT_Y      37
+#define EDJE_STATE_PARAM_MAP_ROT_Z      38
+#define EDJE_STATE_PARAM_MAP_BACK_CULL  39
+#define EDJE_STATE_PARAM_MAP_PERSP_ON   40
+#define EDJE_STATE_PARAM_PERSP_ZPLANE   41
+#define EDJE_STATE_PARAM_PERSP_FOCAL    42
+#define EDJE_STATE_PARAM_LAST           43
+
+#define EDJE_ENTRY_EDIT_MODE_NONE 0
+#define EDJE_ENTRY_EDIT_MODE_SELECTABLE 1
+#define EDJE_ENTRY_EDIT_MODE_EDITABLE 2
+#define EDJE_ENTRY_EDIT_MODE_PASSWORD 3
+
+#define EDJE_ENTRY_SELECTION_MODE_DEFAULT 0
+#define EDJE_ENTRY_SELECTION_MODE_EXPLICIT 1
+
+#define EDJE_PART_PATH_SEPARATOR ':'
+#define EDJE_PART_PATH_SEPARATOR_STRING ":"
+/*----------*/
+
+struct _Edje_File
+{
+   const char                     *path;
+   time_t                          mtime;
+
+   Edje_External_Directory        *external_dir;
+   Edje_Font_Directory            *font_dir;
+   Edje_Image_Directory           *image_dir;
+   Edje_Spectrum_Directory        *spectrum_dir;
+   Edje_Part_Collection_Directory *collection_dir;
+   Eina_List                      *data;
+   Eina_List                      *styles;
+   Eina_List                      *color_classes;
+
+   int                             references;
+   char                           *compiler;
+   int                             version;
+   int                             feature_ver;
+
+   Eina_Hash                      *collection_hash;
+   Eina_Hash                     *font_hash;
+   Eina_List                      *collection_cache;
+   Eina_Hash                      *data_cache;
+
+   Eet_File                       *ef;
+   
+   unsigned int                    free_strings : 1;
+   unsigned int                    dangling : 1;
+};
+
+struct _Edje_Style
+{
+   char                           *name;
+   Eina_List                      *tags;
+   Evas_Textblock_Style           *style;
+};
+
+struct _Edje_Style_Tag
+{
+   const char                     *key;
+   const char                     *value;
+   const char                    *font;
+   double                         font_size;
+   const char                    *text_class;
+};
+
+/*----------*/
+
+struct _Edje_Data
+{
+   char *key;
+   char *value;
+};
+
+/*----------*/
+
+struct _Edje_Font_Directory
+{
+   Eina_List *entries; /* a list of Edje_Font_Directory_Entry */
+};
+
+struct _Edje_Font_Directory_Entry
+{
+   const char *entry; /* the name of the font */
+   const char *path;
+   const char *file; /* the name of the file */
+};
+
+/*----------*/
+
+struct _Edje_External_Directory
+{
+   Eina_List *entries; /* a list of Edje_External_Directory_Entry */
+};
+
+struct _Edje_External_Directory_Entry
+{
+   const char *entry; /* the name of the external */
+};
+
+
+/*----------*/
+
+
+
+/*----------*/
+
+struct _Edje_Image_Directory
+{
+   Eina_List *entries; /* a list of Edje_Image_Directory_Entry */
+};
+
+struct _Edje_Image_Directory_Entry
+{
+   char *entry; /* the nominal name of the image - if any */
+   int   source_type; /* alternate source mode. 0 = none */
+   int   source_param; /* extra params on encoding */
+   int   id; /* the id no. of the image */
+};
+
+/*----------*/
+
+struct _Edje_Spectrum_Directory
+{
+   Eina_List *entries; /* a list of Edje_Spectrum_Directory_Entry */
+};
+
+struct _Edje_Spectrum_Directory_Entry
+{
+   char      *entry;
+   /* only one of the following two should be included. filename takes precedence */
+   char      *filename; /* filename of external spectrum. */
+   Eina_List *color_list; /* list of Edje_Spectrum_Color */
+   int        id;
+};
+
+struct _Edje_Spectrum_Color
+{
+   int r, g, b, a;
+   int d;
+};
+
+
+/*----------*/
+
+struct _Edje_Program /* a conditional program to be run */
+{
+   int         id; /* id of program */
+   const char *name; /* name of the action */
+
+   const char *signal; /* if signal emission name matches the glob here... */
+   const char *source; /* if part that emitted this (name) matches this glob */
+
+   struct {
+      const char *part;
+      const char *state; /* if state is not set, we will try with source */
+   } filter; /* the part filter.part should be in state filter.state for signal to be accepted */
+
+   struct {
+      double   from;
+      double   range;
+   } in;
+
+   int         action; /* type - set state, stop action, set drag pos etc. */
+   const char *state; /* what state of alternates to apply, NULL = default */
+   const char *state2; /* what other state to use - for signal emit action */
+   double      value; /* value of state to apply (if multiple names match) */
+   double      value2; /* other value for drag actions */
+
+   struct {
+      int      mode; /* how to tween - linear, sinusoidal etc. */
+      FLOAT_T  time; /* time to graduate between current and new state */
+   } tween;
+
+   Eina_List  *targets; /* list of target parts to apply the state to */
+
+   Eina_List  *after; /* list of actions to run at the end of this, for looping */
+
+   struct {
+      const char *name;
+      const char *description;
+   } api;
+
+   /* used for PARAM_COPY (param names in state and state2 above!) */
+   struct {
+      int src; /* part where parameter is being retrieved */
+      int dst; /* part where parameter is being stored */
+   } param;
+};
+
+struct _Edje_Program_Target /* the target of an action */
+{
+   int id; /* just the part id no, or action id no */
+};
+
+struct _Edje_Program_After /* the action to run after another action */
+{
+   int id;
+};
+
+/*----------*/
+
+struct _Edje_Part_Collection_Directory
+{
+   Eina_List *entries; /* a list of Edje_Part_Collection_Directory_Entry */
+
+   int        references;
+};
+
+struct _Edje_Part_Collection_Directory_Entry
+{
+   const char *entry; /* the nominal name of the part collection */
+   int         id; /* the id of this named part collection */
+};
+
+/*----------*/
+
+/*----------*/
+
+struct _Edje_Pack_Element
+{
+   unsigned char    type; /* only GROUP supported for now */
+   const char      *name; /* if != NULL, will be set with evas_object_name_set */
+   const char      *source; /* group name to use as source for this element */
+   Edje_Size        min, prefer, max;
+   struct {
+          int l, r, t, b;
+   } padding;
+   Edje_Alignment   align;
+   Edje_Alignment   weight;
+   Edje_Aspect      aspect;
+   const char      *options; /* extra options for custom objects */
+   /* table specific follows */
+   int              col, row;
+   unsigned short   colspan, rowspan;
+};
+
+/*----------*/
+
+struct _Edje_Part_Collection
+{
+   Eina_List *programs; /* a list of Edje_Program */
+   Eina_List *parts; /* a list of Edje_Part */
+   Eina_List *data;
+
+   int        id; /* the collection id */
+
+   struct {
+      Edje_Size min, max;
+   } prop;
+
+   int        references;
+#ifdef EDJE_PROGRAM_CACHE
+   struct {
+      Eina_Hash                   *no_matches;
+      Eina_Hash                   *matches;
+   } prog_cache;
+#endif
+
+   Embryo_Program   *script; /* all the embryo script code for this group */
+   const char       *part;
+   
+   unsigned char    script_only;
+
+   unsigned char    lua_script_only;
+};
+
+struct _Edje_Part
+{
+   const char            *name; /* the name if any of the part */
+   Edje_Part_Description *default_desc; /* the part descriptor for default */
+   Eina_List             *other_desc; /* other possible descriptors */
+   const char            *source, *source2, *source3, *source4, *source5, *source6;
+   int                    id; /* its id number */
+   int                    clip_to_id; /* the part id to clip this one to */
+   struct {
+      int                 step_x; /* drag jumps n pixels (0 = no limit) */
+      int                 step_y; /* drag jumps n pixels (0 = no limit) */
+
+      int                 count_x; /* drag area divided by n (0 = no limit) */
+      int                 count_y; /* drag area divided by n (0 = no limit) */
+
+      int                 confine_id; /* dragging within this bit, -1 = no */
+
+      /* davinchi */
+      int                events_id; /* If it is used as scrollbar */
+
+      signed char         x; /* can u click & drag this bit in x dir */
+      signed char         y; /* can u click & drag this bit in y dir */
+   } dragable;
+   Eina_List             *items; /* packed items for box and table */
+   unsigned char          type; /* what type (image, rect, text) */
+   unsigned char          effect; /* 0 = plain... */
+   unsigned char          mouse_events; /* it will affect/respond to mouse events */
+   unsigned char          repeat_events; /* it will repeat events to objects below */
+   Evas_Event_Flags       ignore_flags;
+   unsigned char          scale; /* should certain properties scale with edje scale factor? */
+   unsigned char          precise_is_inside;
+   unsigned char          use_alternate_font_metrics;
+   unsigned char          pointer_mode;
+   unsigned char          entry_mode;
+   unsigned char          select_mode;
+   unsigned char          multiline;
+   struct {
+      const char         *name;
+      const char         *description;
+   } api;
+};
+
+struct _Edje_Part_Image_Id
+{
+   int id;
+};
+
+struct _Edje_Part_Description
+{
+   struct {
+      double         value; /* the value of the state (for ranges) */
+      const char    *name; /* the named state if any */
+   } state;
+
+   Edje_Alignment align; /* 0 <-> 1.0 alignment within allocated space */
+
+   struct {
+      unsigned char  w, h; /* width or height is fixed in side (cannot expand with Edje object size) */
+   } fixed;
+
+   Edje_Size min, max;
+   Edje_Position step; /* size stepping by n pixels, 0 = none */
+   Edje_Aspect_Prefer aspect;
+
+   struct {
+      FLOAT_T        relative_x;
+      FLOAT_T       relative_y;
+      int            offset_x;
+      int            offset_y;
+      int            id_x; /* -1 = whole part collection, or part ID */
+      int            id_y; /* -1 = whole part collection, or part ID */
+   } rel1, rel2;
+
+   struct {
+      Eina_List     *tween_list; /* list of Edje_Part_Image_Id */
+      int            id; /* the image id to use */
+      int            scale_hint; /* evas scale hint */
+   } image;
+
+   struct {
+      char          *type; /* type of spectrum - 'linear', 'radial', etc */
+      char          *params; /* params for spectrum type */
+      int            id; /* the spectrum id to use */
+      int            use_rel; /* 1 - use rel1,rel2; 0 - use fill */
+      struct {
+         FLOAT_T     relative_x;
+         FLOAT_T     relative_y;
+         int         offset_x;
+         int         offset_y;
+      } rel1, rel2; /* linear gradient fill options */
+   } gradient;
+
+   struct {
+      int            l, r, t, b; /* border scaling on image fill */
+      unsigned char  no_fill; /* do we fill the center of the image if bordered? 1 == NO!!!! */
+      unsigned char  scale; /* scale image border by same as scale factor */
+   } border;
+
+   struct {
+      FLOAT_T        pos_rel_x; /* fill offset x relative to area */
+      FLOAT_T        rel_x; /* relative size compared to area */
+      FLOAT_T        pos_rel_y; /* fill offset y relative to area */
+      FLOAT_T        rel_y; /* relative size compared to area */
+      int            pos_abs_x; /* fill offset x added to fill offset */
+      int            abs_x; /* size of fill added to relative fill */
+      int            pos_abs_y; /* fill offset y added to fill offset */
+      int            abs_y; /* size of fill added to relative fill */
+      int            angle; /* angle of fill -- currently only used by grads */
+      int            spread; /* spread of fill -- currently only used by grads */
+      char           smooth; /* fill with smooth scaling or not */
+      unsigned char  type; /* fill coordinate from container (SCALE) or from source image (TILE) */
+   } fill;
+
+   char             *color_class; /* how to modify the color */
+
+   struct {
+      char          *text; /* if "" or NULL, then leave text unchanged */
+      char          *text_class; /* how to apply/modify the font */
+      char          *style; /* the text style if a textblock */
+      char          *font; /* if a specific font is asked for */
+      char          *repch; /* replacement char for password mode entry */
+
+      Edje_Alignment align; /* text alignment within bounds */
+
+      double         elipsis; /* 0.0 - 1.0 defining where the elipsis align */
+      int            size; /* 0 = use user set size */
+      int            id_source; /* -1 if none */
+      int            id_text_source; /* -1 if none */
+
+      unsigned char  fit_x; /* resize font size down to fit in x dir */
+      unsigned char  fit_y; /* resize font size down to fit in y dir */
+      unsigned char  min_x; /* if text size should be part min size */
+      unsigned char  min_y; /* if text size should be part min size */
+      unsigned char  max_x; /* if text size should be part max size */
+      unsigned char  max_y; /* if text size should be part max size */
+   } text;
+
+   struct {
+      char          *layout, *alt_layout;
+      Edje_Alignment align;
+      struct {
+         int x, y;
+      } padding;
+      struct {
+         Eina_Bool h, v;
+      } min;
+   } box;
+   
+   struct {
+      unsigned char  homogeneous;
+      Edje_Alignment align;
+      struct {
+         int x, y;
+      } padding;
+   } table;
+   
+   struct {
+      int id_persp;
+      int id_light;
+      struct {
+         int id_center;
+         FLOAT_T x, y, z;
+      } rot;
+      unsigned char backcull;
+      unsigned char on;
+      unsigned char persp_on;
+      unsigned char smooth;
+      unsigned char alpha;
+   } map;
+   
+   struct {
+      int zplane;
+      int focal;
+   } persp;
+   
+   Edje_Color color, color2, color3;  /* color for rect or text, shadow etc. */
+   Eina_List *external_params; /* parameters for external objects */
+
+   unsigned char     visible; /* is it shown */
+};
+
+
+/*----------*/
+
+
+typedef struct _Edje Edje;
+typedef struct _Edje_Real_Part_State Edje_Real_Part_State;
+typedef struct _Edje_Real_Part_Drag Edje_Real_Part_Drag;
+typedef struct _Edje_Real_Part Edje_Real_Part;
+typedef struct _Edje_Running_Program Edje_Running_Program;
+typedef struct _Edje_Signal_Callback Edje_Signal_Callback;
+typedef struct _Edje_Calc_Params Edje_Calc_Params;
+typedef struct _Edje_Pending_Program Edje_Pending_Program;
+typedef struct _Edje_Text_Style Edje_Text_Style;
+typedef struct _Edje_Color_Class Edje_Color_Class;
+typedef struct _Edje_Text_Class Edje_Text_Class;
+typedef struct _Edje_Var Edje_Var;
+typedef struct _Edje_Var_Int Edje_Var_Int;
+typedef struct _Edje_Var_Float Edje_Var_Float;
+typedef struct _Edje_Var_String Edje_Var_String;
+typedef struct _Edje_Var_List Edje_Var_List;
+typedef struct _Edje_Var_Hash Edje_Var_Hash;
+typedef struct _Edje_Var_Animator Edje_Var_Animator;
+typedef struct _Edje_Var_Timer Edje_Var_Timer;
+typedef struct _Edje_Var_Pool Edje_Var_Pool;
+typedef struct _Edje_Signal_Source_Char Edje_Signal_Source_Char;
+
+struct _Edje_Signal_Source_Char
+{
+   EINA_RBTREE;
+
+   const char *signal;
+   const char *source;
+
+   Eina_List *list;
+};
+
+struct _Edje_Signals_Sources_Patterns
+{
+   Edje_Patterns *signals_patterns;
+   Edje_Patterns *sources_patterns;
+
+   Eina_Rbtree   *exact_match;
+   Eina_List     *globing;
+};
+
+typedef struct _Edje_Signals_Sources_Patterns Edje_Signals_Sources_Patterns;
+
+struct _Edje
+{
+   const Edje_Smart_Api *api;
+   const char           *path;
+   const char           *group;
+   const char           *parent;
+
+   Evas_Coord            x, y, w, h;
+   Edje_Size             min;
+   double                paused_at;
+   Evas                 *evas; /* the Evas this Edje belongs to */
+   Evas_Object          *obj; /* the smart object */
+   Evas_Object          *clipper; /* a big rect to clip this Edje to */
+   Edje_File            *file; /* the file the data comes form */
+   Edje_Part_Collection *collection; /* the description being used */
+   Eina_List            *actions; /* currently running actions */
+   Eina_List            *callbacks;
+   Eina_List            *pending_actions;
+   Eina_List            *color_classes;
+   Eina_List            *text_classes;
+   /* variable pool for Edje Embryo scripts */
+   Edje_Var_Pool        *var_pool;
+   /* for faster lookups to avoid nth list walks */
+   Edje_Real_Part      **table_parts;
+   Edje_Program        **table_programs;
+   Edje_Real_Part       *focused_part;
+   Eina_List            *subobjs;
+   void                 *script_only_data;
+   int                   table_programs_size;
+   int                   table_parts_size;
+   
+   Edje_Perspective     *persp;
+
+   struct {
+      Edje_Signals_Sources_Patterns callbacks;
+      Edje_Signals_Sources_Patterns programs;
+   } patterns;
+
+   int                   references;
+   int                   block;
+   int                   load_error;
+   int                   freeze;
+   FLOAT_T              scale;
+
+   struct {
+      void (*func) (void *data, Evas_Object *obj, const char *part);
+      void *data;
+   } text_change;
+
+   struct {
+      void                (*func) (void *data, Evas_Object *obj, Edje_Message_Type type, int id, void *msg);
+      void                 *data;
+      int                   num;
+   } message;
+   int                      processing_messages;
+
+   int                   state;
+
+   int                  preload_count;
+
+   unsigned int          dirty : 1;
+   unsigned int          recalc : 1;
+   unsigned int          walking_callbacks : 1;
+   unsigned int          delete_callbacks : 1;
+   unsigned int          just_added_callbacks : 1;
+   unsigned int          have_objects : 1;
+   unsigned int          paused : 1;
+   unsigned int          no_anim : 1;
+   unsigned int          calc_only : 1;
+   unsigned int          walking_actions : 1;
+   unsigned int          block_break : 1;
+   unsigned int          delete_me : 1;
+   unsigned int          postponed : 1;
+   unsigned int          freeze_calc : 1;
+   unsigned int          has_entries : 1;
+   unsigned int          entries_inited : 1;
+#ifdef EDJE_CALC_CACHE
+   unsigned int          text_part_change : 1;
+   unsigned int          all_part_change : 1;
+#endif
+   unsigned int          have_mapped_part : 1;
+
+   lua_State            *L;
+   Eina_Inlist          *lua_objs;
+   int                   lua_ref;
+   
+   struct {
+      Evas_Object *(*func) (void *data, Evas_Object *obj, const char *part, const char *item);
+      void *data;
+   } item_provider;
+};
+
+struct _Edje_Calc_Params
+{
+   int              x, y, w, h; // 16
+   Edje_Rectangle   req; // 16
+   Edje_Rectangle   req_drag; // 16
+   Edje_Color       color; // 4
+   union {
+      struct {
+        struct {
+           int           x, y, w, h; // 16
+           int           angle; // 4
+           int           spread; // 4
+        } fill; // 24
+
+        union {
+           struct {
+              int           l, r, t, b; // 16
+           } image; // 16
+           struct {
+              int           id; // 4
+              char         *type; // 4
+           } gradient; // 8
+        } spec; // 16
+      } common; // 40
+      struct {
+        Edje_Alignment align; /* text alignment within bounds */ // 16
+        double         elipsis; // 8
+        int            size; // 4
+        Edje_Color     color2, color3; // 8
+      } text; // 36
+   } type; // 40
+   unsigned char    visible : 1;
+   unsigned char    smooth : 1; // 1
+}; // 96
+
+struct _Edje_Real_Part_State
+{
+   Edje_Part_Description *description; // 4
+   Edje_Real_Part        *rel1_to_x; // 4
+   Edje_Real_Part        *rel1_to_y; // 4
+   Edje_Real_Part        *rel2_to_x; // 4
+   Edje_Real_Part        *rel2_to_y; // 4
+#ifdef EDJE_CALC_CACHE
+   int                    state; // 4
+   Edje_Calc_Params       p; // 96
+#endif
+   void                  *external_params; // 4
+}; // 24
+// WITH EDJE_CALC_CACHE 124
+
+struct _Edje_Real_Part_Drag
+{
+   FLOAT_T              x, y; // 16
+   Edje_Position_Scale  val, size, step, page; // 64
+   struct {
+      unsigned int      count; // 4
+      int               x, y; // 8
+   } down;
+   struct {
+      int               x, y; // 8
+   } tmp;
+   unsigned char        need_reset : 1; // 4
+   Edje_Real_Part       *confine_to; // 4
+}; // 104
+
+struct _Edje_Real_Part
+{
+   Edje                     *edje; // 4
+   Edje_Part                *part; // 4
+   Evas_Object              *object; // 4
+   int                       x, y, w, h; // 16
+   Edje_Rectangle            req; // 16
+
+   Eina_List                *items; // 4 //FIXME: only if table/box
+   void                     *entry_data; // 4 // FIXME: move to entry section
+   Evas_Object              *cursorbg_object; // 4 // FIXME: move to entry section
+   Evas_Object              *cursorfg_object; // 4 // FIXME: move to entry section
+
+   Evas_Object              *swallowed_object; // 4 // FIXME: move with swallow_params data
+   struct {
+      Edje_Size min, max; // 16
+      Edje_Aspect aspect; // 12
+   } swallow_params; // 28 // FIXME: only if type SWALLOW
+
+   Edje_Real_Part_Drag      *drag; // 4
+   Edje_Real_Part          *events_to; // 4
+
+   struct {
+      Edje_Real_Part        *source; // 4
+      Edje_Real_Part        *text_source; // 4
+      const char            *text; // 4
+      Edje_Position          offset; // 8 text only
+      const char           *font; // 4 text only
+      const char           *style; // 4 text only
+      int                    size; // 4 text only
+      struct {
+        double              in_w, in_h; // 16 text only
+        int                 in_size; // 4 text only
+        const char         *in_str; // 4 text only
+        const char         *out_str; // 4 text only
+        int                 out_size; // 4 text only
+        FLOAT_T             align_x, align_y; // 16 text only
+        double              elipsis; // 8 text only
+        int                 fit_x, fit_y; // 8 text only
+      } cache; // 64
+   } text; // 86 // FIXME make text a potiner to struct and alloc at end
+                 // if part type is TEXT move common members textblock +
+                 // text to front and have smaller struct for textblock
+
+   FLOAT_T                   description_pos; // 8
+   Edje_Part_Description    *chosen_description; // 4
+   Edje_Real_Part_State      param1; // 20
+   // WITH EDJE_CALC_CACHE: 140
+   Edje_Real_Part_State     *param2, *custom; // 8
+
+#ifdef EDJE_CALC_CACHE
+   int                       state; // 4
+#endif
+
+   Edje_Real_Part           *clip_to; // 4
+
+   Edje_Running_Program     *program; // 4
+
+   int                       clicked_button; // 4
+   int                       gradient_id; // 4 // FIXME: only for gradient
+
+   unsigned char             calculated; // 1
+   unsigned char             calculating; // 1
+
+   unsigned char             still_in   : 1; // 1
+#ifdef EDJE_CALC_CACHE
+   unsigned char             invalidate : 1; // 0
+#endif
+}; //  260
+// WITH EDJE_CALC_CACHE: 400
+
+struct _Edje_Running_Program
+{
+   Edje           *edje;
+   Edje_Program   *program;
+   double          start_time;
+   char            delete_me : 1;
+};
+
+struct _Edje_Signal_Callback
+{
+   const char    *signal;
+   const char    *source;
+   void (*func) (void *data, Evas_Object *o, const char *emission, const char *source);
+   void  *data;
+   unsigned char just_added : 1;
+   unsigned char delete_me : 1;
+};
+
+struct _Edje_Pending_Program
+{
+   Edje         *edje;
+   Edje_Program *program;
+   Ecore_Timer  *timer;
+};
+
+struct _Edje_Text_Style
+{
+   struct {
+      unsigned char x, y;
+   } offset;
+   struct {
+      unsigned char l, r, t, b;
+   } pad;
+   int num;
+   struct {
+      unsigned char color; /* 0 = color, 1, 2 = color2, color3 */
+      signed   char x, y; /* offset */
+      unsigned char alpha;
+   } members[32];
+};
+
+struct _Edje_Color_Class
+{
+   const char    *name;
+   unsigned char  r, g, b, a;
+   unsigned char  r2, g2, b2, a2;
+   unsigned char  r3, g3, b3, a3;
+};
+
+struct _Edje_Text_Class
+{
+   const char     *name;
+   const char     *font;
+   Evas_Font_Size  size;
+};
+
+struct _Edje_Var_Int
+{
+   int      v;
+};
+
+struct _Edje_Var_Float
+{
+   double   v;
+};
+
+struct _Edje_Var_String
+{
+   char    *v;
+};
+
+struct _Edje_Var_List
+{
+   Eina_List *v;
+};
+
+struct _Edje_Var_Hash
+{
+   Eina_Hash *v;
+};
+
+struct _Edje_Var_Timer
+{
+   Edje           *edje;
+   int             id;
+   Embryo_Function func;
+   int             val;
+   Ecore_Timer    *timer;
+};
+
+struct _Edje_Var_Animator
+{
+   Edje           *edje;
+   int             id;
+   Embryo_Function func;
+   int             val;
+   double          start, len;
+   char            delete_me;
+};
+
+struct _Edje_Var_Pool
+{
+   int          id_count;
+   Eina_List   *timers;
+   Eina_List   *animators;
+   int          size;
+   Edje_Var    *vars;
+   int          walking_list;
+};
+
+struct _Edje_Var
+{
+   union {
+      Edje_Var_Int    i;
+      Edje_Var_Float  f;
+      Edje_Var_String s;
+      Edje_Var_List   l;
+      Edje_Var_Hash   h;
+   } data;
+   unsigned char type;
+};
+
+typedef enum _Edje_Queue
+{
+   EDJE_QUEUE_APP,
+     EDJE_QUEUE_SCRIPT
+} Edje_Queue;
+
+typedef struct _Edje_Message_Signal Edje_Message_Signal;
+typedef struct _Edje_Message        Edje_Message;
+
+struct _Edje_Message_Signal
+{
+   const char *sig;
+   const char *src;
+};
+
+struct _Edje_Message
+{
+   Edje              *edje;
+   Edje_Queue         queue;
+   Edje_Message_Type  type;
+   int                id;
+   unsigned char     *msg;
+};
+
+typedef enum _Edje_Fill
+{
+   EDJE_FILL_TYPE_SCALE = 0,
+     EDJE_FILL_TYPE_TILE
+} Edje_Fill;
+
+typedef enum _Edje_Match_Error
+{
+   EDJE_MATCH_OK,
+     EDJE_MATCH_ALLOC_ERROR,
+     EDJE_MATCH_SYNTAX_ERROR
+
+} Edje_Match_Error;
+
+typedef struct _Edje_States     Edje_States;
+struct _Edje_Patterns
+{
+   const char    **patterns;
+
+   Edje_States    *states;
+
+   int             ref;
+   Eina_Bool       delete_me : 1;
+   
+   size_t          patterns_size;
+   size_t          max_length;
+   size_t          finals[];
+};
+
+Edje_Patterns   *edje_match_collection_dir_init(Eina_List *lst);
+Edje_Patterns   *edje_match_programs_signal_init(Eina_List *lst);
+Edje_Patterns   *edje_match_programs_source_init(Eina_List *lst);
+Edje_Patterns   *edje_match_callback_signal_init(Eina_List *lst);
+Edje_Patterns   *edje_match_callback_source_init(Eina_List *lst);
+
+Eina_Bool        edje_match_collection_dir_exec(const Edje_Patterns      *ppat,
+                                               const char               *string);
+Eina_Bool        edje_match_programs_exec(const Edje_Patterns    *ppat_signal,
+                                         const Edje_Patterns    *ppat_source,
+                                         const char             *signal,
+                                         const char             *source,
+                                         Eina_List              *programs,
+                                         Eina_Bool (*func)(Edje_Program *pr, void *data),
+                                         void                   *data);
+int              edje_match_callback_exec(Edje_Patterns          *ppat_signal,
+                                         Edje_Patterns          *ppat_source,
+                                         const char             *signal,
+                                         const char             *source,
+                                         Eina_List              *callbacks,
+                                         Edje                   *ed);
+
+void             edje_match_patterns_free(Edje_Patterns *ppat);
+
+Eina_List *edje_match_program_hash_build(const Eina_List *callbacks,
+                                        Eina_Rbtree **tree);
+Eina_List *edje_match_callback_hash_build(const Eina_List *callbacks,
+                                         Eina_Rbtree **tree);
+const Eina_List *edje_match_signal_source_hash_get(const char *signal,
+                                                  const char *source,
+                                                  const Eina_Rbtree *tree);
+void edje_match_signal_source_free(Edje_Signal_Source_Char *key, void *data);
+
+EAPI extern Eet_Data_Descriptor *_edje_edd_edje_file;
+EAPI extern Eet_Data_Descriptor *_edje_edd_edje_style;
+EAPI extern Eet_Data_Descriptor *_edje_edd_edje_style_tag;
+EAPI extern Eet_Data_Descriptor *_edje_edd_edje_data;
+EAPI extern Eet_Data_Descriptor *_edje_edd_edje_font_directory;
+EAPI extern Eet_Data_Descriptor *_edje_edd_edje_font_directory_entry;
+EAPI extern Eet_Data_Descriptor *_edje_edd_edje_image_directory;
+EAPI extern Eet_Data_Descriptor *_edje_edd_edje_image_directory_entry;
+EAPI extern Eet_Data_Descriptor *_edje_edd_edje_spectrum_directory;
+EAPI extern Eet_Data_Descriptor *_edje_edd_edje_spectrum_directory_entry;
+EAPI extern Eet_Data_Descriptor *_edje_edd_edje_program;
+EAPI extern Eet_Data_Descriptor *_edje_edd_edje_program_target;
+EAPI extern Eet_Data_Descriptor *_edje_edd_edje_part_collection_directory;
+EAPI extern Eet_Data_Descriptor *_edje_edd_edje_part_collection_directory_entry;
+EAPI extern Eet_Data_Descriptor *_edje_edd_edje_part_collection;
+EAPI extern Eet_Data_Descriptor *_edje_edd_edje_part;
+EAPI extern Eet_Data_Descriptor *_edje_edd_edje_part_description;
+EAPI extern Eet_Data_Descriptor *_edje_edd_edje_part_image_id;
+EAPI extern Eet_Data_Descriptor *_edje_edd_edje_spectrum_color;
+
+extern int              _edje_anim_count;
+extern Ecore_Animator  *_edje_timer;
+extern Eina_List       *_edje_animators;
+extern Eina_List       *_edje_edjes;
+
+extern char            *_edje_fontset_append;
+extern FLOAT_T          _edje_scale;
+extern int              _edje_freeze_val;
+extern int              _edje_freeze_calc_count;
+extern Eina_List       *_edje_freeze_calc_list;
+
+extern Eina_Mempool *_edje_real_part_mp;
+extern Eina_Mempool *_edje_real_part_state_mp;
+
+void  _edje_part_pos_set(Edje *ed, Edje_Real_Part *ep, int mode, FLOAT_T pos);
+Edje_Part_Description *_edje_part_description_find(Edje *ed, Edje_Real_Part *rp, const char *name, double val);
+void  _edje_part_description_apply(Edje *ed, Edje_Real_Part *ep, const char  *d1, double v1, const char *d2, double v2);
+void  _edje_recalc(Edje *ed);
+void  _edje_recalc_do(Edje *ed);
+void  _edje_part_recalc_1(Edje *ed, Edje_Real_Part *ep);
+int   _edje_part_dragable_calc(Edje *ed, Edje_Real_Part *ep, FLOAT_T *x, FLOAT_T *y);
+void  _edje_dragable_pos_set(Edje *ed, Edje_Real_Part *ep, FLOAT_T x, FLOAT_T y);
+
+int   _edje_timer_cb(void *data);
+int   _edje_pending_timer_cb(void *data);
+void  _edje_callbacks_add(Evas_Object *obj, Edje *ed, Edje_Real_Part *rp);
+void  _edje_callbacks_focus_add(Evas_Object *obj, Edje *ed, Edje_Real_Part *rp);
+void  _edje_callbacks_del(Evas_Object *obj, Edje *ed);
+void  _edje_callbacks_focus_del(Evas_Object *obj, Edje *ed);
+
+void  _edje_edd_init(void);
+void  _edje_edd_shutdown(void);
+
+int _edje_object_file_set_internal(Evas_Object *obj, const char *file, const char *group, Eina_List *group_path);
+
+void  _edje_file_add(Edje *ed);
+void  _edje_file_del(Edje *ed);
+void  _edje_file_free(Edje_File *edf);
+void  _edje_file_cache_shutdown(void);
+void  _edje_collection_free(Edje_File *edf, Edje_Part_Collection *ec);
+void  _edje_collection_free_part_description_free(Edje_Part_Description *desc, Eina_Bool free_strings);
+
+void  _edje_object_smart_set(Edje_Smart_Api *sc);
+const Edje_Smart_Api * _edje_object_smart_class_get(void);
+
+void  _edje_del(Edje *ed);
+void  _edje_ref(Edje *ed);
+void  _edje_unref(Edje *ed);
+void  _edje_clean_objects(Edje *ed);
+void  _edje_ref(Edje *ed);
+void  _edje_unref(Edje *ed);
+
+Eina_Bool _edje_program_run_iterate(Edje_Running_Program *runp, double tim);
+void  _edje_program_end(Edje *ed, Edje_Running_Program *runp);
+void  _edje_program_run(Edje *ed, Edje_Program *pr, Eina_Bool force, const char *ssig, const char *ssrc);
+void _edje_programs_patterns_clean(Edje *ed);
+void _edje_programs_patterns_init(Edje *ed);
+void  _edje_emit(Edje *ed, const char *sig, const char *src);
+void  _edje_emit_handle(Edje *ed, const char *sig, const char *src);
+void  _edje_signals_sources_patterns_clean(Edje_Signals_Sources_Patterns *ssp);
+void  _edje_callbacks_patterns_clean(Edje *ed);
+
+void           _edje_text_init(void);
+void           _edje_text_part_on_add(Edje *ed, Edje_Real_Part *ep);
+void           _edje_text_part_on_del(Edje *ed, Edje_Part *ep);
+void           _edje_text_recalc_apply(Edje *ed, Edje_Real_Part *ep, Edje_Calc_Params *params, Edje_Part_Description *chosen_desc);
+Evas_Font_Size _edje_text_size_calc(Evas_Font_Size size, Edje_Text_Class *tc);
+const char *   _edje_text_class_font_get(Edje *ed, Edje_Part_Description *chosen_desc, int *size, char **free_later);
+
+
+Edje_Real_Part   *_edje_real_part_get(Edje *ed, const char *part);
+Edje_Real_Part   *_edje_real_part_recursive_get(Edje *ed, const char *part);
+Edje_Color_Class *_edje_color_class_find(Edje *ed, const char *color_class);
+void              _edje_color_class_member_add(Edje *ed, const char *color_class);
+void              _edje_color_class_member_del(Edje *ed, const char *color_class);
+void              _edje_color_class_on_del(Edje *ed, Edje_Part *ep);
+void              _edje_color_class_members_free(void);
+void              _edje_color_class_hash_free(void);
+
+Edje_Text_Class  *_edje_text_class_find(Edje *ed, const char *text_class);
+void              _edje_text_class_member_add(Edje *ed, const char *text_class);
+void              _edje_text_class_member_del(Edje *ed, const char *text_class);
+void              _edje_text_class_members_free(void);
+void              _edje_text_class_hash_free(void);
+
+Edje             *_edje_fetch(const Evas_Object *obj);
+int               _edje_freeze(Edje *ed);
+int               _edje_thaw(Edje *ed);
+int               _edje_block(Edje *ed);
+int               _edje_unblock(Edje *ed);
+int               _edje_block_break(Edje *ed);
+void              _edje_block_violate(Edje *ed);
+void              _edje_object_part_swallow_free_cb(void *data, Evas *e, Evas_Object *obj, void *event_info);
+void              _edje_object_part_swallow_changed_hints_cb(void *data, Evas *e, Evas_Object *obj, void *event_info);
+void              _edje_real_part_swallow(Edje_Real_Part *rp, Evas_Object *obj_swallow);
+void              _edje_real_part_swallow_clear(Edje_Real_Part *rp);
+void              _edje_box_init(void);
+void              _edje_box_shutdown(void);
+Eina_Bool         _edje_box_layout_find(const char *name, Evas_Object_Box_Layout *cb, void **data, void (**free_data)(void *data));
+
+Eina_Bool         _edje_real_part_box_append(Edje_Real_Part *rp, Evas_Object *child_obj);
+Eina_Bool         _edje_real_part_box_prepend(Edje_Real_Part *rp, Evas_Object *child_obj);
+Eina_Bool         _edje_real_part_box_insert_before(Edje_Real_Part *rp, Evas_Object *child_obj, const Evas_Object *ref);
+Eina_Bool         _edje_real_part_box_insert_at(Edje_Real_Part *rp, Evas_Object *child_obj, unsigned int pos);
+Evas_Object      *_edje_real_part_box_remove(Edje_Real_Part *rp, Evas_Object *child_obj);
+Evas_Object      *_edje_real_part_box_remove_at(Edje_Real_Part *rp, unsigned int pos);
+Eina_Bool         _edje_real_part_box_remove_all(Edje_Real_Part *rp, Eina_Bool clear);
+Eina_Bool         _edje_real_part_table_pack(Edje_Real_Part *rp, Evas_Object *child_obj, unsigned short col, unsigned short row, unsigned short colspan, unsigned short rowspan);
+Eina_Bool         _edje_real_part_table_unpack(Edje_Real_Part *rp, Evas_Object *child_obj);
+void              _edje_real_part_table_clear(Edje_Real_Part *rp, Eina_Bool clear);
+
+Eina_Bool         _edje_object_part_text_raw_set(Evas_Object *obj, Edje_Real_Part *rp, const char *part, const char *text);
+char             *_edje_text_escape(const char *text);
+char             *_edje_text_unescape(const char *text);
+
+void          _edje_embryo_script_init      (Edje *ed);
+void          _edje_embryo_script_shutdown  (Edje *ed);
+void          _edje_embryo_script_reset     (Edje *ed);
+void          _edje_embryo_test_run         (Edje *ed, const char *fname, const char *sig, const char *src);
+Edje_Var     *_edje_var_new                 (void);
+void          _edje_var_free                (Edje_Var *var);
+void          _edje_var_init                (Edje *ed);
+void          _edje_var_shutdown            (Edje *ed);
+int           _edje_var_string_id_get       (Edje *ed, const char *string);
+int           _edje_var_var_int_get         (Edje *ed, Edje_Var *var);
+void          _edje_var_var_int_set         (Edje *ed, Edje_Var *var, int v);
+double        _edje_var_var_float_get       (Edje *ed, Edje_Var *var);
+void          _edje_var_var_float_set       (Edje *ed, Edje_Var *var, double v);
+const char   *_edje_var_var_str_get         (Edje *ed, Edje_Var *var);
+void          _edje_var_var_str_set         (Edje *ed, Edje_Var *var, const char *str);
+int           _edje_var_int_get             (Edje *ed, int id);
+void          _edje_var_int_set             (Edje *ed, int id, int v);
+double        _edje_var_float_get           (Edje *ed, int id);
+void          _edje_var_float_set           (Edje *ed, int id, double v);
+const char   *_edje_var_str_get             (Edje *ed, int id);
+void          _edje_var_str_set             (Edje *ed, int id, const char *str);
+
+void          _edje_var_list_var_append(Edje *ed, int id, Edje_Var *var);
+void          _edje_var_list_var_prepend(Edje *ed, int id, Edje_Var *var);
+void          _edje_var_list_var_append_relative(Edje *ed, int id, Edje_Var *var, Edje_Var *relative);
+void          _edje_var_list_var_prepend_relative(Edje *ed, int id, Edje_Var *var, Edje_Var *relative);
+Edje_Var     *_edje_var_list_nth(Edje *ed, int id, int n);
+
+int           _edje_var_list_count_get(Edje *ed, int id);
+void          _edje_var_list_remove_nth(Edje *ed, int id, int n);
+
+int           _edje_var_list_nth_int_get(Edje *ed, int id, int n);
+void          _edje_var_list_nth_int_set(Edje *ed, int id, int n, int v);
+void          _edje_var_list_int_append(Edje *ed, int id, int v);
+void          _edje_var_list_int_prepend(Edje *ed, int id, int v);
+void          _edje_var_list_int_insert(Edje *ed, int id, int n, int v);
+
+double        _edje_var_list_nth_float_get(Edje *ed, int id, int n);
+void          _edje_var_list_nth_float_set(Edje *ed, int id, int n, double v);
+void          _edje_var_list_float_append(Edje *ed, int id, double v);
+void          _edje_var_list_float_prepend(Edje *ed, int id, double v);
+void          _edje_var_list_float_insert(Edje *ed, int id, int n, double v);
+
+const char   *_edje_var_list_nth_str_get(Edje *ed, int id, int n);
+void          _edje_var_list_nth_str_set(Edje *ed, int id, int n, const char *v);
+void          _edje_var_list_str_append(Edje *ed, int id, const char *v);
+void          _edje_var_list_str_prepend(Edje *ed, int id, const char *v);
+void          _edje_var_list_str_insert(Edje *ed, int id, int n, const char *v);
+
+int           _edje_var_timer_add           (Edje *ed, double in, const char *fname, int val);
+void          _edje_var_timer_del           (Edje *ed, int id);
+
+int           _edje_var_anim_add            (Edje *ed, double len, const char *fname, int val);
+void          _edje_var_anim_del            (Edje *ed, int id);
+
+void          _edje_message_init            (void);
+void          _edje_message_shutdown        (void);
+void          _edje_message_cb_set          (Edje *ed, void (*func) (void *data, Evas_Object *obj, Edje_Message_Type type, int id, void *msg), void *data);
+Edje_Message *_edje_message_new             (Edje *ed, Edje_Queue queue, Edje_Message_Type type, int id);
+void          _edje_message_free            (Edje_Message *em);
+void          _edje_message_send            (Edje *ed, Edje_Queue queue, Edje_Message_Type type, int id, void *emsg);
+void          _edje_message_parameters_push (Edje_Message *em);
+void          _edje_message_process         (Edje_Message *em);
+void          _edje_message_queue_process   (void);
+void          _edje_message_queue_clear     (void);
+void          _edje_message_del             (Edje *ed);
+
+void _edje_textblock_styles_add(Edje *ed);
+void _edje_textblock_styles_del(Edje *ed);
+void _edje_textblock_style_all_update(Edje *ed);
+void _edje_textblock_style_parse_and_fix(Edje_File *edf);
+void _edje_textblock_style_cleanup(Edje_File *edf);
+Edje_File *_edje_cache_file_coll_open(const char *file, const char *coll, int *error_ret, Edje_Part_Collection **edc_ret);
+void _edje_cache_coll_clean(Edje_File *edf);
+void _edje_cache_coll_flush(Edje_File *edf);
+void _edje_cache_coll_unref(Edje_File *edf, Edje_Part_Collection *edc);
+void _edje_cache_file_unref(Edje_File *edf);
+
+void _edje_embryo_globals_init(Edje *ed);
+
+#define CHKPARAM(n) if (params[0] != (sizeof(Embryo_Cell) * (n))) return -1;
+#define GETSTR(str, par) { \
+   Embryo_Cell *___cptr; \
+   int ___l; \
+   str = NULL; \
+   if ((___cptr = embryo_data_address_get(ep, (par)))) { \
+      ___l = embryo_data_string_length_get(ep, ___cptr); \
+      if (((str) = alloca(___l + 1))) \
+       embryo_data_string_get(ep, ___cptr, (str)); } }
+#define GETSTREVAS(str, par) { \
+   if ((str)) { \
+      if ((par) && (!strcmp((par), (str)))) return 0; \
+      if ((par)) eina_stringshare_del((par)); \
+      (par) = (char *)eina_stringshare_add((str)); } \
+   else (par) = NULL; }
+#define GETFLOAT(val, par) { \
+   float *___cptr; \
+   if ((___cptr = (float *)embryo_data_address_get(ep, (par)))) { \
+      val = *___cptr; } }
+
+#define GETFLOAT_T(val, par)                                           \
+  {                                                                    \
+     float *___cptr;                                                   \
+     if ((___cptr = (float *)embryo_data_address_get(ep, (par))))      \
+       {                                                               \
+         val = FROM_DOUBLE(*___cptr);                                  \
+       }                                                               \
+  }
+
+#define GETINT(val, par) {                     \
+   int *___cptr; \
+   if ((___cptr = (int *)embryo_data_address_get(ep, (par)))) { \
+      val = *___cptr; } }
+#define SETSTR(str, par) { \
+   Embryo_Cell *___cptr; \
+   if ((___cptr = embryo_data_address_get(ep, (par)))) { \
+      embryo_data_string_set(ep, str, ___cptr); } }
+#define SETSTRALLOCATE(s) { \
+   if (s) { \
+      if (strlen((s)) < params[4]) { \
+        SETSTR((s), params[3]); } \
+      else { \
+        char *ss; \
+        ss = alloca(strlen((s)) + 1); \
+        strcpy(ss, (s)); \
+        ss[params[4] - 2] = 0; \
+        SETSTR(ss, params[3]); } } \
+   else \
+     SETSTR("", params[3]); }
+#define SETFLOAT(val, par) { \
+   float *___cptr; \
+   if ((___cptr = (float *)embryo_data_address_get(ep, (par)))) { \
+      *___cptr = (float)val; } }
+#define SETFLOAT_T(val, par)                                           \
+  {                                                                    \
+     float *___cptr;                                                   \
+     if ((___cptr = (float *)embryo_data_address_get(ep, (par))))      \
+       {                                                               \
+         *___cptr = (float) TO_DOUBLE(val);                            \
+       }                                                               \
+  }
+#define SETINT(val, par) { \
+   int *___cptr; \
+   if ((___cptr = (int *)embryo_data_address_get(ep, (par)))) { \
+      *___cptr = (int)val; } }
+
+Eina_Bool _edje_script_only(Edje *ed);
+void _edje_script_only_init(Edje *ed);
+void _edje_script_only_shutdown(Edje *ed);
+void _edje_script_only_show(Edje *ed);
+void _edje_script_only_hide(Edje *ed);
+void _edje_script_only_move(Edje *ed);
+void _edje_script_only_resize(Edje *ed);
+void _edje_script_only_message(Edje *ed, Edje_Message *em);
+
+extern jmp_buf _edje_lua_panic_jmp;
+#define _edje_lua_panic_here() setjmp(_edje_lua_panic_jmp)
+
+lua_State *_edje_lua_state_get();
+lua_State *_edje_lua_new_thread(Edje *ed, lua_State *L);
+void _edje_lua_free_thread(Edje *ed, lua_State *L);
+void _edje_lua_new_reg(lua_State *L, int index, void *ptr);
+void _edje_lua_get_reg(lua_State *L, void *ptr);
+void _edje_lua_free_reg(lua_State *L, void *ptr);
+void _edje_lua_script_fn_new(Edje *ed);
+void _edje_lua_group_fn_new(Edje *ed);
+void _edje_lua_init();
+void _edje_lua_shutdown();
+
+void __edje_lua_error(const char *file, const char *fnc, int line, lua_State *L, int err_code);
+#define _edje_lua_error(L, err_code)                                   \
+  __edje_lua_error(__FILE__, __FUNCTION__, __LINE__, L, err_code)
+
+Eina_Bool  _edje_lua_script_only(Edje *ed);
+void _edje_lua_script_only_init(Edje *ed);
+void _edje_lua_script_only_shutdown(Edje *ed);
+void _edje_lua_script_only_show(Edje *ed);
+void _edje_lua_script_only_hide(Edje *ed);
+void _edje_lua_script_only_move(Edje *ed);
+void _edje_lua_script_only_resize(Edje *ed);
+void _edje_lua_script_only_message(Edje *ed, Edje_Message *em);
+
+void _edje_entry_init(Edje *ed);
+void _edje_entry_shutdown(Edje *ed);
+void _edje_entry_real_part_init(Edje_Real_Part *rp);
+void _edje_entry_real_part_shutdown(Edje_Real_Part *rp);
+void _edje_entry_real_part_configure(Edje_Real_Part *rp);
+const char *_edje_entry_selection_get(Edje_Real_Part *rp);
+const char *_edje_entry_text_get(Edje_Real_Part *rp);
+void _edje_entry_text_markup_set(Edje_Real_Part *rp, const char *text);
+void _edje_entry_text_markup_insert(Edje_Real_Part *rp, const char *text);
+void _edje_entry_set_cursor_start(Edje_Real_Part *rp);
+void _edje_entry_set_cursor_end(Edje_Real_Part *rp);
+void _edje_entry_cursor_copy(Edje_Real_Part *rp, Edje_Cursor cur, Edje_Cursor dst);
+void _edje_entry_select_none(Edje_Real_Part *rp);
+void _edje_entry_select_all(Edje_Real_Part *rp);
+void _edje_entry_select_begin(Edje_Real_Part *rp);
+void _edje_entry_select_extend(Edje_Real_Part *rp);
+const Eina_List *_edje_entry_anchor_geometry_get(Edje_Real_Part *rp, const char *anchor);
+const Eina_List *_edje_entry_anchors_list(Edje_Real_Part *rp);
+Eina_Bool _edje_entry_item_geometry_get(Edje_Real_Part *rp, const char *item, Evas_Coord *cx, Evas_Coord *cy, Evas_Coord *cw, Evas_Coord *ch);
+const Eina_List *_edje_entry_items_list(Edje_Real_Part *rp);
+void _edje_entry_cursor_geometry_get(Edje_Real_Part *rp, Evas_Coord *cx, Evas_Coord *cy, Evas_Coord *cw, Evas_Coord *ch);
+void _edje_entry_select_allow_set(Edje_Real_Part *rp, Eina_Bool allow);
+Eina_Bool _edje_entry_select_allow_get(const Edje_Real_Part *rp);
+void _edje_entry_select_abort(Edje_Real_Part *rp);
+
+Eina_Bool _edje_entry_cursor_next(Edje_Real_Part *rp, Edje_Cursor cur);
+Eina_Bool _edje_entry_cursor_prev(Edje_Real_Part *rp, Edje_Cursor cur);
+Eina_Bool _edje_entry_cursor_up(Edje_Real_Part *rp, Edje_Cursor cur);
+Eina_Bool _edje_entry_cursor_down(Edje_Real_Part *rp, Edje_Cursor cur);
+void _edje_entry_cursor_begin(Edje_Real_Part *rp, Edje_Cursor cur);
+void _edje_entry_cursor_end(Edje_Real_Part *rp, Edje_Cursor cur);
+void _edje_entry_cursor_line_begin(Edje_Real_Part *rp, Edje_Cursor cur);
+void _edje_entry_cursor_line_end(Edje_Real_Part *rp, Edje_Cursor cur);
+Eina_Bool _edje_entry_cursor_is_format_get(Edje_Real_Part *rp, Edje_Cursor cur);
+Eina_Bool _edje_entry_cursor_is_visible_format_get(Edje_Real_Part *rp, Edje_Cursor cur);
+const char *_edje_entry_cursor_content_get(Edje_Real_Part *rp, Edje_Cursor cur);
+    
+void _edje_external_init();
+void _edje_external_shutdown();
+Evas_Object *_edje_external_type_add(const char *type_name, Evas *evas, Evas_Object *parent, const Eina_List *params, const char *part_name);
+void _edje_external_signal_emit(Evas_Object *obj, const char *emission, const char *source);
+Eina_Bool _edje_external_param_set(Evas_Object *obj, const Edje_External_Param *param) EINA_ARG_NONNULL(1, 2);
+Eina_Bool _edje_external_param_get(const Evas_Object *obj, Edje_External_Param *param) EINA_ARG_NONNULL(1, 2);
+void _edje_external_params_free(Eina_List *params, Eina_Bool free_strings);
+void _edje_external_recalc_apply(Edje *ed, Edje_Real_Part *ep, Edje_Calc_Params *params, Edje_Part_Description *chosen_desc);
+void *_edje_external_params_parse(Evas_Object *obj, const Eina_List *params);
+void _edje_external_parsed_params_free(Evas_Object *obj, void *params);
+
+void _edje_module_init();
+void _edje_module_shutdown();
+
+
+
+
+
+
+
+// new lua stuff - supercedes the old
+//#define LUA2 1
+
+#ifdef LUA2
+void _edje_lua2_error_full(const char *file, const char *fnc, int line, lua_State *L, int err_code);
+#define _edje_lua2_error(L, err_code) _edje_lua2_error_full(__FILE__, __FUNCTION__, __LINE__, L, err_code)
+void _edje_lua2_script_init(Edje *ed);
+void _edje_lua2_script_shutdown(Edje *ed);
+void _edje_lua2_script_load(Edje_Part_Collection *edc, void *data, int size);
+void _edje_lua2_script_unload(Edje_Part_Collection *edc);
+#endif
+
+#endif
diff --git a/src/lib/edje_program.c b/src/lib/edje_program.c
new file mode 100644 (file)
index 0000000..4004ad3
--- /dev/null
@@ -0,0 +1,2096 @@
+/*
+ * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifndef _WIN32
+# define _GNU_SOURCE
+#endif
+
+#ifdef HAVE_ALLOCA_H
+# include <alloca.h>
+#elif defined __GNUC__
+# define alloca __builtin_alloca
+#elif defined _AIX
+# define alloca __alloca
+#elif defined _MSC_VER
+# include <malloc.h>
+# define alloca _alloca
+#else
+# include <stddef.h>
+# ifdef  __cplusplus
+extern "C"
+# endif
+void *alloca (size_t);
+#endif
+
+#include <string.h>
+
+#include "edje_private.h"
+
+static void _edje_emit_cb(Edje *ed, const char *sig, const char *src);
+static void _edje_param_copy(Edje_Real_Part *src_part, const char *src_param, Edje_Real_Part *dst_part, const char *dst_param);
+static void _edje_param_set(Edje_Real_Part *part, const char *param, const char *value);
+
+int             _edje_anim_count = 0;
+Ecore_Animator *_edje_timer = NULL;
+Eina_List      *_edje_animators = NULL;
+
+
+/*============================================================================*
+ *                                   API                                      *
+ *============================================================================*/
+
+/**
+ * @addtogroup Edje_program_Group Program
+ *
+ * @brief These functions provide an abstraction layer between the
+ * application code and the interface, while allowing extremely
+ * flexible dynamic layouts and animations.
+ *
+ * @{
+ */
+
+/**
+ * @brief Set edje trasitions' frame time.
+ *
+ * @param t The frame time, in seconds. Default value is 1/30.
+ *
+ * This function sets the edje built-in animations' frame time (thus,
+ * affecting their resolution) by calling
+ * ecore_animator_frametime_set(). This frame time can be retrieved
+ * with edje_frametime_get().
+ *
+ * @see edje_frametime_get()
+ *
+ */
+EAPI void
+edje_frametime_set(double t)
+{
+   ecore_animator_frametime_set(t);
+}
+
+/**
+ * @brief Get edje trasitions' frame time.
+ *
+ * @return The frame time, in seconds.
+ *
+ * This function returns the edje frame time set by
+ * edje_frametime_set().
+ *
+ * @see edje_frametime_set()
+ *
+ */
+EAPI double
+edje_frametime_get(void)
+{
+   return ecore_animator_frametime_get();
+}
+
+/**
+ * @brief Add a callback for a signal emitted by @a obj.
+ *
+ * @param obj A valid Evas_Object handle.
+ * @param emission The signal's name.
+ * @param source The signal's source.
+ * @param func The callback function to be executed when the signal is
+ * emitted.
+ * @param data A pointer to data to pass in to the callback function.
+ *
+ * Connects a callback function to a signal emitted by @a obj.
+ * In EDC, a program can emit a signal as follows:
+ *
+ * @code
+ * program {
+ *   name: "emit_example";
+ *   action: SIGNAL_EMIT "a_signal" "a_source";
+ * }
+ * @endcode
+ *
+ * Assuming a function with the following declaration is definded:
+ *
+ * @code
+ * void cb_signal(void *data, Evas_Object *o, const char *emission, const char *source);
+ * @endcode
+ *
+ * a callback is attached using:
+ *
+ * @code
+ * edje_object_callback_add(obj, "a_signal", "a_source", cb_signal, data);
+ * @endcode
+ *
+ * Here, @a data is an arbitrary pointer to be used as desired.  Note
+ * that @a emission and @a source correspond respectively to the first
+ * and the second parameters at the SIGNAL_EMIT action.
+ *
+ * Internal edje signals can also be attached to, and globs can occur
+ * in either the emission or source name, e.g.
+ *
+ * @code
+ * edje_object_callback_add(obj, "mouse,down,*", "button.*", NULL);
+ * @endcode
+ *
+ * Here, any mouse down events on an edje part whose name begins with
+ * "button." will trigger the callback. The actual signal and source
+ * names will be passed in to the @a emission and @a source parameters
+ * of the callback function (e.g. "mouse,down,2" and "button.close").
+ */
+EAPI void
+edje_object_signal_callback_add(Evas_Object *obj, const char *emission, const char *source, void (*func) (void *data, Evas_Object *o, const char *emission, const char *source), void *data)
+{
+   Edje *ed;
+   Edje_Signal_Callback *escb;
+
+   if ((!emission) || (!source) || (!func)) return;
+   ed = _edje_fetch(obj);
+   if (!ed) return;
+   if (ed->delete_me) return;
+   escb = calloc(1, sizeof(Edje_Signal_Callback));
+   if (emission[0])
+     escb->signal = eina_stringshare_add(emission);
+   if (source[0])
+     escb->source = eina_stringshare_add(source);
+   escb->func = func;
+   escb->data = data;
+   ed->callbacks = eina_list_append(ed->callbacks, escb);
+   if (ed->walking_callbacks)
+     {
+       escb->just_added = 1;
+       ed->just_added_callbacks = 1;
+     }
+   else
+     _edje_callbacks_patterns_clean(ed);
+}
+
+/**
+ * @brief Remove a signal-triggered callback from an object.
+ *
+ * @param obj A valid Evas_Object handle.
+ * @param emission The emission string.
+ * @param source The source string.
+ * @param func The callback function.
+ * @return The data pointer
+ *
+ * This function removes a callback, previously attached to the
+ * emittion of a signal, from the object @a obj. The parameters @a
+ * emission, @a source and @a func must match exactly those passed to
+ * a previous call to edje_object_signal_callback_add(). The data
+ * pointer that was passed to this call will be returned.
+ *
+ * @see edje_object_signal_callback_add().
+ *
+ */
+EAPI void *
+edje_object_signal_callback_del(Evas_Object *obj, const char *emission, const char *source, void (*func) (void *data, Evas_Object *o, const char *emission, const char *source))
+{
+   Edje *ed;
+   Eina_List *l;
+   Edje_Signal_Callback *escb;
+
+   if ((!emission) || (!source) || (!func)) return NULL;
+   ed = _edje_fetch(obj);
+   if (!ed) return NULL;
+   if (ed->delete_me) return NULL;
+   EINA_LIST_FOREACH(ed->callbacks, l, escb)
+     {
+       if ((escb->func == func) &&
+           ((!escb->signal && !emission[0]) ||
+             (escb->signal && !strcmp(escb->signal, emission))) &&
+           ((!escb->source && !source[0]) ||
+             (escb->source && !strcmp(escb->source, source))))
+         {
+            void *data;
+
+            data = escb->data;
+            if (ed->walking_callbacks)
+              {
+                 escb->delete_me = 1;
+                 ed->delete_callbacks = 1;
+              }
+            else
+              {
+                 _edje_callbacks_patterns_clean(ed);
+
+                 ed->callbacks = eina_list_remove_list(ed->callbacks, l);
+                 if (escb->signal) eina_stringshare_del(escb->signal);
+                 if (escb->source) eina_stringshare_del(escb->source);
+                 free(escb);
+              }
+            return data;
+         }
+     }
+   return NULL;
+}
+
+/**
+ * @brief Send a signal to an edje object.
+ *
+ * @param obj A valid Evas_Object handle.
+ * @param emission The signal's name.
+ * @param source The signal's source.
+ *
+ * This function sends a signal to the object @a obj. An edje program
+ * can respond to a signal by specifying matching 'signal' and
+ * 'source' fields.
+ *
+ * @code
+ * edje_object_signal_emit(obj, "a_signal", "");
+ * @endcode
+ *
+ * will trigger a program whose EDC block is:
+ *
+ * @code
+ * program {
+ *  name: "a_program";
+ *  signal: "a_signal";
+ *  source: "";
+ *  action: ...
+ * }
+ * @endcode
+ *
+ * FIXME: should this signal be sent to children also?
+ */
+EAPI void
+edje_object_signal_emit(Evas_Object *obj, const char *emission, const char *source)
+{
+   Edje *ed;
+
+   if ((!emission) || (!source)) return;
+   ed = _edje_fetch(obj);
+   if (!ed) return;
+   if (ed->delete_me) return;
+   _edje_emit(ed, (char *)emission, (char *)source);
+}
+
+/* FIXDOC: Verify/Expand */
+/**
+ * @brief Set the edje object to playing or paused states.
+ *
+ * @param obj A valid Evas_Object handle.
+ * @param play Object state (1 to playing, 0 to pauseed).
+ *
+ * This function sets the edje object @a obj to playing or paused
+ * states, depending on the parameter @a play.  This has no effect if
+ * the object was already at that state.
+ *
+ * @see edje_object_play_get().
+ *
+ */
+EAPI void
+edje_object_play_set(Evas_Object *obj, Eina_Bool play)
+{
+   Edje *ed;
+   double t;
+   Eina_List *l;
+   Edje_Running_Program *runp;
+   int i;
+
+   ed = _edje_fetch(obj);
+   if (!ed) return;
+   if (ed->delete_me) return;
+   if (play)
+     {
+       if (!ed->paused) return;
+       ed->paused = 0;
+       t = ecore_time_get() - ed->paused_at;
+       EINA_LIST_FOREACH(ed->actions, l, runp)
+         runp->start_time += t;
+     }
+   else
+     {
+       if (ed->paused) return;
+       ed->paused = EINA_TRUE;
+       ed->paused_at = ecore_time_get();
+     }
+
+   for (i = 0; i < ed->table_parts_size; i++)
+     {
+       Edje_Real_Part *rp;
+       rp = ed->table_parts[i];
+       if (rp->part->type == EDJE_PART_TYPE_GROUP && rp->swallowed_object)
+         edje_object_play_set(rp->swallowed_object, play);
+     }
+}
+
+/**
+ * @brief Get the edje object's play/pause state.
+ *
+ * @param obj A valid Evas_Object handle.
+ * @return @c EINA_FALSE if the object is not connected, its @c delete_me flag
+ * is set, or it is at paused state; @c EINA_TRUE if the object is at playing
+ * state.
+ *
+ * This function tells if an edje object is playing or not. This state
+ * is set by edje_object_play_set().
+ *
+ * @see edje_object_play_set().
+ *
+ */
+EAPI Eina_Bool
+edje_object_play_get(const Evas_Object *obj)
+{
+   Edje *ed;
+
+   ed = _edje_fetch(obj);
+   if (!ed) return EINA_FALSE;
+   if (ed->delete_me) return EINA_FALSE;
+   if (ed->paused) return EINA_FALSE;
+   return EINA_TRUE;
+}
+
+/* FIXDOC: Verify/Expand */
+/**
+ * @brief Set the object's animation state.
+ *
+ * @param obj A valid Evas_Object handle.
+ * @param on Animation State.
+ *
+ * This function starts or stops an edje object's animation. The
+ * information if it's runnig can be retrieved by
+ * edje_object_animation_get().
+ *
+ * @see edje_object_animation_get()
+ *
+ */
+EAPI void
+edje_object_animation_set(Evas_Object *obj, Eina_Bool on)
+{
+   Edje *ed;
+   Eina_List *l;
+   int i;
+
+   ed = _edje_fetch(obj);
+   if (!ed) return;
+   if (ed->delete_me) return;
+   _edje_block(ed);
+   ed->no_anim = !on;
+   _edje_freeze(ed);
+   if (!on)
+     {
+       Eina_List *newl = NULL;
+       const void *data;
+
+       EINA_LIST_FOREACH(ed->actions, l, data)
+         newl = eina_list_append(newl, data);
+       while (newl)
+         {
+            Edje_Running_Program *runp;
+
+            runp = eina_list_data_get(newl);
+            newl = eina_list_remove(newl, eina_list_data_get(newl));
+            _edje_program_run_iterate(runp, runp->start_time + TO_DOUBLE(runp->program->tween.time));
+            if (_edje_block_break(ed))
+              {
+                 eina_list_free(newl);
+                 goto break_prog;
+              }
+         }
+     }
+   else
+     {
+       _edje_emit(ed, "load", NULL);
+       if (evas_object_visible_get(obj))
+         {
+            evas_object_hide(obj);
+            evas_object_show(obj);
+         }
+     }
+   break_prog:
+
+   for (i = 0; i < ed->table_parts_size; i++)
+     {
+       Edje_Real_Part *rp;
+       rp = ed->table_parts[i];
+       if (rp->part->type == EDJE_PART_TYPE_GROUP && rp->swallowed_object)
+         edje_object_animation_set(rp->swallowed_object, on);
+     }
+
+   _edje_thaw(ed);
+   _edje_unblock(ed);
+}
+
+/**
+ * @brief Get the edje object's animation state.
+ *
+ * @param obj A valid Evas_Object handle.
+ * @return @c EINA_FALSE on error or if object is not animated;
+ * @c EINA_TRUE if animated.
+ *
+ * This function returns if the animation is playing or not. The
+ * animation state is set by edje_object_play_set().
+ *
+ * @see edje_object_animation_set().
+ *
+ */
+
+EAPI Eina_Bool
+edje_object_animation_get(const Evas_Object *obj)
+{
+   Edje *ed;
+
+   ed = _edje_fetch(obj);
+   if (!ed) return EINA_FALSE;
+   if (ed->delete_me) return EINA_FALSE;
+   if (ed->no_anim) return EINA_FALSE;
+   return EINA_TRUE;
+}
+
+/* Private Routines */
+
+Eina_Bool
+_edje_program_run_iterate(Edje_Running_Program *runp, double tim)
+{
+   FLOAT_T t, total;
+   Eina_List *l;
+   Edje *ed;
+   Edje_Program_Target *pt;
+   Edje_Real_Part *rp;
+
+   ed = runp->edje;
+   if (ed->delete_me) return 0;
+   _edje_block(ed);
+   _edje_ref(ed);
+   _edje_freeze(ed);
+   t = FROM_DOUBLE(tim - runp->start_time);
+   total = runp->program->tween.time;
+   t = DIV(t, total);
+   if (t > FROM_INT(1)) t = FROM_INT(1);
+   EINA_LIST_FOREACH(runp->program->targets, l, pt)
+     {
+       if (pt->id >= 0)
+         {
+            rp = ed->table_parts[pt->id % ed->table_parts_size];
+            if (rp) _edje_part_pos_set(ed, rp,
+                                       runp->program->tween.mode, t);
+         }
+     }
+   if (t >= FROM_INT(1))
+     {
+        Edje_Program_After *pa;
+
+        EINA_LIST_FOREACH(runp->program->targets, l, pt)
+         {
+            if (pt->id >= 0)
+              {
+                 rp = ed->table_parts[pt->id % ed->table_parts_size];
+                 if (rp)
+                   {
+                      _edje_part_description_apply(ed, rp,
+                                                   runp->program->state,
+                                                   runp->program->value,
+                                                   NULL,
+                                                   0.0);
+                      _edje_part_pos_set(ed, rp,
+                                         runp->program->tween.mode, ZERO);
+                      rp->program = NULL;
+                   }
+              }
+         }
+       _edje_recalc(ed);
+       runp->delete_me = 1;
+       if (!ed->walking_actions)
+         {
+            _edje_anim_count--;
+            ed->actions = eina_list_remove(ed->actions, runp);
+            if (!ed->actions)
+              _edje_animators = eina_list_remove(_edje_animators, ed);
+         }
+//     _edje_emit(ed, "program,stop", runp->program->name);
+       if (_edje_block_break(ed))
+         {
+            if (!ed->walking_actions) free(runp);
+            goto break_prog;
+         }
+       EINA_LIST_FOREACH(runp->program->after, l, pa)
+         {
+            Edje_Program *pr;
+
+            if (pa->id >= 0)
+              {
+                 pr = ed->table_programs[pa->id % ed->table_programs_size];
+                 if (pr) _edje_program_run(ed, pr, 0, "", "");
+                 if (_edje_block_break(ed))
+                   {
+                      if (!ed->walking_actions) free(runp);
+                      goto break_prog;
+                   }
+              }
+         }
+       _edje_thaw(ed);
+       _edje_unref(ed);
+       if (!ed->walking_actions) free(runp);
+       _edje_unblock(ed);
+       return  0;
+     }
+   break_prog:
+   _edje_recalc(ed);
+   _edje_thaw(ed);
+   _edje_unref(ed);
+   _edje_unblock(ed);
+   return 1;
+}
+
+void
+_edje_program_end(Edje *ed, Edje_Running_Program *runp)
+{
+   Eina_List *l;
+   Edje_Program_Target *pt;
+   const char *pname = NULL;
+   int free_runp = 0;
+
+   if (ed->delete_me) return;
+   _edje_ref(ed);
+   _edje_freeze(ed);
+   EINA_LIST_FOREACH(runp->program->targets, l, pt)
+     {
+       Edje_Real_Part *rp;
+
+       if (pt->id >= 0)
+         {
+            rp = ed->table_parts[pt->id % ed->table_parts_size];
+            if (rp)
+              {
+                 _edje_part_description_apply(ed, rp,
+                                              runp->program->state,
+                                              runp->program->value,
+                                              NULL,
+                                              0.0);
+                 _edje_part_pos_set(ed, rp,
+                                    runp->program->tween.mode, ZERO);
+                 rp->program = NULL;
+              }
+         }
+     }
+   _edje_recalc(ed);
+   runp->delete_me = 1;
+   pname = runp->program->name;
+   if (!ed->walking_actions)
+     {
+       _edje_anim_count--;
+       ed->actions = eina_list_remove(ed->actions, runp);
+       free_runp = 1;
+       if (!ed->actions)
+         {
+            _edje_animators = eina_list_remove(_edje_animators, ed);
+         }
+     }
+//   _edje_emit(ed, "program,stop", pname);
+   _edje_thaw(ed);
+   _edje_unref(ed);
+   if (free_runp) free(runp);
+}
+
+void
+_edje_program_run(Edje *ed, Edje_Program *pr, Eina_Bool force, const char *ssig, const char *ssrc)
+{
+   Eina_List *l;
+   Edje_Real_Part *rp;
+   Edje_Program_Target *pt;
+   Edje_Program *pr2;
+   Edje_Program_After *pa;
+   /* limit self-feeding loops in programs to 64 levels */
+   static int recursions = 0;
+   static int recursion_limit = 0;
+
+   if (ed->delete_me) return;
+   if ((pr->in.from > 0.0) && (pr->in.range >= 0.0) && (!force))
+     {
+       Edje_Pending_Program *pp;
+       double r = 0.0;
+
+       pp = calloc(1, sizeof(Edje_Pending_Program));
+       if (!pp) return;
+       if (pr->in.range > 0.0) r = ((double)rand() / RAND_MAX);
+       pp->timer = ecore_timer_add(pr->in.from + (pr->in.range * r),
+                                   _edje_pending_timer_cb, pp);
+       if (!pp->timer)
+         {
+            free(pp);
+            return;
+         }
+       pp->edje = ed;
+       pp->program = pr;
+       ed->pending_actions = eina_list_append(ed->pending_actions, pp);
+       return;
+     }
+   if ((recursions >= 64) || (recursion_limit))
+     {
+       ERR("Programs recursing up to recursion limit of %i. Disabled.",
+           64);
+       recursion_limit = 1;
+       return;
+     }
+   recursions++;
+   _edje_block(ed);
+   _edje_ref(ed);
+   _edje_freeze(ed);
+   if (pr->action == EDJE_ACTION_TYPE_STATE_SET)
+     {
+       if ((pr->tween.time > ZERO) && (!ed->no_anim))
+         {
+            Edje_Running_Program *runp;
+
+            runp = calloc(1, sizeof(Edje_Running_Program));
+            EINA_LIST_FOREACH(pr->targets, l, pt)
+              {
+                 if (pt->id >= 0)
+                   {
+                      rp = ed->table_parts[pt->id % ed->table_parts_size];
+                      if (rp)
+                        {
+                           if (rp->program)
+                             _edje_program_end(ed, rp->program);
+                           _edje_part_description_apply(ed, rp,
+                                                        rp->param1.description->state.name,
+                                                        rp->param1.description->state.value,
+                                                        pr->state,
+                                                        pr->value);
+                           _edje_part_pos_set(ed, rp, pr->tween.mode, ZERO);
+                           rp->program = runp;
+                        }
+                   }
+              }
+//          _edje_emit(ed, "program,start", pr->name);
+            if (_edje_block_break(ed))
+              {
+                 ed->actions = eina_list_append(ed->actions, runp);
+                 goto break_prog;
+              }
+            if (!ed->actions)
+              _edje_animators = eina_list_append(_edje_animators, ed);
+            ed->actions = eina_list_append(ed->actions, runp);
+            runp->start_time = ecore_loop_time_get();
+            runp->edje = ed;
+            runp->program = pr;
+            if (!_edje_timer)
+              _edje_timer = ecore_animator_add(_edje_timer_cb, NULL);
+            _edje_anim_count++;
+         }
+       else
+         {
+            EINA_LIST_FOREACH(pr->targets, l, pt)
+              {
+                 if (pt->id >= 0)
+                   {
+                      rp = ed->table_parts[pt->id % ed->table_parts_size];
+                      if (rp)
+                        {
+                           if (rp->program)
+                             _edje_program_end(ed, rp->program);
+                           _edje_part_description_apply(ed, rp,
+                                                        pr->state,
+                                                        pr->value,
+                                                        NULL,
+                                                        0.0);
+                           _edje_part_pos_set(ed, rp, pr->tween.mode, ZERO);
+                        }
+                   }
+              }
+//          _edje_emit(ed, "program,start", pr->name);
+            if (_edje_block_break(ed)) goto break_prog;
+//          _edje_emit(ed, "program,stop", pr->name);
+            if (_edje_block_break(ed)) goto break_prog;
+
+            EINA_LIST_FOREACH(pr->after, l, pa)
+              {
+                 if (pa->id >= 0)
+                   {
+                      pr2 = ed->table_programs[pa->id % ed->table_programs_size];
+                      if (pr2) _edje_program_run(ed, pr2, 0, "", "");
+                      if (_edje_block_break(ed)) goto break_prog;
+                   }
+              }
+            _edje_recalc(ed);
+         }
+     }
+   else if (pr->action == EDJE_ACTION_TYPE_ACTION_STOP)
+     {
+//     _edje_emit(ed, "program,start", pr->name);
+        EINA_LIST_FOREACH(pr->targets, l, pt)
+         {
+            Eina_List *ll;
+            Edje_Running_Program *runp;
+            Edje_Pending_Program *pp;
+
+            EINA_LIST_FOREACH(ed->actions, ll, runp)
+              {
+                 if (pt->id == runp->program->id)
+                   {
+                      _edje_program_end(ed, runp);
+//                    goto done;
+                   }
+              }
+            EINA_LIST_FOREACH(ed->pending_actions, ll, pp)
+              {
+                 if (pt->id == pp->program->id)
+                   {
+                      ed->pending_actions = eina_list_remove(ed->pending_actions, pp);
+                      ecore_timer_del(pp->timer);
+                      free(pp);
+//                    goto done;
+                   }
+              }
+//          done:
+//             continue;
+         }
+//     _edje_emit(ed, "program,stop", pr->name);
+       if (_edje_block_break(ed)) goto break_prog;
+     }
+   else if (pr->action == EDJE_ACTION_TYPE_SIGNAL_EMIT)
+     {
+//     _edje_emit(ed, "program,start", pr->name);
+       if (_edje_block_break(ed)) goto break_prog;
+       _edje_emit(ed, pr->state, pr->state2);
+       if (_edje_block_break(ed)) goto break_prog;
+//     _edje_emit(ed, "program,stop", pr->name);
+       if (_edje_block_break(ed)) goto break_prog;
+     }
+   else if (pr->action == EDJE_ACTION_TYPE_DRAG_VAL_SET)
+     {
+//     _edje_emit(ed, "program,start", pr->name);
+       if (_edje_block_break(ed)) goto break_prog;
+       EINA_LIST_FOREACH(pr->targets, l, pt)
+         {
+            if (pt->id >= 0)
+              {
+                 rp = ed->table_parts[pt->id % ed->table_parts_size];
+                 if ((rp) && (rp->drag) && (rp->drag->down.count == 0))
+                   {
+                      rp->drag->val.x = pr->value;
+                      rp->drag->val.y = pr->value2;
+                      if      (rp->drag->val.x < 0.0) rp->drag->val.x = 0.0;
+                      else if (rp->drag->val.x > 1.0) rp->drag->val.x = 1.0;
+                      if      (rp->drag->val.y < 0.0) rp->drag->val.y = 0.0;
+                      else if (rp->drag->val.y > 1.0) rp->drag->val.y = 1.0;
+                      _edje_dragable_pos_set(ed, rp, rp->drag->val.x, rp->drag->val.y);
+                      _edje_emit(ed, "drag,set", rp->part->name);
+                      if (_edje_block_break(ed)) goto break_prog;
+                   }
+              }
+         }
+//     _edje_emit(ed, "program,stop", pr->name);
+       if (_edje_block_break(ed)) goto break_prog;
+     }
+   else if (pr->action == EDJE_ACTION_TYPE_DRAG_VAL_STEP)
+     {
+//     _edje_emit(ed, "program,start", pr->name);
+       if (_edje_block_break(ed)) goto break_prog;
+       EINA_LIST_FOREACH(pr->targets, l, pt)
+         {
+            if (pt->id >= 0)
+              {
+                 rp = ed->table_parts[pt->id % ed->table_parts_size];
+                 if ((rp) && (rp->drag) && (rp->drag->down.count == 0))
+                   {
+                      rp->drag->val.x += pr->value * rp->drag->step.x * rp->part->dragable.x;
+                      rp->drag->val.y += pr->value2 * rp->drag->step.y * rp->part->dragable.y;
+                      if      (rp->drag->val.x < 0.0) rp->drag->val.x = 0.0;
+                      else if (rp->drag->val.x > 1.0) rp->drag->val.x = 1.0;
+                      if      (rp->drag->val.y < 0.0) rp->drag->val.y = 0.0;
+                      else if (rp->drag->val.y > 1.0) rp->drag->val.y = 1.0;
+                      _edje_dragable_pos_set(ed, rp, rp->drag->val.x, rp->drag->val.y);
+                      _edje_emit(ed, "drag,step", rp->part->name);
+                      if (_edje_block_break(ed)) goto break_prog;
+                   }
+              }
+         }
+//     _edje_emit(ed, "program,stop", pr->name);
+       if (_edje_block_break(ed)) goto break_prog;
+     }
+   else if (pr->action == EDJE_ACTION_TYPE_DRAG_VAL_PAGE)
+     {
+//     _edje_emit(ed, "program,start", pr->name);
+       if (_edje_block_break(ed)) goto break_prog;
+       EINA_LIST_FOREACH(pr->targets, l, pt)
+         {
+            if (pt->id >= 0)
+              {
+                 rp = ed->table_parts[pt->id % ed->table_parts_size];
+                 if ((rp) && (rp->drag) && (rp->drag->down.count == 0))
+                   {
+                      rp->drag->val.x += pr->value * rp->drag->page.x * rp->part->dragable.x;
+                      rp->drag->val.y += pr->value2 * rp->drag->page.y * rp->part->dragable.y;
+                      if      (rp->drag->val.x < 0.0) rp->drag->val.x = 0.0;
+                      else if (rp->drag->val.x > 1.0) rp->drag->val.x = 1.0;
+                      if      (rp->drag->val.y < 0.0) rp->drag->val.y = 0.0;
+                      else if (rp->drag->val.y > 1.0) rp->drag->val.y = 1.0;
+                      _edje_dragable_pos_set(ed, rp, rp->drag->val.x, rp->drag->val.y);
+                      _edje_emit(ed, "drag,page", rp->part->name);
+                      if (_edje_block_break(ed)) goto break_prog;
+                   }
+              }
+         }
+//     _edje_emit(ed, "program,stop", pr->name);
+       if (_edje_block_break(ed)) goto break_prog;
+     }
+   else if (pr->action == EDJE_ACTION_TYPE_SCRIPT)
+     {
+       char fname[128];
+
+//     _edje_emit(ed, "program,start", pr->name);
+       if (_edje_block_break(ed)) goto break_prog;
+       snprintf(fname, sizeof(fname), "_p%i", pr->id);
+       _edje_embryo_test_run(ed, fname, ssig, ssrc);
+//     _edje_emit(ed, "program,stop", pr->name);
+       if (_edje_block_break(ed)) goto break_prog;
+       _edje_recalc_do(ed);
+     }
+   else if (pr->action == EDJE_ACTION_TYPE_LUA_SCRIPT)
+     {
+       //printf ("running Lua program script %i\n", pr->id);
+
+//     _edje_emit(ed, "program,start", pr->name);
+       if (_edje_block_break(ed)) goto break_prog;
+        
+#ifdef LUA2
+       _edje_lua2_script_init(ed);
+#else        
+       if (ed->L == NULL) /* private state does not yet exist, create it */
+         {
+            ed->L = _edje_lua_new_thread(ed, _edje_lua_state_get());
+         }
+       lua_State *L = ed->L;
+       lua_pushnumber(L, pr->id);
+       lua_gettable(L, LUA_GLOBALSINDEX);
+       if (!lua_isnil(L, -1))
+         {
+            int err_code;
+
+            lua_pushvalue(L, LUA_GLOBALSINDEX); /* set function environment from collection thread to edje object thread */
+            lua_setfenv(L, -2);
+            _edje_lua_get_reg(L, ed);
+            if (lua_isnil(L, -1)) /* group object does not yet exist, create it */
+              {
+                 lua_pop(L, 1);
+                 _edje_lua_group_fn_new (ed);
+              }
+            lua_pushstring(L, ssig);
+            lua_pushstring(L, ssrc);
+
+            if ((err_code = lua_pcall(L, 3, 0, 0)))
+              _edje_lua_error(L, err_code);
+         }
+#endif
+       //      _edje_emit(ed, "program,stop", pr->name);
+       if (_edje_block_break(ed)) goto break_prog;
+       _edje_recalc_do(ed);
+     }
+   else if (pr->action == EDJE_ACTION_TYPE_FOCUS_SET)
+     {
+       if (!pr->targets)
+         {
+            ed->focused_part = NULL;
+         }
+       else
+         {
+            EINA_LIST_FOREACH(pr->targets, l, pt)
+              {
+                 if (pt->id >= 0)
+                   {
+                      rp = ed->table_parts[pt->id % ed->table_parts_size];
+                      if (rp)
+                        {
+                           if (ed->focused_part != rp)
+                             {
+                                if (ed->focused_part)
+                                  _edje_emit(ed, "focus,part,out", 
+                                             ed->focused_part->part->name);
+                                ed->focused_part = rp;
+                                _edje_emit(ed, "focus,part,in",
+                                           ed->focused_part->part->name);
+                             }
+                        }
+                   }
+              }
+         }
+     }
+   else if (pr->action == EDJE_ACTION_TYPE_FOCUS_OBJECT)
+     {
+       if (!pr->targets)
+         {
+            Evas_Object *focused;
+
+            focused = evas_focus_get(evas_object_evas_get(ed->obj));
+            if (focused)
+              {
+                 int i;
+
+                 /* Check if the current swallowed object is one of my child. */
+                 for (i = 0; i < ed->table_parts_size; ++i)
+                   {
+                      rp = ed->table_parts[i];
+                      if (rp && rp->swallowed_object == focused)
+                        {
+                           evas_object_focus_set(focused, EINA_FALSE);
+                           break;
+                        }
+                   }
+              }
+         }
+       else
+         {
+            EINA_LIST_FOREACH(pr->targets, l, pt)
+              {
+                 if (pt->id >= 0)
+                   {
+                      rp = ed->table_parts[pt->id % ed->table_parts_size];
+                      if (rp && rp->swallowed_object)
+                        {
+                           evas_object_focus_set(rp->swallowed_object, EINA_TRUE);
+                        }
+                   }
+              }
+         }
+     }
+   else if (pr->action == EDJE_ACTION_TYPE_PARAM_COPY)
+     {
+       Edje_Real_Part *src_part, *dst_part;
+
+//     _edje_emit(ed, "program,start", pr->name);
+       if (_edje_block_break(ed)) goto break_prog;
+
+       src_part = ed->table_parts[pr->param.src % ed->table_parts_size];
+       dst_part = ed->table_parts[pr->param.dst % ed->table_parts_size];
+       _edje_param_copy(src_part, pr->state, dst_part, pr->state2);
+
+       if (_edje_block_break(ed)) goto break_prog;
+//     _edje_emit(ed, "program,stop", pr->name);
+       if (_edje_block_break(ed)) goto break_prog;
+     }
+   else if (pr->action == EDJE_ACTION_TYPE_PARAM_SET)
+     {
+       Edje_Real_Part *part;
+
+//     _edje_emit(ed, "program,start", pr->name);
+       if (_edje_block_break(ed)) goto break_prog;
+
+       part = ed->table_parts[pr->param.dst % ed->table_parts_size];
+       _edje_param_set(part, pr->state, pr->state2);
+
+       if (_edje_block_break(ed)) goto break_prog;
+//     _edje_emit(ed, "program,stop", pr->name);
+       if (_edje_block_break(ed)) goto break_prog;
+     }
+   else
+     {
+//     _edje_emit(ed, "program,start", pr->name);
+//     _edje_emit(ed, "program,stop", pr->name);
+     }
+   if (!((pr->action == EDJE_ACTION_TYPE_STATE_SET)
+        /* hmm this fucks somethgin up. must look into it later */
+        /* && (pr->tween.time > ZERO) && (!ed->no_anim))) */
+        ))
+     {
+        EINA_LIST_FOREACH(pr->after, l, pa)
+         {
+            if (pa->id >= 0)
+              {
+                 pr2 = ed->table_programs[pa->id % ed->table_programs_size];
+                 if (pr2) _edje_program_run(ed, pr2, 0, "", "");
+                 if (_edje_block_break(ed)) goto break_prog;
+              }
+         }
+     }
+   break_prog:
+   _edje_thaw(ed);
+   _edje_unref(ed);
+   recursions--;
+   if (recursions == 0) recursion_limit = 0;
+   _edje_unblock(ed);
+}
+
+void
+_edje_emit(Edje *ed, const char *sig, const char *src)
+{
+   Edje_Message_Signal emsg;
+   Eina_List *l;
+   Evas_Object *obj;
+   const char *sep;
+
+   if (ed->delete_me) return;
+
+   sep = strchr(sig, ':');
+   if (sep)
+     {
+        size_t length;
+        char *part;
+       /* the signal contains a colon, split the signal into "part:signal",
+       * and deliver it to "part" (if there is a GROUP or EXTERNAL part named "part")
+       */
+       length = strlen(sig) + 1;
+       part = alloca(length);
+       if (part)
+        {
+            char *newsig;
+           int i;
+
+            memcpy(part, sig, length);
+            newsig = part + (sep - sig);
+           *newsig = '\0';
+           newsig++;
+
+            for (i = 0; i < ed->table_parts_size; i++)
+              {
+                 Edje_Real_Part *rp = ed->table_parts[i];
+                 if ((rp->part->type == EDJE_PART_TYPE_GROUP || rp->part->type == EDJE_PART_TYPE_EXTERNAL) &&
+                     (rp->swallowed_object) &&
+                     (rp->part) && (rp->part->name) &&
+                     (strcmp(rp->part->name, part) == 0))
+                   {
+                     if (rp->part->type == EDJE_PART_TYPE_GROUP)
+                       {
+                          Edje *ed2 = _edje_fetch(rp->swallowed_object);
+                          if (ed2) _edje_emit(ed2, newsig, src);
+                          return; /* stop processing.
+                                   * XXX maybe let signal be processed anyway?
+                                   * XXX in this case, just comment this line
+                                   */
+                       }
+                     else if (rp->part->type == EDJE_PART_TYPE_EXTERNAL)
+                       {
+                          _edje_external_signal_emit(rp->swallowed_object, newsig, src);
+                          return;
+                       }
+                   }
+              }
+         }
+     }
+
+   emsg.sig = sig;
+   emsg.src = src;
+   _edje_message_send(ed, EDJE_QUEUE_SCRIPT, EDJE_MESSAGE_SIGNAL, 0, &emsg);
+   EINA_LIST_FOREACH(ed->subobjs, l, obj)
+     {
+        Edje *ed2;
+        
+        ed2 = _edje_fetch(obj);
+        if (!ed2) continue;
+        if (ed2->delete_me) continue;
+        _edje_message_send(ed2, EDJE_QUEUE_SCRIPT, EDJE_MESSAGE_SIGNAL, 0, &emsg);
+     }
+}
+
+struct _Edje_Program_Data
+{
+#ifdef EDJE_PROGRAM_CACHE
+  Eina_List     *matches;
+  int            matched;
+#endif
+  Edje          *ed;
+  const char    *signal;
+  const char    *source;
+};
+
+static Eina_Bool _edje_glob_callback(Edje_Program *pr, void *dt)
+{
+   struct _Edje_Program_Data *data = dt;
+   Edje_Real_Part *rp = NULL;
+   Eina_Bool exec = EINA_TRUE;
+
+#ifdef EDJE_PROGRAM_CACHE
+   data->matched++;
+#endif
+
+   if (pr->filter.state)
+     {
+       rp = _edje_real_part_get(data->ed, pr->filter.part ? pr->filter.part : data->source);
+       if (rp)
+         exec = (rp->chosen_description->state.name == pr->filter.state);
+     }
+
+   if (exec)
+     _edje_program_run(data->ed, pr, 0, data->signal, data->source);
+
+   if (_edje_block_break(data->ed))
+     {
+#ifdef EDJE_PROGRAM_CACHE
+        eina_list_free(data->matches);
+        data->matches = NULL;
+#endif
+        return EINA_TRUE;
+     }
+
+#ifdef EDJE_PROGRAM_CACHE
+   data->matches = eina_list_append(data->matches, pr);
+#endif
+
+   return EINA_FALSE;
+}
+
+
+void
+_edje_callbacks_patterns_clean(Edje *ed)
+{
+   _edje_signals_sources_patterns_clean(&ed->patterns.callbacks);
+
+   eina_rbtree_delete(ed->patterns.callbacks.exact_match,
+                     EINA_RBTREE_FREE_CB(edje_match_signal_source_free),
+                     NULL);
+   ed->patterns.callbacks.exact_match = NULL;
+
+   ed->patterns.callbacks.globing = eina_list_free(ed->patterns.callbacks.globing);
+}
+
+static void
+_edje_callbacks_patterns_init(Edje *ed)
+{
+   Edje_Signals_Sources_Patterns *ssp = &ed->patterns.callbacks;
+
+   if ((ssp->signals_patterns) || (ssp->sources_patterns) ||
+       (ssp->globing) || (ssp->exact_match))
+     return;
+
+   ssp->globing = edje_match_callback_hash_build(ed->callbacks,
+                                                &ssp->exact_match);
+
+   ssp->signals_patterns = edje_match_callback_signal_init(ssp->globing);
+   ssp->sources_patterns = edje_match_callback_source_init(ssp->globing);
+}
+
+/* FIXME: what if we delete the evas object??? */
+void
+_edje_emit_handle(Edje *ed, const char *sig, const char *src)
+{
+   if (ed->delete_me) return;
+   if (!sig) sig = "";
+   if (!src) src = "";
+//   printf("EDJE EMIT: signal: \"%s\" source: \"%s\"\n", sig, src);
+   _edje_block(ed);
+   _edje_ref(ed);
+   _edje_freeze(ed);
+   if (ed->collection)
+     {
+       Edje_Part_Collection *ec;
+#ifdef EDJE_PROGRAM_CACHE
+       char *tmps;
+       int l1, l2;
+#endif
+       int done;
+
+       ec = ed->collection;
+#ifdef EDJE_PROGRAM_CACHE
+       l1 = strlen(sig);
+       l2 = strlen(src);
+       tmps = alloca(l1 + l2 + 3); /* \0, \337, \0 */
+       strcpy(tmps, sig);
+       tmps[l1] = '\377';
+       strcpy(&(tmps[l1 + 1]), src);
+#endif
+       done = 0;
+
+#ifdef EDJE_PROGRAM_CACHE
+         {
+            Eina_List *matches;
+            Eina_List *l;
+            Edje_Program *pr;
+
+            if (eina_hash_find(ec->prog_cache.no_matches, tmps))
+              {
+                 done = 1;
+              }
+            else if ((matches = eina_hash_find(ec->prog_cache.matches, tmps)))
+              {
+                EINA_LIST_FOREACH(matches, l, pr)
+                   {
+                      _edje_program_run(ed, pr, 0, sig, src);
+                      if (_edje_block_break(ed))
+                        {
+                           goto break_prog;
+                        }
+                   }
+                 done = 1;
+              }
+         }
+#endif
+       if (!done)
+         {
+             struct _Edje_Program_Data  data;
+
+             data.ed = ed;
+             data.source = src;
+             data.signal = sig;
+#ifdef EDJE_PROGRAM_CACHE
+            data.matched = 0;
+            data.matches = NULL;
+#endif
+             if (ed->collection->programs)
+               {
+                 const Eina_List *match;
+                 const Eina_List *l;
+                 Edje_Program *pr;
+
+                 if (ed->patterns.programs.globing)
+                   if (edje_match_programs_exec(ed->patterns.programs.signals_patterns,
+                                                ed->patterns.programs.sources_patterns,
+                                                sig,
+                                                src,
+                                                ed->patterns.programs.globing,
+                                                _edje_glob_callback,
+                                                &data) == 0)
+                     goto break_prog;
+
+                 match = edje_match_signal_source_hash_get(sig, src,
+                                                           ed->patterns.programs.exact_match);
+                 EINA_LIST_FOREACH(match, l, pr)
+                   _edje_glob_callback(pr, &data);
+               }
+
+#ifdef EDJE_PROGRAM_CACHE
+            if (tmps)
+              {
+                 if (data.matched == 0)
+                   {
+                     if (!ec->prog_cache.no_matches)
+                       ec->prog_cache.no_matches = eina_hash_string_superfast_new(NULL);
+                     eina_hash_add(ec->prog_cache.no_matches, tmps, ed);
+                   }
+                 else
+                   {
+                     if (!ec->prog_cache.matches)
+                       ec->prog_cache.matches = eina_hash_string_superfast_new(NULL);
+                     eina_hash_add(ec->prog_cache.matches, tmps, data.matches);
+                   }
+              }
+#endif
+         }
+       _edje_emit_cb(ed, sig, src);
+       if (_edje_block_break(ed))
+         {
+            goto break_prog;
+         }
+     }
+   break_prog:
+   _edje_thaw(ed);
+   _edje_unref(ed);
+   _edje_unblock(ed);
+}
+
+/* FIXME: what if we delete the evas object??? */
+static void
+_edje_emit_cb(Edje *ed, const char *sig, const char *src)
+{
+   Eina_List            *l;
+
+   if (ed->delete_me) return;
+   _edje_ref(ed);
+   _edje_freeze(ed);
+   _edje_block(ed);
+
+   if (ed->just_added_callbacks)
+     _edje_callbacks_patterns_clean(ed);
+
+   ed->walking_callbacks = 1;
+
+   if (ed->callbacks)
+     {
+       Edje_Signal_Callback *escb;
+       const Eina_List *match;
+       const Eina_List *l;
+        int r = 1;
+
+       _edje_callbacks_patterns_init(ed);
+       if (ed->patterns.callbacks.globing)
+         r = edje_match_callback_exec(ed->patterns.callbacks.signals_patterns,
+                                      ed->patterns.callbacks.sources_patterns,
+                                      sig,
+                                      src,
+                                      ed->patterns.callbacks.globing,
+                                      ed);
+
+        if (!r)
+          goto break_prog;
+
+       match = edje_match_signal_source_hash_get(sig, src,
+                                                 ed->patterns.callbacks.exact_match);
+       EINA_LIST_FOREACH(match, l, escb)
+         if ((!escb->just_added) && (!escb->delete_me))
+           {
+              escb->func(escb->data, ed->obj, sig, src);
+              if (_edje_block_break(ed))
+                goto break_prog;
+           }
+     }
+   break_prog:
+
+   ed->walking_callbacks = 0;
+   if ((ed->delete_callbacks) || (ed->just_added_callbacks))
+     {
+       ed->delete_callbacks = 0;
+       ed->just_added_callbacks = 0;
+       l = ed->callbacks;
+       while (l)
+         {
+            Edje_Signal_Callback *escb = l->data;
+            Eina_List *next_l = l->next;
+
+            if (escb->just_added)
+              escb->just_added = 0;
+            if (escb->delete_me)
+              {
+                 ed->callbacks = eina_list_remove_list(ed->callbacks, l);
+                 if (escb->signal) eina_stringshare_del(escb->signal);
+                 if (escb->source) eina_stringshare_del(escb->source);
+                 free(escb);
+              }
+            l = next_l;
+         }
+
+        _edje_callbacks_patterns_clean(ed);
+     }
+   _edje_unblock(ed);
+   _edje_thaw(ed);
+   _edje_unref(ed);
+}
+
+static const Edje_External_Param_Info *
+_edje_external_param_info_get(const Evas_Object *obj, const char *name)
+{
+   const Edje_External_Type *type;
+   const Edje_External_Param_Info *info;
+
+   type = evas_object_data_get(obj, "Edje_External_Type");
+   if (!type) return NULL;
+   for (info = type->parameters_info; info->name != NULL; info++)
+     if (!strcmp(info->name, name)) return info;
+
+   return NULL;
+}
+
+static Edje_External_Param *
+_edje_param_external_get(const Evas_Object *obj, const char *name, Edje_External_Param *param)
+{
+   const Edje_External_Param_Info *info;
+
+   info = _edje_external_param_info_get(obj, name);
+   if (!info) return NULL;
+
+   memset(param, 0, sizeof(*param));
+   param->name = info->name;
+   param->type = info->type;
+   if (!_edje_external_param_get(obj, param)) return NULL;
+   return param;
+}
+
+/* simulate external properties for native objects */
+static Edje_External_Param *
+_edje_param_native_get(Edje_Real_Part *rp, const char *name, Edje_External_Param *param, void **free_ptr)
+{
+   *free_ptr = NULL;
+   if ((rp->part->type == EDJE_PART_TYPE_TEXT) ||
+       (rp->part->type == EDJE_PART_TYPE_TEXTBLOCK))
+     {
+       if (!strcmp(name, "text"))
+         {
+            param->name = name;
+            param->type = EDJE_EXTERNAL_PARAM_TYPE_STRING;
+
+            _edje_recalc_do(rp->edje);
+            if (rp->part->entry_mode > EDJE_ENTRY_EDIT_MODE_NONE)
+              param->s = _edje_entry_text_get(rp);
+            else if (rp->part->type == EDJE_PART_TYPE_TEXT)
+                   param->s = rp->text.text;
+            else
+              param->s = evas_object_textblock_text_markup_get(rp->object);
+            return param;
+         }
+       if (rp->part->type == EDJE_PART_TYPE_TEXTBLOCK)
+         {
+            if (!strcmp(name, "text_unescaped"))
+              {
+                 param->name = name;
+                 param->type = EDJE_EXTERNAL_PARAM_TYPE_STRING;
+
+                 _edje_recalc_do(rp->edje);
+                 if (rp->part->entry_mode > EDJE_ENTRY_EDIT_MODE_NONE)
+                   {
+                      const char *tmp = _edje_entry_text_get(rp);
+                      char *unescaped = _edje_text_unescape(tmp);
+                      *free_ptr = unescaped;
+                      param->s = unescaped;
+                   }
+                 else if (rp->part->type == EDJE_PART_TYPE_TEXT)
+                   param->s = rp->text.text;
+                 else
+                   {
+                      const char *tmp;
+                      char *unescaped;
+
+                      tmp = evas_object_textblock_text_markup_get(rp->object);
+                      unescaped = _edje_text_unescape(tmp);
+                      *free_ptr = unescaped;
+                      param->s = unescaped;
+                   }
+
+                 return param;
+              }
+
+            if ((rp->entry_data) &&
+                (rp->part->entry_mode > EDJE_ENTRY_EDIT_MODE_NONE) &&
+                (!strcmp(name, "select_allow")))
+              {
+                 param->name = name;
+                 param->type = EDJE_EXTERNAL_PARAM_TYPE_BOOL;
+                 param->i = _edje_entry_select_allow_get(rp);
+                 return param;
+              }
+         }
+     }
+
+   if ((rp->drag) && (rp->drag->down.count == 0))
+     {
+       if (!strncmp(name, "drag_", sizeof("drag_") - 1))
+         {
+            const char *sub_name = name + sizeof("drag_") - 1;
+            if (!strcmp(sub_name, "value_x"))
+              {
+                 double d;
+
+                 _edje_recalc_do(rp->edje);
+                 d = TO_DOUBLE(rp->drag->val.x);
+                 if (rp->part->dragable.x < 0) d = 1.0 - d;
+                 param->name = name;
+                 param->type = EDJE_EXTERNAL_PARAM_TYPE_DOUBLE;
+                 param->d = d;
+                 return param;
+              }
+            if (!strcmp(sub_name, "value_y"))
+              {
+                 double d;
+
+                 _edje_recalc_do(rp->edje);
+                 d = TO_DOUBLE(rp->drag->val.y);
+                 if (rp->part->dragable.y < 0) d = 1.0 - d;
+                 param->name = name;
+                 param->type = EDJE_EXTERNAL_PARAM_TYPE_DOUBLE;
+                 param->d = d;
+                 return param;
+              }
+
+            if (!strcmp(sub_name, "size_w"))
+              {
+                 _edje_recalc_do(rp->edje);
+                 param->name = name;
+                 param->type = EDJE_EXTERNAL_PARAM_TYPE_DOUBLE;
+                 param->d = TO_DOUBLE(rp->drag->size.x);
+                 return param;
+              }
+            if (!strcmp(sub_name, "size_h"))
+              {
+                 _edje_recalc_do(rp->edje);
+                 param->name = name;
+                 param->type = EDJE_EXTERNAL_PARAM_TYPE_DOUBLE;
+                 param->d = TO_DOUBLE(rp->drag->size.y);
+                 return param;
+              }
+
+            if (!strcmp(sub_name, "step_x"))
+              {
+                 _edje_recalc_do(rp->edje);
+                 param->name = name;
+                 param->type = EDJE_EXTERNAL_PARAM_TYPE_DOUBLE;
+                 param->d = TO_DOUBLE(rp->drag->step.x);
+                 return param;
+              }
+            if (!strcmp(sub_name, "step_y"))
+              {
+                 _edje_recalc_do(rp->edje);
+                 param->name = name;
+                 param->type = EDJE_EXTERNAL_PARAM_TYPE_DOUBLE;
+                 param->d = TO_DOUBLE(rp->drag->step.y);
+                 return param;
+              }
+
+            if (!strcmp(sub_name, "page_x"))
+              {
+                 _edje_recalc_do(rp->edje);
+                 param->name = name;
+                 param->type = EDJE_EXTERNAL_PARAM_TYPE_DOUBLE;
+                 param->d = TO_DOUBLE(rp->drag->page.x);
+                 return param;
+              }
+            if (!strcmp(sub_name, "page_y"))
+              {
+                 _edje_recalc_do(rp->edje);
+                 param->name = name;
+                 param->type = EDJE_EXTERNAL_PARAM_TYPE_DOUBLE;
+                 param->d = TO_DOUBLE(rp->drag->page.y);
+                 return param;
+              }
+
+            return NULL;
+         }
+     }
+
+   return NULL;
+}
+
+static Eina_Bool
+_edje_param_native_set(Edje_Real_Part *rp, const char *name, const Edje_External_Param *param)
+{
+   if ((rp->part->type == EDJE_PART_TYPE_TEXT) ||
+       (rp->part->type == EDJE_PART_TYPE_TEXTBLOCK))
+     {
+       if (!strcmp(name, "text"))
+         {
+            if (param->type != EDJE_EXTERNAL_PARAM_TYPE_STRING)
+              return EINA_FALSE;
+
+            _edje_object_part_text_raw_set
+              (rp->edje->obj, rp, rp->part->name, param->s);
+            return EINA_TRUE;
+         }
+       if (rp->part->type == EDJE_PART_TYPE_TEXTBLOCK)
+         {
+            if (!strcmp(name, "text_unescaped"))
+              {
+                 if (param->type != EDJE_EXTERNAL_PARAM_TYPE_STRING)
+                   return EINA_FALSE;
+
+                 if (rp->part->type == EDJE_PART_TYPE_TEXT)
+                   _edje_object_part_text_raw_set
+                     (rp->edje->obj, rp, rp->part->name, param->s);
+                 else
+                   {
+                      char *escaped = _edje_text_escape(param->s);
+                     _edje_object_part_text_raw_set
+                        (rp->edje->obj, rp, rp->part->name, escaped);
+                      free(escaped);
+                   }
+
+                 return EINA_TRUE;
+              }
+
+            if ((rp->entry_data) &&
+                (rp->part->entry_mode > EDJE_ENTRY_EDIT_MODE_NONE) &&
+                (!strcmp(name, "select_allow")))
+              {
+                 if (param->type != EDJE_EXTERNAL_PARAM_TYPE_BOOL)
+                   return EINA_FALSE;
+                 _edje_entry_select_allow_set(rp, param->i);
+                 return EINA_TRUE;
+              }
+         }
+     }
+
+   if ((rp->drag) && (rp->drag->down.count == 0))
+     {
+       if (!strncmp(name, "drag_", sizeof("drag_") - 1))
+         {
+            const char *sub_name = name + sizeof("drag_") - 1;
+            if (!strcmp(sub_name, "value_x"))
+              {
+                 double d;
+                 if (param->type != EDJE_EXTERNAL_PARAM_TYPE_DOUBLE)
+                   return EINA_FALSE;
+                 d = param->d;
+                 if (rp->part->dragable.confine_id != -1)
+                   d = CLAMP(d, 0.0, 1.0);
+                 if (rp->part->dragable.x < 0) d = 1.0 - d;
+                 if (rp->drag->val.x == FROM_DOUBLE(d)) return EINA_TRUE;
+                 rp->drag->val.x = FROM_DOUBLE(d);
+#ifdef EDJE_CALC_CACHE
+                 rp->invalidate = 1;
+#endif
+                 _edje_dragable_pos_set
+                   (rp->edje, rp, rp->drag->val.x, rp->drag->val.y);
+                 _edje_emit(rp->edje, "drag,set", rp->part->name);
+                 return EINA_TRUE;
+              }
+            if (!strcmp(sub_name, "value_y"))
+              {
+                 double d;
+                 if (param->type != EDJE_EXTERNAL_PARAM_TYPE_DOUBLE)
+                   return EINA_FALSE;
+                 d = param->d;
+                 if (rp->part->dragable.confine_id != -1)
+                   d = CLAMP(d, 0.0, 1.0);
+                 if (rp->part->dragable.y < 0) d = 1.0 - d;
+                 if (rp->drag->val.y == FROM_DOUBLE(d)) return EINA_TRUE;
+                 rp->drag->val.y = FROM_DOUBLE(d);
+#ifdef EDJE_CALC_CACHE
+                 rp->invalidate = 1;
+#endif
+                 _edje_dragable_pos_set
+                   (rp->edje, rp, rp->drag->val.x, rp->drag->val.y);
+                 _edje_emit(rp->edje, "drag,set", rp->part->name);
+                 return EINA_TRUE;
+              }
+
+            if (!strcmp(sub_name, "size_w"))
+              {
+                 if (param->type != EDJE_EXTERNAL_PARAM_TYPE_DOUBLE)
+                   return EINA_FALSE;
+                 rp->drag->size.x = FROM_DOUBLE(CLAMP(param->d, 0.0, 1.0));
+                 rp->edje->dirty = 1;
+#ifdef EDJE_CALC_CACHE
+                 rp->invalidate = 1;
+#endif
+                 _edje_recalc(rp->edje);
+                 return EINA_TRUE;
+              }
+            if (!strcmp(sub_name, "size_h"))
+              {
+                 if (param->type != EDJE_EXTERNAL_PARAM_TYPE_DOUBLE)
+                   return EINA_FALSE;
+                 rp->drag->size.y = FROM_DOUBLE(CLAMP(param->d, 0.0, 1.0));
+                 rp->edje->dirty = 1;
+#ifdef EDJE_CALC_CACHE
+                 rp->invalidate = 1;
+#endif
+                 _edje_recalc(rp->edje);
+                 return EINA_TRUE;
+              }
+
+            if (!strcmp(sub_name, "step_x"))
+              {
+                 if (param->type != EDJE_EXTERNAL_PARAM_TYPE_DOUBLE)
+                   return EINA_FALSE;
+                 rp->drag->step.x = FROM_DOUBLE(CLAMP(param->d, 0.0, 1.0));
+#ifdef EDJE_CALC_CACHE
+                 rp->invalidate = 1;
+#endif
+                 return EINA_TRUE;
+              }
+            if (!strcmp(sub_name, "step_y"))
+              {
+                 if (param->type != EDJE_EXTERNAL_PARAM_TYPE_DOUBLE)
+                   return EINA_FALSE;
+                 rp->drag->step.y = FROM_DOUBLE(CLAMP(param->d, 0.0, 1.0));
+#ifdef EDJE_CALC_CACHE
+                 rp->invalidate = 1;
+#endif
+                 return EINA_TRUE;
+              }
+
+            if (!strcmp(sub_name, "page_x"))
+              {
+                 if (param->type != EDJE_EXTERNAL_PARAM_TYPE_DOUBLE)
+                   return EINA_FALSE;
+                 rp->drag->page.x = FROM_DOUBLE(CLAMP(param->d, 0.0, 1.0));
+#ifdef EDJE_CALC_CACHE
+                 rp->invalidate = 1;
+#endif
+                 return EINA_TRUE;
+              }
+            if (!strcmp(sub_name, "page_y"))
+              {
+                 if (param->type != EDJE_EXTERNAL_PARAM_TYPE_DOUBLE)
+                   return EINA_FALSE;
+                 rp->drag->page.y = FROM_DOUBLE(CLAMP(param->d, 0.0, 1.0));
+#ifdef EDJE_CALC_CACHE
+                 rp->invalidate = 1;
+#endif
+                 return EINA_TRUE;
+              }
+
+            return EINA_FALSE;
+         }
+     }
+
+   return EINA_FALSE;
+}
+
+static const Edje_External_Param_Info *
+_edje_native_param_info_get(const Edje_Real_Part *rp, const char *name)
+{
+   if ((rp->part->type == EDJE_PART_TYPE_TEXT) ||
+       (rp->part->type == EDJE_PART_TYPE_TEXTBLOCK))
+     {
+       if (!strcmp(name, "text"))
+         {
+            static const Edje_External_Param_Info pi =
+              EDJE_EXTERNAL_PARAM_INFO_STRING("text");
+            return &pi;
+         }
+       if (rp->part->type == EDJE_PART_TYPE_TEXTBLOCK)
+         {
+            if (!strcmp(name, "text_unescaped"))
+              {
+                 static const Edje_External_Param_Info pi =
+                   EDJE_EXTERNAL_PARAM_INFO_STRING("text_unescaped");
+                 return &pi;
+              }
+            if (!strcmp(name, "select_allow"))
+              {
+                 static const Edje_External_Param_Info pi =
+                   EDJE_EXTERNAL_PARAM_INFO_BOOL("text_unescaped");
+                 return &pi;
+              }
+         }
+     }
+
+   if ((rp->drag) && (rp->drag->down.count == 0))
+     {
+       if (!strncmp(name, "drag_", sizeof("drag_") - 1))
+         {
+            name += sizeof("drag_") - 1;
+            if (!strcmp(name, "value_x"))
+              {
+                 static const Edje_External_Param_Info pi =
+                   EDJE_EXTERNAL_PARAM_INFO_DOUBLE("drag_value_x");
+                 return &pi;
+              }
+            if (!strcmp(name, "value_y"))
+              {
+                 static const Edje_External_Param_Info pi =
+                   EDJE_EXTERNAL_PARAM_INFO_DOUBLE("drag_value_y");
+                 return &pi;
+              }
+            if (!strcmp(name, "size_w"))
+              {
+                 static const Edje_External_Param_Info pi =
+                   EDJE_EXTERNAL_PARAM_INFO_DOUBLE("drag_size_w");
+                 return &pi;
+              }
+            if (!strcmp(name, "size_h"))
+              {
+                 static const Edje_External_Param_Info pi =
+                   EDJE_EXTERNAL_PARAM_INFO_DOUBLE("drag_size_h");
+                 return &pi;
+              }
+            if (!strcmp(name, "step_x"))
+              {
+                 static const Edje_External_Param_Info pi =
+                   EDJE_EXTERNAL_PARAM_INFO_DOUBLE("drag_step_x");
+                 return &pi;
+              }
+            if (!strcmp(name, "step_y"))
+              {
+                 static const Edje_External_Param_Info pi =
+                   EDJE_EXTERNAL_PARAM_INFO_DOUBLE("drag_step_y");
+                 return &pi;
+              }
+            if (!strcmp(name, "page_x"))
+              {
+                 static const Edje_External_Param_Info pi =
+                   EDJE_EXTERNAL_PARAM_INFO_DOUBLE("drag_page_x");
+                 return &pi;
+              }
+            if (!strcmp(name, "page_y"))
+              {
+                 static const Edje_External_Param_Info pi =
+                   EDJE_EXTERNAL_PARAM_INFO_DOUBLE("drag_page_y");
+                 return &pi;
+              }
+
+            return NULL;
+         }
+     }
+
+   return NULL;
+}
+
+static Edje_External_Param *
+_edje_param_convert(Edje_External_Param *param, const Edje_External_Param_Info *dst_info)
+{
+   if (param->type == dst_info->type) return param;
+
+   switch (dst_info->type)
+     {
+      case EDJE_EXTERNAL_PARAM_TYPE_BOOL:
+      case EDJE_EXTERNAL_PARAM_TYPE_INT:
+       {
+          int i;
+          switch (param->type)
+            {
+             case EDJE_EXTERNAL_PARAM_TYPE_DOUBLE:
+                i = (int)param->d;
+                break;
+             case EDJE_EXTERNAL_PARAM_TYPE_STRING:
+             case EDJE_EXTERNAL_PARAM_TYPE_CHOICE:
+                i = (param->s) ? atoi(param->s) : 0;
+                break;
+             case EDJE_EXTERNAL_PARAM_TYPE_BOOL:
+             case EDJE_EXTERNAL_PARAM_TYPE_INT:
+                i = param->i;
+             default:
+                return NULL;
+            }
+          if (dst_info->type == EDJE_EXTERNAL_PARAM_TYPE_BOOL)
+            i = !!i;
+          param->type = dst_info->type;
+          param->i = i;
+          return param;
+       }
+
+      case EDJE_EXTERNAL_PARAM_TYPE_DOUBLE:
+       {
+          double d;
+          switch (param->type)
+            {
+             case EDJE_EXTERNAL_PARAM_TYPE_INT:
+                d = (double)param->i;
+                break;
+             case EDJE_EXTERNAL_PARAM_TYPE_STRING:
+             case EDJE_EXTERNAL_PARAM_TYPE_CHOICE:
+                d = (param->s) ? atof(param->s) : 0.0;
+                break;
+             case EDJE_EXTERNAL_PARAM_TYPE_BOOL:
+                d = (double)param->i;
+             default:
+                return NULL;
+            }
+          param->type = dst_info->type;
+          param->d = d;
+          return param;
+       }
+
+      case EDJE_EXTERNAL_PARAM_TYPE_STRING:
+       {
+          static char s[64];
+          switch (param->type)
+            {
+             case EDJE_EXTERNAL_PARAM_TYPE_BOOL:
+             case EDJE_EXTERNAL_PARAM_TYPE_INT:
+                if (!snprintf(s, sizeof(s), "%i", param->i)) return NULL;
+                break;
+             case EDJE_EXTERNAL_PARAM_TYPE_DOUBLE:
+                if (!snprintf(s, sizeof(s), "%f", param->d)) return NULL;
+                break;
+             case EDJE_EXTERNAL_PARAM_TYPE_CHOICE:
+                param->type = dst_info->type;
+                return param;
+             default:
+                return NULL;
+            }
+          param->type = dst_info->type;
+          param->s = s;
+          return param;
+       }
+
+      case EDJE_EXTERNAL_PARAM_TYPE_CHOICE:
+       {
+          static char s[64];
+          const char *val;
+          switch (param->type)
+            {
+             case EDJE_EXTERNAL_PARAM_TYPE_BOOL:
+             case EDJE_EXTERNAL_PARAM_TYPE_INT:
+                if (!snprintf(s, sizeof(s), "%i", param->i)) return NULL;
+                val = s;
+                break;
+             case EDJE_EXTERNAL_PARAM_TYPE_DOUBLE:
+                if (!snprintf(s, sizeof(s), "%f", param->d)) return NULL;
+                val = s;
+                break;
+             case EDJE_EXTERNAL_PARAM_TYPE_STRING:
+                val = param->s;
+                break;
+             default:
+                return NULL;
+            }
+
+          param->type = dst_info->type;
+          if (param->s != val) param->s = val;
+          return param;
+       }
+
+      default: return NULL;
+     }
+}
+
+static Eina_Bool
+_edje_param_validate(const Edje_External_Param *param, const Edje_External_Param_Info *info)
+{
+   switch (info->type)
+     {
+      case EDJE_EXTERNAL_PARAM_TYPE_BOOL:
+        return ((param->i == 0) || (param->i == 1));
+
+      case EDJE_EXTERNAL_PARAM_TYPE_INT:
+        if ((info->info.i.min != EDJE_EXTERNAL_INT_UNSET) &&
+            (info->info.i.min > param->i))
+          return EINA_FALSE;
+
+        if ((info->info.i.max != EDJE_EXTERNAL_INT_UNSET) &&
+            (info->info.i.max < param->i))
+          return EINA_FALSE;
+
+        return EINA_TRUE;
+
+      case EDJE_EXTERNAL_PARAM_TYPE_DOUBLE:
+        if ((info->info.d.min != EDJE_EXTERNAL_DOUBLE_UNSET) &&
+            (info->info.d.min > param->d))
+          return EINA_FALSE;
+
+        if ((info->info.d.max != EDJE_EXTERNAL_DOUBLE_UNSET) &&
+            (info->info.d.max < param->d))
+          return EINA_FALSE;
+
+        return EINA_TRUE;
+
+      case EDJE_EXTERNAL_PARAM_TYPE_STRING:
+        if (!param->s) return EINA_FALSE;
+        if (info->info.s.accept_fmt)
+          INF("string 'accept_fmt' validation not implemented.");
+        if (info->info.s.deny_fmt)
+          INF("string 'deny_fmt' validation not implemented.");
+        return EINA_TRUE;
+
+      case EDJE_EXTERNAL_PARAM_TYPE_CHOICE:
+       {
+          const char **itr = info->info.c.choices;
+          if (!itr) return EINA_FALSE;
+          for (; *itr != NULL; itr++)
+            if (!strcmp(*itr, param->s))
+              return EINA_TRUE;
+          return EINA_FALSE;
+       }
+
+      default: return EINA_FALSE;
+     }
+}
+
+static void
+_edje_param_copy(Edje_Real_Part *src_part, const char *src_param, Edje_Real_Part *dst_part, const char *dst_param)
+{
+   Edje_External_Param val;
+   const Edje_External_Param_Info *dst_info;
+   void *free_ptr = NULL;
+
+   if ((!src_part) || (!src_param) || (!dst_part) || (!dst_param))
+     return;
+
+   if (dst_part->part->type == EDJE_PART_TYPE_EXTERNAL)
+     dst_info = _edje_external_param_info_get
+       (dst_part->swallowed_object, dst_param);
+   else
+     dst_info = _edje_native_param_info_get(dst_part, dst_param);
+
+   if (!dst_info)
+     {
+       ERR("cannot copy, invalid destination parameter '%s' of part '%s'",
+           dst_param, dst_part->part->name);
+       return;
+     }
+
+   if (src_part->part->type == EDJE_PART_TYPE_EXTERNAL)
+     {
+       if (!_edje_param_external_get
+           (src_part->swallowed_object, src_param, &val))
+         {
+            ERR("cannot get parameter '%s' of part '%s'",
+                src_param, src_part->part->name);
+            return;
+         }
+     }
+   else
+     {
+       if (!_edje_param_native_get(src_part, src_param, &val, &free_ptr))
+         {
+            ERR("cannot get parameter '%s' of part '%s'",
+                src_param, src_part->part->name);
+            return;
+         }
+     }
+
+   if (!_edje_param_convert(&val, dst_info))
+     {
+       ERR("cannot convert parameter type %s to requested type %s",
+           edje_external_param_type_str(val.type),
+           edje_external_param_type_str(dst_info->type));
+       goto end;
+     }
+
+   if (!_edje_param_validate(&val, dst_info))
+     {
+       ERR("incorrect parameter value failed validation for type %s",
+           edje_external_param_type_str(dst_info->type));
+       goto end;
+     }
+
+   if (dst_part->part->type == EDJE_PART_TYPE_EXTERNAL)
+     {
+       val.name = dst_param;
+       if (!_edje_external_param_set(dst_part->swallowed_object, &val))
+         {
+            ERR("failed to set parameter '%s' (%s) of part '%s'",
+                dst_param, edje_external_param_type_str(dst_info->type),
+                dst_part->part->name);
+            goto end;
+         }
+     }
+   else
+     {
+       if (!_edje_param_native_set(dst_part, dst_param, &val))
+         {
+            ERR("failed to set parameter '%s' (%s) of part '%s'",
+                dst_param, edje_external_param_type_str(dst_info->type),
+                dst_part->part->name);
+            goto end;
+         }
+     }
+
+ end:
+   free(free_ptr);
+}
+
+static void
+_edje_param_set(Edje_Real_Part *part, const char *param, const char *value)
+{
+   Edje_External_Param val;
+   const Edje_External_Param_Info *info;
+
+   if ((!part) || (!param) || (!value))
+     return;
+
+   if (part->part->type == EDJE_PART_TYPE_EXTERNAL)
+     info = _edje_external_param_info_get(part->swallowed_object, param);
+   else
+     info = _edje_native_param_info_get(part, param);
+
+   if (!info)
+     {
+       ERR("cannot copy, invalid destination parameter '%s' of part '%s'",
+           param, part->part->name);
+       return;
+     }
+
+   val.name = "(temp)";
+   val.type = EDJE_EXTERNAL_PARAM_TYPE_STRING;
+   val.s = value;
+
+   if (!_edje_param_convert(&val, info))
+     {
+       ERR("cannot convert parameter type STRING to requested type %s",
+           edje_external_param_type_str(info->type));
+       return;
+     }
+
+   if (!_edje_param_validate(&val, info))
+     {
+       ERR("incorrect parameter value failed validation for type %s",
+           edje_external_param_type_str(info->type));
+       return;
+     }
+
+   if (part->part->type == EDJE_PART_TYPE_EXTERNAL)
+     {
+       val.name = param;
+       if (!_edje_external_param_set(part->swallowed_object, &val))
+         {
+            ERR("failed to set parameter '%s' (%s) of part '%s'",
+                param, edje_external_param_type_str(info->type),
+                part->part->name);
+            return;
+         }
+     }
+   else
+     {
+       if (!_edje_param_native_set(part, param, &val))
+         {
+            ERR("failed to set parameter '%s' (%s) of part '%s'",
+                param, edje_external_param_type_str(info->type),
+                part->part->name);
+            return;
+         }
+     }
+}
+
+/**
+ *
+ * @}
+ */
diff --git a/src/lib/edje_script_only.c b/src/lib/edje_script_only.c
new file mode 100644 (file)
index 0000000..7763ea8
--- /dev/null
@@ -0,0 +1,660 @@
+/*
+ * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef HAVE_ALLOCA_H
+# include <alloca.h>
+#elif defined __GNUC__
+# define alloca __builtin_alloca
+#elif defined _AIX
+# define alloca __alloca
+#elif defined _MSC_VER
+# include <malloc.h>
+# define alloca _alloca
+#else
+# include <stddef.h>
+# ifdef  __cplusplus
+extern "C"
+# endif
+void *alloca(size_t);
+#endif
+
+#include "edje_private.h"
+
+/*
+ * ALREADY EXPORTED BY EMBRYO:
+ *
+ * enum Float_Round_Method {
+ *    ROUND, FLOOR, CEIL, TOZERO
+ * };
+ * enum Float_Angle_Mode {
+ *    RADIAN, DEGREES, GRADES
+ * };
+ *
+ * numargs();
+ * getarg(arg, index=0);
+ * setarg(arg, index=0, value);
+ *
+ * Float:atof(string[]);
+ * Float:fract(Float:value);
+ *       round(Float:value, Float_Round_Method:method=ROUND);
+ * Float:sqrt(Float:value);
+ * Float:pow(Float:value, Float:exponent);
+ * Float:log(Float:value, Float:base=10.0);
+ * Float:sin(Float:value, Float_Angle_Mode:mode=RADIAN);
+ * Float:cos(Float:value, Float_Angle_Mode:mode=RADIAN);
+ * Float:tan(Float:value, Float_Angle_Mode:mode=RADIAN);
+ * Float:abs(Float:value);
+ *       atoi(str[]);
+ *       fnmatch(glob[], str[]);
+ *       strcmp(str1[], str2[]);
+ *       strncmp(str1[], str2[]);
+ *       strcpy(dst[], src[]);
+ *       strncpy(dst[], src[], n);
+ *       strlen(str[]);
+ *       strcat(dst[], src[]);
+ *       strncat(dst[], src[], n);
+ *       strprep(dst[], src[]);
+ *       strnprep(dst[], src[], n);
+ *       strcut(dst[], str[], n, n2);
+ *       snprintf(dst[], dstn, fmt[], ...);
+ *       strstr(str[], ndl[]);
+ *       strchr(str[], ch[]);
+ *       strrchr(str[], ch[]);
+ *       rand();
+ * Float:randf();
+ * Float:seconds();
+ *       date(&year, &month, &day, &yearday, &weekday, &hr, &min, &Float:sec);
+ *
+ */
+
+typedef struct _Sinfo Sinfo;
+
+struct _Sinfo
+{
+   struct
+   {
+      Embryo_Function
+        obj_init, obj_shutdown, obj_show, obj_show_immediate,
+        obj_hide, obj_hide_immediate, obj_move, obj_move_immediate,
+        obj_resize, obj_resize_immediate, obj_message;
+   } fn;
+   struct
+   {
+      Ecore_Job * show, *hide, *move, *resize;
+   } job;
+   struct
+   {
+      int id;
+      Eina_Hash *hash;         // FIXME: hash -> bad. too big. one-way lookup etc.
+   } oid;
+};
+
+static void _call_fn(Edje * ed, const char *fname, Embryo_Function fn);
+
+/* frankly - these make the code shorter to type and read - just sanity for
+ * development */
+#define IFFN(func) if (si->fn.func != EMBRYO_FUNCTION_NONE)
+#define IFNO(func) if (si->fn.func == EMBRYO_FUNCTION_NONE)
+#define CLFN(func) IFFN(func) {_call_fn(ed, #func, si->fn.func);}
+#define SI Sinfo *si; si = ed->script_only_data; if (!si) return
+#define SI_RETURN(ret) Sinfo *si; si = ed->script_only_data; if (!si) return (ret)
+#define PINT(val) embryo_parameter_cell_push(ed->collection->script, (Embryo_Cell)(val))
+#define PSTR(val) embryo_parameter_string_push(ed->collection->script, val)
+#define GTFN(func) si->fn.func = embryo_program_function_find(ed->collection->script, #func)
+#define DELJ(type) if (si->job.type) ecore_job_del(si->job.type);
+#define ADDJ(type, func) si->job.type = ecore_job_add(func, ed);
+#define ZERJ(type) si->job.type = NULL;
+#define IFNJ(type) if (!si->job.type)
+#define EXPF(func) embryo_program_native_call_add(ed->collection->script, #func, _exp_##func)
+
+typedef struct _Oid Oid;
+
+struct _Oid
+{
+   Edje *ed;
+   Evas_Object *obj;
+   Evas_Coord x, y, w, h;
+   int oid;
+};
+
+/* FIXME: using eina_hash and strings is just nasty! make a custom int hash */
+static int
+_oid_alloc(Edje * ed)
+{
+   SI_RETURN(0);
+
+   si->oid.id++;
+   return si->oid.id;
+}
+
+static Oid *
+_oid_track(Edje * ed, Evas_Object * o)
+{
+   Oid *oi;
+
+   char buf[64];
+
+   SI_RETURN(NULL);
+
+   oi = calloc(1, sizeof(Oid));
+   if (!oi)
+      return NULL;
+   oi->oid = _oid_alloc(ed);
+   if (!oi->oid)
+     {
+       free(oi);
+       return NULL;
+     }
+   oi->ed = ed;
+   oi->obj = o;
+   evas_object_smart_member_add(oi->obj, oi->ed->obj);
+   evas_object_clip_set(oi->obj, oi->ed->clipper);
+   evas_object_geometry_get(oi->obj, &(oi->x), &(oi->y), &(oi->w), &(oi->h));
+   snprintf(buf, sizeof(buf), "%i", oi->oid);
+   if (!si->oid.hash)
+      si->oid.hash = eina_hash_string_superfast_new(NULL);
+   eina_hash_add(si->oid.hash, buf, oi);
+   return oi;
+}
+
+static Oid *
+_oid_find(Edje * ed, int oid)
+{
+   char buf[64];
+
+   SI_RETURN(NULL);
+
+   snprintf(buf, sizeof(buf), "%i", oid);
+   return eina_hash_find(si->oid.hash, buf);
+}
+
+static void
+_oid_del(Edje * ed, int oid)
+{
+   char buf[64];
+
+   SI;
+
+   snprintf(buf, sizeof(buf), "%i", oid);
+   eina_hash_del(si->oid.hash, buf, NULL);
+}
+
+static void
+_oid_free(Oid * oid)
+{
+   free(oid);
+}
+
+static Eina_Bool
+_oid_freeall_cb(const Eina_Hash *hash __UNUSED__, const void *key __UNUSED__, void *data, void *fdata __UNUSED__)
+{
+   Oid *oid = data;
+
+   evas_object_del(oid->obj);
+   free(oid);
+   return 1;
+}
+
+static void
+_oid_freeall(Edje * ed)
+{
+   SI;
+   if (!si->oid.hash)
+      return;
+   eina_hash_foreach(si->oid.hash, _oid_freeall_cb, ed);
+   eina_hash_free(si->oid.hash);
+   si->oid.hash = NULL;
+}
+
+static Eina_Bool
+_oid_moveall_cb(const Eina_Hash *hash __UNUSED__, const void *key __UNUSED__, void *data, void *fdata __UNUSED__)
+{
+   Oid *oid = data;
+
+   evas_object_move(oid->obj, oid->ed->x + oid->x, oid->ed->y + oid->y);
+   return 1;
+}
+
+static void
+_oid_moveall(Edje * ed)
+{
+   SI;
+   if (!si->oid.hash)
+      return;
+   eina_hash_foreach(si->oid.hash, _oid_moveall_cb, ed);
+}
+
+/**********/
+
+static Embryo_Cell
+_exp_e_obj_del(Embryo_Program * ep, Embryo_Cell * params)
+{
+   Edje *ed = embryo_program_data_get(ep);
+
+   Oid *oid;
+
+   SI_RETURN(-1);
+
+   CHKPARAM(1);
+   if (!(oid = _oid_find(ed, params[1])))
+      return -1;
+   evas_object_del(oid->obj);
+   _oid_del(ed, oid->oid);
+   _oid_free(oid);
+   return 0;
+}
+
+static Embryo_Cell
+_exp_e_obj_rect_add(Embryo_Program * ep, Embryo_Cell * params __UNUSED__)
+{
+   Edje *ed = embryo_program_data_get(ep);
+
+   Evas_Object *o;
+
+   Oid *oid;
+
+   SI_RETURN(-1);
+
+   o = evas_object_rectangle_add(evas_object_evas_get(ed->obj));
+   if (!o)
+      return 0;
+   oid = _oid_track(ed, o);
+   if (oid)
+      return oid->oid;
+   return 0;
+}
+
+static Embryo_Cell
+_exp_e_obj_show(Embryo_Program * ep, Embryo_Cell * params)
+{
+   Edje *ed = embryo_program_data_get(ep);
+
+   Oid *oid;
+
+   SI_RETURN(-1);
+
+   CHKPARAM(1);
+   if (!(oid = _oid_find(ed, params[1])))
+      return -1;
+   evas_object_show(oid->obj);
+   return 0;
+}
+
+static Embryo_Cell
+_exp_e_obj_hide(Embryo_Program * ep, Embryo_Cell * params)
+{
+   Edje *ed = embryo_program_data_get(ep);
+
+   Oid *oid;
+
+   SI_RETURN(-1);
+
+   CHKPARAM(1);
+   if (!(oid = _oid_find(ed, params[1])))
+      return -1;
+   evas_object_hide(oid->obj);
+   return 0;
+}
+
+static Embryo_Cell
+_exp_e_obj_move(Embryo_Program * ep, Embryo_Cell * params)
+{
+   Edje *ed = embryo_program_data_get(ep);
+
+   Oid *oid;
+
+   SI_RETURN(-1);
+
+   CHKPARAM(3);
+   if (!(oid = _oid_find(ed, params[1])))
+      return -1;
+   if ((oid->x == params[2]) && (oid->y == params[3]))
+      return -1;
+   oid->x = params[2];
+   oid->y = params[3];
+   evas_object_move(oid->obj, ed->x + oid->x, ed->y + oid->y);
+   return 0;
+}
+
+static Embryo_Cell
+_exp_e_obj_resize(Embryo_Program * ep, Embryo_Cell * params)
+{
+   Edje *ed = embryo_program_data_get(ep);
+
+   Oid *oid;
+
+   SI_RETURN(-1);
+
+   CHKPARAM(3);
+   if (!(oid = _oid_find(ed, params[1])))
+      return -1;
+   if ((oid->w == params[2]) && (oid->h == params[3]))
+      return -1;
+   oid->w = params[2];
+   oid->h = params[3];
+   evas_object_resize(oid->obj, oid->w, oid->h);
+   return 0;
+}
+
+static Embryo_Cell
+_exp_e_obj_geometry_set(Embryo_Program * ep, Embryo_Cell * params)
+{
+   Edje *ed = embryo_program_data_get(ep);
+
+   Oid *oid;
+
+   SI_RETURN(-1);
+
+   CHKPARAM(5);
+   if (!(oid = _oid_find(ed, params[1])))
+      return -1;
+   if ((oid->x == params[2]) && (oid->y == params[3]) &&
+       (oid->w == params[4]) && (oid->h == params[5]))
+      return -1;
+   oid->x = params[2];
+   oid->y = params[3];
+   oid->w = params[4];
+   oid->h = params[5];
+   evas_object_move(oid->obj, ed->x + oid->x, ed->y + oid->y);
+   evas_object_resize(oid->obj, oid->w, oid->h);
+   return 0;
+}
+
+static Embryo_Cell
+_exp_e_obj_geometry_get(Embryo_Program * ep, Embryo_Cell * params)
+{
+   Edje *ed = embryo_program_data_get(ep);
+
+   Oid *oid;
+
+   SI_RETURN(-1);
+
+   CHKPARAM(5);
+   if (!(oid = _oid_find(ed, params[1])))
+      return -1;
+   SETINT(oid->x, params[2]);
+   SETINT(oid->y, params[3]);
+   SETINT(oid->w, params[4]);
+   SETINT(oid->h, params[5]);
+   return 0;
+}
+
+static Embryo_Cell
+_exp_e_obj_color_set(Embryo_Program * ep, Embryo_Cell * params)
+{
+   Edje *ed = embryo_program_data_get(ep);
+
+   Oid *oid;
+
+   SI_RETURN(-1);
+
+   CHKPARAM(5);
+   if (!(oid = _oid_find(ed, params[1])))
+      return -1;
+   evas_object_color_set(oid->obj, params[2], params[3], params[4], params[5]);
+   return 0;
+}
+
+static Embryo_Cell
+_exp_e_obj_color_get(Embryo_Program * ep, Embryo_Cell * params)
+{
+   Edje *ed = embryo_program_data_get(ep);
+
+   Oid *oid;
+
+   int r, g, b, a;
+
+   SI_RETURN(-1);
+
+   CHKPARAM(5);
+   if (!(oid = _oid_find(ed, params[1])))
+      return -1;
+   evas_object_color_get(oid->obj, &r, &g, &b, &a);
+   SETINT(r, params[2]);
+   SETINT(g, params[3]);
+   SETINT(b, params[4]);
+   SETINT(a, params[5]);
+   return 0;
+}
+
+static Embryo_Cell
+_exp_e_signal_emit(Embryo_Program * ep, Embryo_Cell * params)
+{
+   Edje *ed = embryo_program_data_get(ep);
+
+   char *sig = NULL, *src = NULL;
+
+   SI_RETURN(-1);
+
+   CHKPARAM(2);
+   GETSTR(sig, params[1]);
+   GETSTR(src, params[2]);
+   if ((!sig) || (!src))
+      return -1;
+   _edje_emit(ed, sig, src);
+   return 0;
+}
+
+/**********/
+
+Eina_Bool
+_edje_script_only(Edje * ed)
+{
+   if ((ed->collection) && (ed->collection->script) &&
+       (ed->collection->script_only))
+      return EINA_TRUE;
+   return EINA_FALSE;
+}
+
+void
+_edje_script_only_init(Edje * ed)
+{
+   Sinfo *si;
+
+   si = calloc(1, sizeof(Sinfo));
+   if (!si)
+      return;
+   ed->script_only_data = si;
+
+   embryo_program_data_set(ed->collection->script, ed);
+
+   EXPF(e_obj_del);
+   EXPF(e_obj_rect_add);
+   EXPF(e_obj_show);
+   EXPF(e_obj_hide);
+   EXPF(e_obj_move);
+   EXPF(e_obj_resize);
+   EXPF(e_obj_geometry_set);
+   EXPF(e_obj_geometry_get);
+   EXPF(e_obj_color_set);
+   EXPF(e_obj_color_get);
+   EXPF(e_signal_emit);
+
+   embryo_program_vm_push(ed->collection->script);
+   embryo_program_max_cycle_run_set(ed->collection->script, 5000000);
+
+   GTFN(obj_init);
+   GTFN(obj_shutdown);
+   GTFN(obj_show);
+   GTFN(obj_show_immediate);
+   GTFN(obj_hide);
+   GTFN(obj_hide_immediate);
+   GTFN(obj_move);
+   GTFN(obj_move_immediate);
+   GTFN(obj_resize);
+   GTFN(obj_resize_immediate);
+   GTFN(obj_message);
+
+   CLFN(obj_init);
+   _edje_script_only_move(ed);
+}
+
+void
+_edje_script_only_shutdown(Edje * ed)
+{
+   SI;
+
+   CLFN(obj_shutdown);
+   DELJ(show);
+   DELJ(hide);
+   DELJ(move);
+   DELJ(resize);
+   _oid_freeall(ed);
+}
+
+static void
+_show_job(void *data)
+{
+   Edje *ed = data;
+
+   SI;
+
+   ZERJ(show);
+   CLFN(obj_show);
+}
+void
+_edje_script_only_show(Edje * ed)
+{
+   SI;
+
+   IFFN(obj_show)
+   {
+      IFNJ(hide)
+      {
+        DELJ(show);
+        ADDJ(show, _show_job);
+      }
+      else
+      {
+        DELJ(hide);
+      }
+   }
+   IFNO(obj_show_immediate) return;
+   CLFN(obj_show_immediate);
+}
+
+static void
+_hide_job(void *data)
+{
+   Edje *ed = data;
+
+   SI;
+
+   ZERJ(hide);
+   CLFN(obj_hide);
+}
+void
+_edje_script_only_hide(Edje * ed)
+{
+   SI;
+
+   IFFN(obj_hide)
+   {
+      IFNJ(show)
+      {
+        DELJ(hide);
+        ADDJ(hide, _hide_job);
+      }
+      else
+      {
+        DELJ(show);
+      }
+   }
+   IFNO(obj_hide_immediate) return;
+   CLFN(obj_hide_immediate);
+}
+
+static void
+_move_job(void *data)
+{
+   Edje *ed = data;
+
+   SI;
+
+   _oid_moveall(ed);
+   ZERJ(move);
+   IFNO(obj_move) return;
+   PINT(ed->x);
+   PINT(ed->y);
+   CLFN(obj_move);
+}
+void
+_edje_script_only_move(Edje * ed)
+{
+   SI;
+
+   DELJ(move);
+   ADDJ(move, _move_job);
+   IFNO(obj_move_immediate) return;
+   PINT(ed->x);
+   PINT(ed->y);
+   CLFN(obj_move_immediate);
+}
+
+static void
+_resize_job(void *data)
+{
+   Edje *ed = data;
+
+   SI;
+
+   ZERJ(resize);
+   PINT(ed->w);
+   PINT(ed->h);
+   CLFN(obj_resize);
+}
+void
+_edje_script_only_resize(Edje * ed)
+{
+   SI;
+
+   IFFN(obj_resize)
+   {
+      DELJ(resize);
+      ADDJ(resize, _resize_job);
+   }
+   PINT(ed->w);
+   PINT(ed->h);
+   CLFN(obj_resize_immediate);
+}
+
+void
+_edje_script_only_message(Edje * ed, Edje_Message * em)
+{
+   SI;
+
+   IFNO(obj_message) return;
+   _edje_message_parameters_push(em);
+   CLFN(obj_message);
+}
+
+/**************************************************/
+
+static void
+_call_fn(Edje * ed, const char *fname, Embryo_Function fn)
+{
+   int ret;
+
+   ret = embryo_program_run(ed->collection->script, fn);
+   if (ret == EMBRYO_PROGRAM_FAIL)
+     {
+       ERR("ERROR with embryo script.\n"
+           "ENTRY POINT: %s\n"
+           "ERROR:       %s",
+              fname,
+              embryo_error_string_get(embryo_program_error_get
+                                      (ed->collection->script)));
+     }
+   else if (ret == EMBRYO_PROGRAM_TOOLONG)
+     {
+       ERR("ERROR with embryo script.\n"
+           "ENTRY POINT: %s\n"
+           "ERROR:       Script exceeded maximum allowed cycle count of %i",
+           fname, embryo_program_max_cycle_run_get(ed->collection->script));
+     }
+}
diff --git a/src/lib/edje_smart.c b/src/lib/edje_smart.c
new file mode 100644 (file)
index 0000000..ba6f1b8
--- /dev/null
@@ -0,0 +1,325 @@
+/*
+ * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
+ */
+
+#include "edje_private.h"
+
+static void _edje_smart_add(Evas_Object * obj);
+static void _edje_smart_del(Evas_Object * obj);
+static void _edje_smart_move(Evas_Object * obj, Evas_Coord x, Evas_Coord y);
+static void _edje_smart_resize(Evas_Object * obj, Evas_Coord w, Evas_Coord h);
+static void _edje_smart_show(Evas_Object * obj);
+static void _edje_smart_hide(Evas_Object * obj);
+static void _edje_smart_color_set(Evas_Object * obj, int r, int g, int b, int a);
+static void _edje_smart_clip_set(Evas_Object * obj, Evas_Object * clip);
+static void _edje_smart_clip_unset(Evas_Object * obj);
+static void _edje_smart_calculate(Evas_Object * obj);
+
+static Eina_Bool _edje_smart_file_set(Evas_Object *obj, const char *file, const char *group);
+
+static Edje_Smart_Api _edje_smart_class = EDJE_SMART_API_INIT_NAME_VERSION("edje");
+static Evas_Smart *_edje_smart = NULL;
+
+Eina_List *_edje_edjes = NULL;
+
+/************************** API Routines **************************/
+
+/* FIXDOC: Verify/Expand */
+/** Constructs the Edje object
+ * @param evas A valid Evas handle
+ * @return The Evas_Object pointer.
+ *
+ * Creates the Edje smart object, returning the Evas_Object handle.
+ */
+EAPI Evas_Object *
+edje_object_add(Evas *evas)
+{
+   if (!_edje_smart)
+     {
+       _edje_object_smart_set(&_edje_smart_class);
+       _edje_smart = evas_smart_class_new((Evas_Smart_Class *)&_edje_smart_class);
+     }
+   return evas_object_smart_add(evas, _edje_smart);
+}
+
+void
+_edje_object_smart_set(Edje_Smart_Api *sc)
+{
+   if (!sc)
+     return;
+
+   sc->base.add = _edje_smart_add;
+   sc->base.del = _edje_smart_del;
+   sc->base.move = _edje_smart_move;
+   sc->base.resize = _edje_smart_resize;
+   sc->base.show = _edje_smart_show;
+   sc->base.hide = _edje_smart_hide;
+   sc->base.color_set = _edje_smart_color_set;
+   sc->base.clip_set = _edje_smart_clip_set;
+   sc->base.clip_unset = _edje_smart_clip_unset;
+   sc->base.calculate = _edje_smart_calculate;
+   sc->base.member_add = NULL;
+   sc->base.member_del = NULL;
+   sc->file_set = _edje_smart_file_set;
+}
+
+const Edje_Smart_Api *
+_edje_object_smart_class_get(void)
+{
+   static const Edje_Smart_Api *class = NULL;
+
+   if (class)
+     return class;
+
+   _edje_object_smart_set(&_edje_smart_class);
+   class = &_edje_smart_class;
+
+   return class;
+}
+
+/* Private Routines */
+static void
+_edje_smart_add(Evas_Object *obj)
+{
+   Edje *ed;
+
+   ed = evas_object_smart_data_get(obj);
+   if (!ed)
+     {
+       const Evas_Smart *smart;
+       const Evas_Smart_Class *sc;
+
+       ed = calloc(1, sizeof(Edje));
+       if (!ed) return;
+
+       smart = evas_object_smart_smart_get(obj);
+       sc = evas_smart_class_get(smart);
+       ed->api = (const Edje_Smart_Api *)sc;
+
+       evas_object_smart_data_set(obj, ed);
+     }
+
+   ed->evas = evas_object_evas_get(obj);
+   ed->clipper = evas_object_rectangle_add(ed->evas);
+   evas_object_smart_member_add(ed->clipper, obj);
+   evas_object_color_set(ed->clipper, 255, 255, 255, 255);
+   evas_object_move(ed->clipper, -10000, -10000);
+   evas_object_resize(ed->clipper, 20000, 20000);
+   evas_object_pass_events_set(ed->clipper, 1);
+   ed->have_objects = 1;
+   ed->references = 1;
+
+   evas_object_geometry_get(obj, &(ed->x), &(ed->y), &(ed->w), &(ed->h));
+   ed->obj = obj;
+   _edje_edjes = eina_list_append(_edje_edjes, obj);
+/*
+     {
+       Eina_List *l;
+       const void *data;
+
+       printf("--- EDJE DUMP [%i]\n", eina_list_count(_edje_edjes));
+       EINA_LIST_FOREACH(_edge_edges, l, data)
+         {
+            ed = _edje_fetch(data);
+            printf("EDJE: %80s | %80s\n", ed->path, ed->part);
+         }
+       printf("--- EDJE DUMP [%i]\n", eina_list_count(_edje_edjes));
+     }
+ */
+}
+
+static void
+_edje_smart_del(Evas_Object * obj)
+{
+   Edje *ed;
+
+   ed = evas_object_smart_data_get(obj);
+   if (!ed) return;
+   _edje_block_violate(ed);
+   ed->delete_me = 1;
+   _edje_edjes = eina_list_remove(_edje_edjes, obj);
+   evas_object_smart_data_set(obj, NULL);
+   if (_edje_script_only(ed)) _edje_script_only_shutdown(ed);
+   if (_edje_lua_script_only(ed)) _edje_lua_script_only_shutdown(ed);
+   if (ed->persp) edje_object_perspective_set(obj, NULL);
+   _edje_file_del(ed);
+   _edje_clean_objects(ed);
+   _edje_unref(ed);
+}
+
+static void
+_edje_smart_move(Evas_Object * obj, Evas_Coord x, Evas_Coord y)
+{
+   Edje *ed;
+   int i;
+
+   ed = evas_object_smart_data_get(obj);
+   if (!ed) return;
+   if ((ed->x == x) && (ed->y == y)) return;
+   ed->x = x;
+   ed->y = y;
+//   evas_object_move(ed->clipper, ed->x, ed->y);
+
+   if (_edje_script_only(ed))
+     {
+       _edje_script_only_move(ed);
+       return;
+     }
+   if (_edje_lua_script_only(ed))
+     {
+        _edje_lua_script_only_move(ed);
+        return;
+     }
+
+   if (ed->have_mapped_part)
+     {
+        ed->dirty = 1;
+        _edje_recalc_do(ed);
+     }
+   else
+     {
+        for (i = 0; i < ed->table_parts_size; i++)
+          {
+             Edje_Real_Part *ep;
+             Evas_Coord ox, oy;
+             
+             ep = ed->table_parts[i];
+             evas_object_geometry_get(ep->object, &ox, &oy, NULL, NULL);
+             evas_object_move(ep->object, ed->x + ep->x + ep->text.offset.x, ed->y + ep->y + ep->text.offset.y);
+             if (ep->part->entry_mode > EDJE_ENTRY_EDIT_MODE_NONE)
+               _edje_entry_real_part_configure(ep);
+             if (ep->swallowed_object)
+               {
+                  evas_object_geometry_get(ep->swallowed_object, &ox, &oy, NULL, NULL);
+                  evas_object_move(ep->swallowed_object, ed->x + ep->x + ep->text.offset.x, ed->y + ep->y + ep->text.offset.y);
+               }
+          }
+     }
+//   _edje_emit(ed, "move", NULL);
+}
+
+static void
+_edje_smart_resize(Evas_Object * obj, Evas_Coord w, Evas_Coord h)
+{
+   Edje *ed;
+
+   ed = evas_object_smart_data_get(obj);
+   if (!ed) return;
+   if ((w == ed->w) && (h == ed->h)) return;
+   ed->w = w;
+   ed->h = h;
+#ifdef EDJE_CALC_CACHE
+   ed->all_part_change = 1;
+#endif
+   if (_edje_script_only(ed))
+     {
+       _edje_script_only_resize(ed);
+       return;
+     }
+   if (_edje_lua_script_only(ed))
+     {
+       _edje_lua_script_only_resize(ed);
+       return;
+     }
+//   evas_object_resize(ed->clipper, ed->w, ed->h);
+   ed->dirty = 1;
+   _edje_recalc_do(ed);
+   _edje_emit(ed, "resize", NULL);
+}
+
+static void
+_edje_smart_show(Evas_Object * obj)
+{
+   Edje *ed;
+
+   ed = evas_object_smart_data_get(obj);
+   if (!ed) return;
+   if (evas_object_visible_get(ed->clipper)) return;
+   if ((ed->collection) && (evas_object_clipees_get(ed->clipper)))
+     evas_object_show(ed->clipper);
+   if (_edje_script_only(ed))
+     {  
+       _edje_script_only_show(ed);
+       return;
+     }
+   if (_edje_lua_script_only(ed))
+     {
+        _edje_lua_script_only_show(ed);
+        return;
+     }
+   _edje_emit(ed, "show", NULL);
+}
+
+static void
+_edje_smart_hide(Evas_Object * obj)
+{
+   Edje *ed;
+
+   ed = evas_object_smart_data_get(obj);
+   if (!ed) return;
+   if (!evas_object_visible_get(ed->clipper)) return;
+   if ((ed->collection) && (evas_object_clipees_get(ed->clipper)))
+     evas_object_hide(ed->clipper);
+   if (_edje_script_only(ed))
+     {  
+       _edje_script_only_hide(ed);
+       return;
+     }
+   if (_edje_lua_script_only(ed))
+     {
+        _edje_lua_script_only_hide(ed);
+        return;
+     }
+   _edje_emit(ed, "hide", NULL);
+}
+
+static void
+_edje_smart_color_set(Evas_Object * obj, int r, int g, int b, int a)
+{
+   Edje *ed;
+
+   ed = evas_object_smart_data_get(obj);
+   if (!ed) return;
+   evas_object_color_set(ed->clipper, r, g, b, a);
+//   _edje_emit(ed, "color_set", NULL);
+}
+
+static void
+_edje_smart_clip_set(Evas_Object * obj, Evas_Object * clip)
+{
+   Edje *ed;
+
+   ed = evas_object_smart_data_get(obj);
+   if (!ed) return;
+   if (evas_object_clip_get(obj) == clip) return;
+   evas_object_clip_set(ed->clipper, clip);
+//   _edje_emit(ed, "clip_set", NULL);
+}
+
+static void
+_edje_smart_clip_unset(Evas_Object * obj)
+{
+   Edje *ed;
+
+   ed = evas_object_smart_data_get(obj);
+   if (!ed) return;
+   if (!evas_object_clip_get(obj)) return;
+   evas_object_clip_unset(ed->clipper);
+//   _edje_emit(ed, "clip_unset", NULL);
+}
+
+static void
+_edje_smart_calculate(Evas_Object *obj)
+{
+   Edje *ed;
+
+   ed = evas_object_smart_data_get(obj);
+   if (!ed) return;
+   _edje_recalc_do(ed);
+}
+
+static Eina_Bool
+_edje_smart_file_set(Evas_Object *obj, const char *file, const char *group)
+{
+   return _edje_object_file_set_internal(obj, file, group, NULL);
+}
diff --git a/src/lib/edje_text.c b/src/lib/edje_text.c
new file mode 100644 (file)
index 0000000..ea59e16
--- /dev/null
@@ -0,0 +1,703 @@
+/*
+ * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
+ */
+
+#include <string.h>
+
+#include "edje_private.h"
+
+
+/* returns with and height for this part.
+ *
+ * depending on the value of the use_alternate_font_metrics flag, it will
+ * either use evas_object_geometry_get() or the _advance_get() functions.
+ *
+ * The latter is useful if you want to make sure that width and height
+ * are the same value for the same number of characters in the text.
+ * This usually only makes sense for monospaced fonts.
+ *
+ * In future changes to this file, you probably should use this wrapper
+ * function everywhere instead of calling evas_object_geometry_get()
+ * directly.
+ */
+static inline void
+part_get_geometry(Edje_Real_Part *rp, Evas_Coord *w, Evas_Coord *h)
+{
+   if (!rp->part->use_alternate_font_metrics)
+     evas_object_geometry_get(rp->object, NULL, NULL, w, h);
+   else
+     {
+       if (w) *w = evas_object_text_horiz_advance_get(rp->object);
+       if (h) *h = evas_object_text_vert_advance_get(rp->object);
+     }
+}
+
+void
+_edje_text_init(void)
+{
+}
+
+void
+_edje_text_part_on_add(Edje *ed, Edje_Real_Part *ep)
+{
+   Eina_List *tmp;
+   Edje_Part *pt = ep->part;
+   Edje_Part_Description *desc;
+
+   if (ep->part->type != EDJE_PART_TYPE_TEXT) return;
+
+   /* if text class exists for this part, add the edje to the tc member list */
+   if ((pt->default_desc) && (pt->default_desc->text.text_class))
+     _edje_text_class_member_add(ed, pt->default_desc->text.text_class);
+
+   /* If any other classes exist add them */
+   EINA_LIST_FOREACH(pt->other_desc, tmp, desc)
+     if ((desc) && (desc->text.text_class))
+       _edje_text_class_member_add(ed, desc->text.text_class);
+}
+
+void
+_edje_text_part_on_del(Edje *ed, Edje_Part *pt)
+{
+   Eina_List *tmp;
+   Edje_Part_Description *desc;
+
+   if ((pt->default_desc) && (pt->default_desc->text.text_class))
+     _edje_text_class_member_del(ed, pt->default_desc->text.text_class);
+
+   EINA_LIST_FOREACH(pt->other_desc, tmp, desc)
+     if (desc->text.text_class)
+       _edje_text_class_member_del(ed, desc->text.text_class);
+}
+
+static void
+_edje_text_fit_set(char *buf, const char *text, int c1, int c2)
+{
+   /* helper function called from _edje_text_fit_x().
+    * note that we can use strcpy()/strcat() safely, the buffer lengths
+    * are checked in the caller.
+    */
+
+   if (c1 >= 0)
+     {
+       strcpy(buf, "...");
+
+       if (c2 >= 0)
+         {
+            strncat(buf, text + c1, c2 - c1);
+            strcat(buf, "...");
+         }
+       else
+         strcat(buf, text + c1);
+     }
+   else
+     {
+       if (c2 >= 0)
+         {
+            strncpy(buf, text, c2);
+            buf[c2] = 0;
+            strcat(buf, "...");
+         }
+       else
+         strcpy(buf, text);
+     }
+}
+
+static const char *
+_edje_text_fit_x(Edje *ed, Edje_Real_Part *ep,
+                 Edje_Calc_Params *params,
+                 const char *text, const char *font, int size,
+                 Evas_Coord sw, int *free_text)
+{
+   Evas_Coord tw = 0, th = 0, p;
+   int l, r;
+   char *buf;
+   int c1 = -1, c2 = -1, loop = 0, extra;
+   size_t orig_len;
+   FLOAT_T sc;
+
+   sc = ed->scale;
+   if (sc == ZERO) sc = _edje_scale;
+   
+   *free_text = 0;
+   if (sw <= 1) return "";
+
+   if (ep->part->scale) evas_object_scale_set(ep->object, TO_DOUBLE(sc));
+   evas_object_text_font_set(ep->object, font, size);
+   evas_object_text_text_set(ep->object, text);
+
+   part_get_geometry(ep, &tw, &th);
+   evas_object_text_style_pad_get(ep->object, &l, &r, NULL, NULL);
+
+   p = ((sw - tw) * params->type.text.elipsis);
+
+   /* chop chop */
+   if (tw > sw)
+     {
+       if (params->type.text.elipsis != 0.0)
+          /* should be the last in text! not the rightmost */
+          c1 = evas_object_text_last_up_to_pos(ep->object,
+                -p + l, th / 2);
+       if (params->type.text.elipsis != 1.0)
+          /* should be the last in text! not the rightmost */
+          c2 = evas_object_text_last_up_to_pos(ep->object,
+                -p + sw - r, th / 2);
+       if ((c1 < 0) && (c2 < 0))
+         {
+            c1 = 0;
+            c2 = 0;
+         }
+     }
+
+   if (!(((c1 >= 0) || (c2 >= 0)) && (tw > sw)))
+     return text;
+
+   if ((c1 == 0) && (c2 == 0))
+     return text;
+
+   orig_len = strlen(text);
+
+   /* don't overflow orig_len by adding extra
+    * FIXME: we might want to set a max string length somewhere...
+    */
+   extra = 1 + 3 + 3; /* terminator, leading and trailing ellipsis */
+   orig_len = MIN(orig_len, 8192 - extra);
+
+   if (!(buf = malloc(orig_len + extra)))
+     return text;
+
+   while (((c1 >= 0) || (c2 >= 0)) && (tw > sw))
+     {
+       loop++;
+       if (sw <= 0.0)
+         {
+            buf[0] = 0;
+            break;
+         }
+       if ((c1 >= 0) && (c2 >= 0))
+         {
+            if ((loop & 0x1))
+              {
+                 if (c1 >= 0)
+                   c1 = evas_string_char_next_get(text, c1, NULL);
+              }
+            else
+              {
+                 if (c2 >= 0)
+                   {
+                      c2 = evas_string_char_prev_get(text, c2, NULL);
+                      if (c2 < 0)
+                        {
+                           buf[0] = 0;
+                           break;
+                        }
+                   }
+              }
+         }
+       else
+         {
+            if (c1 >= 0)
+              c1 = evas_string_char_next_get(text, c1, NULL);
+            else if (c2 >= 0)
+              {
+                 c2 = evas_string_char_prev_get(text, c2, NULL);
+                 if (c2 < 0)
+                   {
+                      buf[0] = 0;
+                      break;
+                   }
+              }
+         }
+       if ((c1 >= 0) && (c2 >= 0))
+         {
+            if (c1 >= c2)
+              {
+                 buf[0] = 0;
+                 break;
+              }
+         }
+       else if ((c1 > 0 && c1 >= orig_len) || c2 == 0)
+         {
+            buf[0] = 0;
+            break;
+         }
+
+       buf[0] = 0;
+
+       _edje_text_fit_set(buf, text, c1, c2);
+
+       evas_object_text_text_set(ep->object, buf);
+       part_get_geometry(ep, &tw, &th);
+     }
+
+   *free_text = 1;
+
+   return buf;
+}
+
+static const char *
+_edje_text_font_get(const char *base, const char *new, char **free_later)
+{
+   const char *base_style, *new_style, *aux;
+   int font_len, style_len;
+
+   if (base && (!new))
+     return base;
+   else if (!base)
+     return new;
+
+   base_style = strstr(base, ":style=");
+   if (!base_style)
+     return new;
+
+   new_style = strstr(new, ":style=");
+   if (new_style)
+     return new;
+
+   font_len = strlen(new);
+   aux = strchr(base_style, ',');
+   style_len = (aux) ?  (aux - base_style) : strlen(base_style);
+
+   *free_later = malloc(font_len + style_len + 1);
+   memcpy(*free_later, new, font_len);
+   memcpy(*free_later + font_len, base_style, style_len);
+   (*free_later)[font_len + style_len] = '\0';
+
+   return *free_later;
+}
+
+const char *
+_edje_text_class_font_get(Edje *ed, Edje_Part_Description *chosen_desc, int *size, char **free_later)
+{
+   Edje_Text_Class *tc;
+   const char *text_class_name, *font;
+
+   font = chosen_desc->text.font;
+   *size = chosen_desc->text.size;
+
+   text_class_name = chosen_desc->text.text_class;
+   if ((!text_class_name) || (!text_class_name[0]))
+     return font;
+
+   tc = _edje_text_class_find(ed, text_class_name);
+   if (!tc)
+     return font;
+
+   font = _edje_text_font_get(chosen_desc->text.font, tc->font, free_later);
+   *size = _edje_text_size_calc(*size, tc);
+
+   return font;
+}
+
+void
+_edje_text_recalc_apply(Edje *ed, Edje_Real_Part *ep,
+                       Edje_Calc_Params *params,
+                       Edje_Part_Description *chosen_desc)
+{
+   const char  *text;
+   const char  *font;
+   char                *font2 = NULL;
+   char         *sfont = NULL;
+   int          size;
+   Evas_Coord   tw, th;
+   Evas_Coord   sw, sh;
+   int          inlined_font = 0, free_text = 0;
+   FLOAT_T       sc;
+
+   sc = ed->scale;
+   if (sc == 0.0) sc = _edje_scale;
+   text = chosen_desc->text.text;
+   font = _edje_text_class_font_get(ed, chosen_desc, &size, &sfont);
+
+   if (ep->text.text) text = (char *) ep->text.text;
+   if (ep->text.font) font = ep->text.font;
+   if (ep->text.size > 0) size = ep->text.size;
+
+   if (ep->text.text_source)
+     {
+       text = ep->text.text_source->chosen_description->text.text;
+       if (ep->text.text_source->text.text) text = ep->text.text_source->text.text;
+     }
+   if (ep->text.source)
+     {
+       font = ep->text.source->chosen_description->text.font;
+       size = ep->text.source->chosen_description->text.size;
+       if (ep->text.source->text.font) font = ep->text.source->text.font;
+       if (ep->text.source->text.size > 0) size = ep->text.source->text.size;
+     }
+
+   if (!text) text = "";
+   if (!font) font = "";
+
+   /* check if the font is embedded in the .eet */
+   if (ed->file->font_hash)
+     {
+       Edje_Font_Directory_Entry *fnt = eina_hash_find(ed->file->font_hash, font);
+
+       if (fnt)
+         {
+            font = fnt->path;
+            inlined_font = 1;
+         }
+     }
+
+   if ((_edje_fontset_append) && (font))
+     {
+       font2 = malloc(strlen(font) + 1 + strlen(_edje_fontset_append) + 1);
+       if (font2)
+         {
+            strcpy(font2, font);
+            strcat(font2, ",");
+            strcat(font2, _edje_fontset_append);
+            font = font2;
+         }
+     }
+     {
+       int l, r, t, b;
+
+       evas_object_text_style_pad_get(ep->object, &l, &r, &t, &b);
+       sw = params->w;
+       sh = params->h;
+     }
+
+   size = params->type.text.size;
+
+   if ((ep->text.cache.in_size == size) &&
+       (ep->text.cache.in_w == sw) &&
+       (ep->text.cache.in_h == sh) &&
+       (ep->text.cache.in_str) &&
+       (text) &&
+       (!strcmp(ep->text.cache.in_str, text)) &&
+       (ep->text.cache.align_x == params->type.text.align.x) &&
+       (ep->text.cache.align_y == params->type.text.align.y) &&
+       (ep->text.cache.elipsis == params->type.text.elipsis) &&
+       (ep->text.cache.fit_x == chosen_desc->text.fit_x) &&
+       (ep->text.cache.fit_y == chosen_desc->text.fit_y))
+     {
+       text = (char *)ep->text.cache.out_str;
+       size = ep->text.cache.out_size;
+
+       if (!text) text = "";
+
+       goto arrange_text;
+     }
+   if (ep->text.cache.in_str) eina_stringshare_del(ep->text.cache.in_str);
+   ep->text.cache.in_str = eina_stringshare_add(text);
+   ep->text.cache.in_size = size;
+   if (chosen_desc->text.fit_x)
+     {
+        if (inlined_font) evas_object_text_font_source_set(ep->object, ed->path);
+       else evas_object_text_font_source_set(ep->object, NULL);
+
+       if (ep->part->scale) evas_object_scale_set(ep->object, TO_DOUBLE(sc));
+       evas_object_text_font_set(ep->object, font, size);
+       evas_object_text_text_set(ep->object, text);
+       part_get_geometry(ep, &tw, &th);
+       if (tw > sw)
+         {
+            int psize;
+
+            psize = size;
+            while ((tw > sw) && (size > 0) && (tw != 0))
+              {
+                 psize = size;
+                 size = (size * sw) / tw;
+                 if ((psize - size) <= 0) size = psize - 1;
+                 if (inlined_font) evas_object_text_font_source_set(ep->object, ed->path);
+                 else evas_object_text_font_source_set(ep->object, NULL);
+
+                 if (ep->part->scale) evas_object_scale_set(ep->object, TO_DOUBLE(sc));
+                 evas_object_text_font_set(ep->object, font, size);
+                 part_get_geometry(ep, &tw, &th);
+                 if ((size > 0) && (tw == 0)) break;
+              }
+         }
+       else if (tw < sw)
+         {
+            int psize;
+
+            psize = size;
+            while ((tw < sw) && (size > 0) && (tw != 0))
+              {
+                 psize = size;
+                 size = (size * sw) / tw;
+                 if ((psize - size) >= 0) size = psize + 1;
+                 if (inlined_font) evas_object_text_font_source_set(ep->object, ed->path);
+                 else evas_object_text_font_source_set(ep->object, NULL);
+
+                 if (ep->part->scale) evas_object_scale_set(ep->object, TO_DOUBLE(sc));
+                 evas_object_text_font_set(ep->object, font, size);
+                 part_get_geometry(ep, &tw, &th);
+                 if ((size > 0) && (tw == 0)) break;
+              }
+         }
+     }
+   if (chosen_desc->text.fit_y)
+     {
+       /* if we fit in the x axis, too, size already has a somewhat
+        * meaningful value, so don't overwrite it with the starting
+        * value in that case
+        */
+       if (!chosen_desc->text.fit_x) size = sh;
+
+        if (inlined_font) evas_object_text_font_source_set(ep->object, ed->path);
+       else evas_object_text_font_source_set(ep->object, NULL);
+
+       if (ep->part->scale) evas_object_scale_set(ep->object, TO_DOUBLE(sc));
+       evas_object_text_font_set(ep->object, font, size);
+       evas_object_text_text_set(ep->object, text);
+       part_get_geometry(ep, &tw, &th);
+
+       /* only grow the font size if we didn't already reach the max size
+        * for the x axis
+        */
+       if (!chosen_desc->text.fit_x && th < sh)
+         {
+            int dif;
+
+            dif = (th - sh) / 4;
+            if (dif < 1) dif = 1;
+            while ((th < sh) && (sw > 0))
+              {
+                 size += dif;
+                 if (size <= 0) break;
+                 if (inlined_font) evas_object_text_font_source_set(ep->object, ed->path);
+                 else evas_object_text_font_source_set(ep->object, NULL);
+
+                 if (ep->part->scale) evas_object_scale_set(ep->object, TO_DOUBLE(sc));
+                 evas_object_text_font_set(ep->object, font, size);
+                 part_get_geometry(ep, &tw, &th);
+                 if ((size > 0) && (th == 0)) break;
+              }
+            size -= dif;
+         }
+       else if (th > sh)
+         {
+            int current;
+
+            if (ep->part->scale) evas_object_scale_set(ep->object, TO_DOUBLE(sc));
+            evas_object_text_font_set(ep->object, font, 10);
+            part_get_geometry(ep, &tw, &th);
+
+            if (th == sh)
+              current = 10;
+            else
+              {
+                 int bottom, top;
+
+                 if (th < sh)
+                   bottom = 10;
+                 else if (th > sh)
+                   {
+                      bottom = 1;
+                      top = 10;
+                   }
+                 else bottom = 0; /* XXX shut up GCC, th == sh is handled before! */
+
+                 top = size;
+                 /* search one that fits (binary search) */
+                 do
+                   {
+                      current = (top + bottom) / 2;
+
+                      if (ep->part->scale) evas_object_scale_set(ep->object, TO_DOUBLE(sc));
+                      evas_object_text_font_set(ep->object, font, current);
+                      part_get_geometry(ep, &tw, &th);
+
+                      if      (th < sh) bottom = current + 1;
+                      else if (th > sh) top    = current - 1;
+                   } while ((bottom < top) && (th != sh));
+              }
+
+            /* search the larger one that fits (linear search) */
+            do
+              {
+                 current++;
+
+                 if (ep->part->scale) evas_object_scale_set(ep->object, TO_DOUBLE(sc));
+                 evas_object_text_font_set(ep->object, font, current);
+                 part_get_geometry(ep, &tw, &th);
+              } while (th <= sh);
+            size = current - 1;
+         }
+     }
+   if (size < 1) size = 1;
+
+   if (!chosen_desc->text.fit_x)
+     {
+       if (inlined_font) evas_object_text_font_source_set(ep->object, ed->path);
+       else evas_object_text_font_source_set(ep->object, NULL);
+
+       text = _edje_text_fit_x(ed, ep, params, text, font, size, sw, &free_text);
+     }
+
+   if (ep->text.cache.out_str) eina_stringshare_del(ep->text.cache.out_str);
+   ep->text.cache.out_str = eina_stringshare_add(text);
+   ep->text.cache.in_w = sw;
+   ep->text.cache.in_h = sh;
+   ep->text.cache.out_size = size;
+   ep->text.cache.align_x = params->type.text.align.x;
+   ep->text.cache.align_y = params->type.text.align.y;
+   ep->text.cache.elipsis = params->type.text.elipsis;
+   ep->text.cache.fit_x = chosen_desc->text.fit_x;
+   ep->text.cache.fit_y = chosen_desc->text.fit_y;
+   arrange_text:
+
+   if (inlined_font) evas_object_text_font_source_set(ep->object, ed->path);
+   else evas_object_text_font_source_set(ep->object, NULL);
+
+   if (ep->part->scale) evas_object_scale_set(ep->object, TO_DOUBLE(sc));
+   evas_object_text_font_set(ep->object, font, size);
+   evas_object_text_text_set(ep->object, text);
+   part_get_geometry(ep, &tw, &th);
+   ep->text.offset.x = TO_INT(SCALE(params->type.text.align.x, (sw - tw)));
+   ep->text.offset.y = TO_INT(SCALE(params->type.text.align.y, (sh - th)));
+
+   evas_object_move(ep->object,
+                   ed->x + params->x + ep->text.offset.x,
+                   ed->y + params->y + ep->text.offset.y);
+
+   if (params->visible) evas_object_show(ep->object);
+   else evas_object_hide(ep->object);
+     {
+       Evas_Text_Style_Type style;
+
+       style = EVAS_TEXT_STYLE_PLAIN;
+
+       evas_object_color_set(ep->object,
+                             (params->color.r * params->color.a) / 255,
+                             (params->color.g * params->color.a) / 255,
+                             (params->color.b * params->color.a) / 255,
+                             params->color.a);
+
+       if ((ep->part->effect == EDJE_TEXT_EFFECT_NONE) ||
+             (ep->part->effect == EDJE_TEXT_EFFECT_PLAIN))
+         {
+            style = EVAS_TEXT_STYLE_PLAIN;
+         }
+       else if (ep->part->effect == EDJE_TEXT_EFFECT_OUTLINE)
+         {
+            style = EVAS_TEXT_STYLE_OUTLINE;
+            evas_object_text_outline_color_set(ep->object,
+                                               (params->type.text.color2.r * params->type.text.color2.a) / 255,
+                                               (params->type.text.color2.g * params->type.text.color2.a) / 255,
+                                               (params->type.text.color2.b * params->type.text.color2.a) / 255,
+                                               params->type.text.color2.a);
+         }
+       else if (ep->part->effect == EDJE_TEXT_EFFECT_SOFT_OUTLINE)
+         {
+            style = EVAS_TEXT_STYLE_SOFT_OUTLINE;
+            evas_object_text_outline_color_set(ep->object,
+                                               (params->type.text.color2.r * params->type.text.color2.a) / 255,
+                                               (params->type.text.color2.g * params->type.text.color2.a) / 255,
+                                               (params->type.text.color2.b * params->type.text.color2.a) / 255,
+                                               params->type.text.color2.a);
+         }
+       else if (ep->part->effect == EDJE_TEXT_EFFECT_SHADOW)
+         {
+            style = EVAS_TEXT_STYLE_SHADOW;
+            evas_object_text_shadow_color_set(ep->object,
+                                              (params->type.text.color3.r * params->type.text.color3.a) / 255,
+                                              (params->type.text.color3.g * params->type.text.color3.a) / 255,
+                                              (params->type.text.color3.b * params->type.text.color3.a) / 255,
+                                              params->type.text.color3.a);
+         }
+       else if (ep->part->effect == EDJE_TEXT_EFFECT_SOFT_SHADOW)
+         {
+            style = EVAS_TEXT_STYLE_SOFT_SHADOW;
+            evas_object_text_shadow_color_set(ep->object,
+                                              (params->type.text.color3.r * params->type.text.color3.a) / 255,
+                                              (params->type.text.color3.g * params->type.text.color3.a) / 255,
+                                              (params->type.text.color3.b * params->type.text.color3.a) / 255,
+                                              params->type.text.color3.a);
+         }
+       else if (ep->part->effect == EDJE_TEXT_EFFECT_OUTLINE_SHADOW)
+         {
+            style = EVAS_TEXT_STYLE_OUTLINE_SHADOW;
+            evas_object_text_outline_color_set(ep->object,
+                                               (params->type.text.color2.r * params->type.text.color2.a) / 255,
+                                               (params->type.text.color2.g * params->type.text.color2.a) / 255,
+                                               (params->type.text.color2.b * params->type.text.color2.a) / 255,
+                                               params->type.text.color2.a);
+            evas_object_text_shadow_color_set(ep->object,
+                                              (params->type.text.color3.r * params->type.text.color3.a) / 255,
+                                              (params->type.text.color3.g * params->type.text.color3.a) / 255,
+                                              (params->type.text.color3.b * params->type.text.color3.a) / 255,
+                                              params->type.text.color3.a);
+         }
+       else if (ep->part->effect == EDJE_TEXT_EFFECT_OUTLINE_SOFT_SHADOW)
+         {
+            style = EVAS_TEXT_STYLE_OUTLINE_SOFT_SHADOW;
+            evas_object_text_outline_color_set(ep->object,
+                                               (params->type.text.color2.r * params->type.text.color2.a) / 255,
+                                               (params->type.text.color2.g * params->type.text.color2.a) / 255,
+                                               (params->type.text.color2.b * params->type.text.color2.a) / 255,
+                                               params->type.text.color2.a);
+            evas_object_text_shadow_color_set(ep->object,
+                                              (params->type.text.color3.r * params->type.text.color3.a) / 255,
+                                              (params->type.text.color3.g * params->type.text.color3.a) / 255,
+                                              (params->type.text.color3.b * params->type.text.color3.a) / 255,
+                                              params->type.text.color3.a);
+         }
+       else if (ep->part->effect == EDJE_TEXT_EFFECT_FAR_SHADOW)
+         {
+            style = EVAS_TEXT_STYLE_FAR_SHADOW;
+            evas_object_text_shadow_color_set(ep->object,
+                                              (params->type.text.color3.r * params->type.text.color3.a) / 255,
+                                              (params->type.text.color3.g * params->type.text.color3.a) / 255,
+                                              (params->type.text.color3.b * params->type.text.color3.a) / 255,
+                                              params->type.text.color3.a);
+         }
+       else if (ep->part->effect == EDJE_TEXT_EFFECT_FAR_SOFT_SHADOW)
+         {
+            style = EVAS_TEXT_STYLE_FAR_SOFT_SHADOW;
+            evas_object_text_shadow_color_set(ep->object,
+                                              (params->type.text.color3.r * params->type.text.color3.a) / 255,
+                                              (params->type.text.color3.g * params->type.text.color3.a) / 255,
+                                              (params->type.text.color3.b * params->type.text.color3.a) / 255,
+                                              params->type.text.color3.a);
+         }
+       else if (ep->part->effect == EDJE_TEXT_EFFECT_GLOW)
+         {
+            style = EVAS_TEXT_STYLE_GLOW;
+            evas_object_text_glow_color_set(ep->object,
+                                               (params->type.text.color2.r * params->type.text.color2.a) / 255,
+                                               (params->type.text.color2.g * params->type.text.color2.a) / 255,
+                                               (params->type.text.color2.b * params->type.text.color2.a) / 255,
+                                               params->type.text.color2.a);
+            evas_object_text_glow2_color_set(ep->object,
+                                              (params->type.text.color3.r * params->type.text.color3.a) / 255,
+                                              (params->type.text.color3.g * params->type.text.color3.a) / 255,
+                                              (params->type.text.color3.b * params->type.text.color3.a) / 255,
+                                              params->type.text.color3.a);
+         }
+       evas_object_text_style_set(ep->object, style);
+     }
+
+   if (free_text)
+     free((char *)text);
+   if (font2)
+     free(font2);
+   if (sfont)
+     free(sfont);
+}
+
+Evas_Font_Size
+_edje_text_size_calc(Evas_Font_Size size, Edje_Text_Class *tc)
+{
+   int val;
+
+   if (tc->size == 0)
+     {
+       val = size;
+     }
+   else if (tc->size > 0.0)
+     {
+       val = tc->size;
+     }
+   else
+     {
+       val = (size * -tc->size) / 100;
+     }
+   return val;
+}
diff --git a/src/lib/edje_textblock_styles.c b/src/lib/edje_textblock_styles.c
new file mode 100644 (file)
index 0000000..c1b1305
--- /dev/null
@@ -0,0 +1,430 @@
+/*
+ * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
+ */
+
+#include <string.h>
+
+#include "edje_private.h"
+
+static int
+_edje_font_is_embedded(Edje_File *edf, char *font __UNUSED__)
+{
+   if (!edf->font_dir) return 0;
+   return 1;
+}
+
+static void
+_edje_format_param_parse(char *item, char **key, char **val)
+{
+   char *p, *k, *v;
+
+   p = strchr(item, '=');
+   k = malloc(p - item + 1);
+   strncpy(k, item, p - item);
+   k[p - item] = 0;
+   *key = k;
+   p++;
+   v = strdup(p);
+   *val = v;
+}
+
+static char *
+_edje_format_parse(const char **s)
+{
+   char *item, *ds;
+   const char *p, *ss;
+   const char *s1 = NULL;
+   const char *s2 = NULL;
+
+   p = *s;
+   if ((!p) || (*p == 0)) return NULL;
+   for (;;)
+     {
+       if (!s1)
+         {
+            if (*p != ' ') s1 = p;
+            if (*p == 0) break;
+         }
+       else if (!s2)
+         {
+            if ((p > *s) && (p[-1] != '\\'))
+              {
+                 if (*p == ' ') s2 = p;
+              }
+            if (*p == 0) s2 = p;
+         }
+       p++;
+       if (s1 && s2)
+         {
+            item = malloc(s2 - s1 + 1);
+            if (item)
+              {
+                 for (ds = item, ss = s1; ss < s2; ss++, ds++)
+                   {
+                      if ((*ss == '\\') && (ss < (s2 - 1))) ss++;
+                      *ds = *ss;
+                   }
+                 *ds = 0;
+              }
+            *s = s2;
+            return item;
+         }
+     }
+   *s = p;
+   return NULL;
+}
+
+static int
+_edje_format_is_param(char *item)
+{
+   if (strchr(item, '=')) return 1;
+   return 0;
+}
+
+static char *
+_edje_format_reparse(Edje_File *edf, const char *str, Edje_Style_Tag **tag_ret)
+{
+   Eina_Strbuf *txt, *tmp = NULL;
+   char *s2, *item, *ret;
+   const char *s;
+
+   txt = eina_strbuf_new();
+   s = str;
+   while ((item = _edje_format_parse(&s)))
+     {
+       if (_edje_format_is_param(item))
+         {
+            char *key = NULL, *val = NULL;
+
+            _edje_format_param_parse(item, &key, &val);
+            if (!strcmp(key, "font_source"))
+              {
+                 /* dont allow font sources */
+              }
+            else if (!strcmp(key, "text_class"))
+              {
+                 if (tag_ret)
+                   (*tag_ret)->text_class = eina_stringshare_add(val);
+              }
+            else if (!strcmp(key, "font_size"))
+              {
+                 if (tag_ret)
+                   (*tag_ret)->font_size = atof(val);
+              }
+            else if (!strcmp(key, "font")) /* Fix fonts */
+              {
+                 if (tag_ret)
+                   {
+                      if (_edje_font_is_embedded(edf, val))
+                        {
+                           if (!tmp)
+                             tmp = eina_strbuf_new();
+                           eina_strbuf_append(tmp, "fonts/");
+                           eina_strbuf_append(tmp, val);
+                           (*tag_ret)->font = eina_stringshare_add(eina_strbuf_string_get(tmp));
+                           eina_strbuf_reset(tmp);
+                        }
+                      else
+                        {
+                           (*tag_ret)->font = eina_stringshare_add(val);
+                        }
+                   }
+              }
+            else /* Otherwise add to tag buffer */
+              {
+                 s2 = eina_str_escape(item);
+                 if (s2)
+                   {
+                      if (eina_strbuf_length_get(txt)) eina_strbuf_append(txt, " ");
+                      eina_strbuf_append(txt, s2);
+                      free(s2);
+                   }
+              }
+            free(key);
+            free(val);
+         }
+       else
+         {
+            if (eina_strbuf_length_get(txt)) eina_strbuf_append(txt, " ");
+            eina_strbuf_append(txt, item);
+         }
+       free(item);
+     }
+   if (tmp)
+     eina_strbuf_free(tmp);
+   ret = eina_strbuf_string_steal(txt);
+   eina_strbuf_free(txt);
+   return ret;
+}
+
+/* Update all evas_styles which are in an edje
+ *
+ * @param ed   The edje containing styles which need to be updated
+ */
+void
+_edje_textblock_style_all_update(Edje *ed)
+{
+   Eina_List *l, *ll;
+   Edje_Style *stl;
+   Eina_Strbuf *txt = NULL;
+
+   if (!ed->file) return;
+
+   EINA_LIST_FOREACH(ed->file->styles, l, stl)
+     {
+       Edje_Style_Tag *tag;
+       Edje_Text_Class *tc;
+       int found = 0;
+       char *fontset = NULL, *fontsource = NULL;
+
+       /* Make sure the style is already defined */
+       if (!stl->style) break;
+
+       /* Make sure the style contains a text_class */
+       EINA_LIST_FOREACH(stl->tags, ll, tag)
+         if (tag->text_class) found = 1;
+
+       /* No text classes , goto next style */
+       if (!found) continue;
+       found = 0;
+       if (!txt)
+         txt = eina_strbuf_new();
+
+       if (_edje_fontset_append)
+         fontset = eina_str_escape(_edje_fontset_append);
+       fontsource = eina_str_escape(ed->file->path);
+
+       /* Build the style from each tag */
+       EINA_LIST_FOREACH(stl->tags, ll, tag)
+         {
+            if (!tag->key) continue;
+
+            /* Add Tag Key */
+            eina_strbuf_append(txt, tag->key);
+            eina_strbuf_append(txt, "='");
+
+            /* Configure fonts from text class if it exists */
+            if ((tc = _edje_text_class_find(ed, tag->text_class)))
+              {
+                 /* Only update if not clearing, If clear leave it at zero */
+                 if (tc->font) found = 1;
+              }
+
+            /* Add and Ha`ndle tag parsed data */
+            eina_strbuf_append(txt, tag->value);
+
+            if (!strcmp(tag->key, "DEFAULT"))
+              {
+                 if (fontset)
+                   {
+                      eina_strbuf_append(txt, " ");
+                      eina_strbuf_append(txt, "font_fallbacks=");
+                      eina_strbuf_append(txt, fontset);
+                   }
+                 eina_strbuf_append(txt, " ");
+                 eina_strbuf_append(txt, "font_source=");
+                 eina_strbuf_append(txt, fontsource);
+              }
+            if (tag->font_size != 0)
+              {
+                 char font_size[32];
+
+                 if (found)
+                   snprintf(font_size, sizeof(font_size), "%f", (double) _edje_text_size_calc(tag->font_size, tc));
+                 else
+                   snprintf(font_size, sizeof(font_size), "%f", tag->font_size);
+
+                 eina_strbuf_append(txt, " ");
+                 eina_strbuf_append(txt, "font_size=");
+                 eina_strbuf_append(txt, font_size);
+              }
+            /* Add font name last to save evas from multiple loads */
+            if (tag->font)
+              {
+                 const char *f;
+
+                 eina_strbuf_append(txt, " ");
+                 eina_strbuf_append(txt, "font=");
+
+                 f = (found) ? tc->font : tag->font;
+                 eina_strbuf_append_escaped(txt, f);
+              }
+            found = 0;
+
+            eina_strbuf_append(txt, "'");
+         }
+       if (fontset) free(fontset);
+       if (fontsource) free(fontsource);
+
+       /* Configure the style */
+       evas_textblock_style_set(stl->style, eina_strbuf_string_get(txt));
+       eina_strbuf_reset(txt);
+     }
+   if (txt)
+     eina_strbuf_free(txt);
+}
+
+void
+_edje_textblock_styles_add(Edje *ed)
+{
+   Eina_List *l, *ll;
+   Edje_Style *stl;
+
+   if (!ed->file) return;
+
+   EINA_LIST_FOREACH(ed->file->styles, l, stl)
+     {
+       Edje_Style_Tag *tag;
+
+       /* Make sure the style contains the text_class */
+       EINA_LIST_FOREACH(stl->tags, ll, tag)
+         {
+           if (!tag->text_class) continue;
+           _edje_text_class_member_add(ed, tag->text_class);
+         }
+     }
+}
+
+void
+_edje_textblock_styles_del(Edje *ed)
+{
+   Eina_List *l, *ll;
+   Edje_Style *stl;
+
+   if (!ed->file) return;
+
+   EINA_LIST_FOREACH(ed->file->styles, l, stl)
+     {
+       Edje_Style_Tag *tag;
+
+       /* Make sure the style contains the text_class */
+       EINA_LIST_FOREACH(stl->tags, ll, tag)
+         {
+            if (!tag->text_class) continue;
+            _edje_text_class_member_del(ed, tag->text_class);
+         }
+     }
+}
+
+/* When we get to here the edje file had been read into memory
+ * the name of the style is established as well as the name and
+ * data for the tags.  This function will create the Evas_Style
+ * object for each style. The style is composed of a base style
+ * followed by a list of tags.
+ */
+void
+_edje_textblock_style_parse_and_fix(Edje_File *edf)
+{
+   Eina_Strbuf *txt = NULL;
+   Eina_List *l, *ll;
+   Edje_Style *stl;
+
+   EINA_LIST_FOREACH(edf->styles, l, stl)
+     {
+       Edje_Style_Tag *tag;
+       char *fontset = NULL, *fontsource = NULL, *ts;
+
+       if (stl->style) break;
+
+       if (!txt)
+         txt = eina_strbuf_new();
+
+       stl->style = evas_textblock_style_new();
+       evas_textblock_style_set(stl->style, NULL);
+
+       if (_edje_fontset_append)
+         fontset = eina_str_escape(_edje_fontset_append);
+       fontsource = eina_str_escape(edf->path);
+
+       /* Build the style from each tag */
+       EINA_LIST_FOREACH(stl->tags, ll, tag)
+         {
+            if (!tag->key) continue;
+
+            /* Add Tag Key */
+            eina_strbuf_append(txt, tag->key);
+            eina_strbuf_append(txt, "='");
+
+            ts = _edje_format_reparse(edf, tag->value, &(tag));
+
+            /* Add and Handle tag parsed data */
+            if (ts)
+              {
+                 if (eet_dictionary_string_check(eet_dictionary_get(edf->ef), tag->value) == 0)
+                   eina_stringshare_del(tag->value);
+                 tag->value = eina_stringshare_add(ts);
+                 eina_strbuf_append(txt, tag->value);
+                 free(ts);
+              }
+
+            if (!strcmp(tag->key, "DEFAULT"))
+              {
+                 if (fontset)
+                   {
+                      eina_strbuf_append(txt, " ");
+                      eina_strbuf_append(txt, "font_fallbacks=");
+                      eina_strbuf_append(txt, fontset);
+                   }
+                 eina_strbuf_append(txt, " ");
+                 eina_strbuf_append(txt, "font_source=");
+                 eina_strbuf_append(txt, fontsource);
+              }
+            if (tag->font_size > 0)
+              {
+                 char font_size[32];
+
+                 snprintf(font_size, sizeof(font_size), "%f", tag->font_size);
+                 eina_strbuf_append(txt, " ");
+                 eina_strbuf_append(txt, "font_size=");
+                 eina_strbuf_append(txt, font_size);
+              }
+            /* Add font name last to save evas from multiple loads */
+            if (tag->font)
+              {
+                 eina_strbuf_append(txt, " ");
+                 eina_strbuf_append(txt, "font=");
+                 eina_strbuf_append_escaped(txt, tag->font);
+              }
+            eina_strbuf_append(txt, "'");
+         }
+       if (fontset) free(fontset);
+       if (fontsource) free(fontsource);
+
+       /* Configure the style */
+       evas_textblock_style_set(stl->style, eina_strbuf_string_get(txt));
+       eina_strbuf_reset(txt);
+     }
+   if (txt)
+     eina_strbuf_free(txt);
+}
+
+void
+_edje_textblock_style_cleanup(Edje_File *edf)
+{
+   while (edf->styles)
+     {
+       Edje_Style *stl;
+
+       stl = edf->styles->data;
+       edf->styles = eina_list_remove_list(edf->styles, edf->styles);
+       while (stl->tags)
+         {
+            Edje_Style_Tag *tag;
+
+            tag = stl->tags->data;
+            stl->tags = eina_list_remove_list(stl->tags, stl->tags);
+             if (edf->free_strings)
+               {
+                  if (tag->key) eina_stringshare_del(tag->key);
+/*                FIXME: Find a proper way to handle it. */
+                  if (tag->value) eina_stringshare_del(tag->value);
+                  if (tag->text_class) eina_stringshare_del(tag->text_class);
+                  if (tag->font) eina_stringshare_del(tag->font);
+               }
+             free(tag);
+         }
+        if (edf->free_strings && stl->name) eina_stringshare_del(stl->name);
+       if (stl->style) evas_textblock_style_free(stl->style);
+       free(stl);
+     }
+}
diff --git a/src/lib/edje_util.c b/src/lib/edje_util.c
new file mode 100644 (file)
index 0000000..57d59cd
--- /dev/null
@@ -0,0 +1,4731 @@
+/*
+ * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
+ */
+
+#include <string.h>
+
+#include "edje_private.h"
+
+typedef struct _Edje_Box_Layout Edje_Box_Layout;
+struct _Edje_Box_Layout
+{
+   EINA_RBTREE;
+   Evas_Object_Box_Layout func;
+   void *(*layout_data_get)(void *);
+   void (*layout_data_free)(void *);
+   void *data;
+   void (*free_data)(void *);
+   char name[];
+};
+
+static Eina_Hash *_edje_color_class_hash = NULL;
+static Eina_Hash *_edje_color_class_member_hash = NULL;
+
+static Eina_Hash *_edje_text_class_hash = NULL;
+static Eina_Hash *_edje_text_class_member_hash = NULL;
+
+static Eina_Rbtree *_edje_box_layout_registry = NULL;
+
+char *_edje_fontset_append = NULL;
+FLOAT_T _edje_scale = ZERO;
+int _edje_freeze_val = 0;
+int _edje_freeze_calc_count = 0;
+Eina_List *_edje_freeze_calc_list = NULL;
+
+typedef struct _Edje_List_Foreach_Data Edje_List_Foreach_Data;
+struct _Edje_List_Foreach_Data
+{
+   Eina_List *list;
+};
+
+static Eina_Bool _edje_color_class_list_foreach(const Eina_Hash *hash, const void *key, void *data, void *fdata);
+static Eina_Bool _edje_text_class_list_foreach(const Eina_Hash *hash, const void *key, void *data, void *fdata);
+static void _edje_object_image_preload_cb(void *data, Evas *e, Evas_Object *obj, void *event_info);
+static void _edje_object_signal_preload_cb(void *data, Evas_Object *obj, const char *emission, const char *source);
+
+Edje_Real_Part *_edje_real_part_recursive_get_helper(Edje *ed, char **path);
+
+/************************** API Routines **************************/
+
+#define FASTFREEZE 1
+
+/**
+ * @brief Freeze Edje objects.
+ *
+ * This function freezes every edje objects in the current process.
+ *
+ * See edje_object_freeze().
+ *
+ */
+EAPI void
+edje_freeze(void)
+{
+#ifdef FASTFREEZE
+   _edje_freeze_val++;
+   INF("fr ++ ->%i", _edje_freeze_val);
+#else
+// FIXME: could just have a global freeze instead of per object
+// above i tried.. but this broke some things. notable e17's menus. why?
+   Eina_List *l;
+   Evas_Object *data;
+
+   EINA_LIST_FOREACH(_edje_edjes, l, data)
+     edje_object_freeze(data);
+#endif
+}
+
+#ifdef FASTFREEZE
+static void
+_edje_thaw_edje(Edje *ed)
+{
+   int i;
+
+   for (i = 0; i < ed->table_parts_size; i++)
+     {
+       Edje_Real_Part *rp;
+
+       rp = ed->table_parts[i];
+       if (rp->part->type == EDJE_PART_TYPE_GROUP && rp->swallowed_object)
+         {
+            Edje *ed2;
+
+            ed2 = _edje_fetch(rp->swallowed_object);
+            if (ed2) _edje_thaw_edje(ed2);
+         }
+     }
+   if ((ed->recalc) && (ed->freeze <= 0)) _edje_recalc_do(ed);
+}
+#endif
+
+/**
+ * @brief Thaw edje objects.
+ *
+ * This function thaw all edje object in the current process.
+ *
+ * See edje_object_thaw().
+ *
+ */
+EAPI void
+edje_thaw(void)
+{
+#ifdef FASTFREEZE
+   _edje_freeze_val--;
+   INF("fr -- ->%i", _edje_freeze_val);
+   if ((_edje_freeze_val <= 0) && (_edje_freeze_calc_count > 0))
+     {
+        Edje *ed;
+
+       _edje_freeze_calc_count = 0;
+       EINA_LIST_FREE(_edje_freeze_calc_list, ed)
+         {
+            _edje_thaw_edje(ed);
+             ed->freeze_calc = 0;
+         }
+     }
+#else   
+  Evas_Object *data;
+
+// FIXME: could just have a global freeze instead of per object
+// comment as above.. why?
+   Eina_List *l;
+
+   EINA_LIST_FOREACH(_edje_edjes, l, data)
+     edje_object_thaw(data);
+#endif
+}
+
+/**
+ * @brief Set the edje append fontset.
+ *
+ * @param fonts The fontset to append.
+ *
+ * This function sets the edje append fontset.
+ *
+ */
+EAPI void
+edje_fontset_append_set(const char *fonts)
+{
+   if (_edje_fontset_append)
+     free(_edje_fontset_append);
+   _edje_fontset_append = fonts ? strdup(fonts) : NULL;
+}
+
+/**
+ * @brief Get the edje append fontset.
+ *
+ * @return The edje append fontset.
+ *
+ * This function returns the edje append fontset set by
+ * edje_fontset_append_set() function.
+ *
+ * @see edje_fontset_append_set().
+ *
+ */
+EAPI const char *
+edje_fontset_append_get(void)
+{
+   return _edje_fontset_append;
+}
+
+/**
+ * @brief Set edje's global scaling factor.
+ *
+ * @param scale The edje (global) scale factor. The defaul is 1.0.
+ *
+ * Edje allows one to build scalable interfaces. Scale factors, which
+ * are set to neutral values by default (no scaling, actual sizes),
+ * are of two types: global and individual. Edje's global scaling
+ * factor will affect all its objects which hadn't their individual
+ * scaling factors altered from the default value. If they had it set
+ * differently, that factor will override the global one.
+ *
+ * Scaling affects the values of min/max object sizes, which are
+ * multiplied by it. Font sizes are scaled, too.
+ *
+ * This property can be retrieved with edje_scale_get().
+ *
+ * @see edje_scale_get().
+ *
+ */
+EAPI void
+edje_scale_set(double scale)
+{
+  Eina_List *l;
+   Evas_Object *data;
+
+   if (_edje_scale == FROM_DOUBLE(scale)) return;
+   _edje_scale = FROM_DOUBLE(scale);
+   EINA_LIST_FOREACH(_edje_edjes, l, data)
+     edje_object_calc_force(data);
+}
+
+/**
+ * @brief Get edje's global scaling factor.
+ *
+ * @return The edje (global) scale factor. The defaul is 1.0.
+ *
+ * This function returns edje's global scale factor, which can be set
+ * by edje_scale_set().
+ *
+ * @see edje_scale_set().
+ *
+ */
+EAPI double
+edje_scale_get(void)
+{
+  return TO_DOUBLE(_edje_scale);
+}
+
+/**
+ * @brief Set the edje object's scaling factor.
+ *
+ * @param obj The edje object's reference.
+ * @param scale The edje object scale factor. The defaul is 1.0.
+ *
+ * This function sets the individual scale factor of the @a obj edje
+ * object. This property (or edje's global scale factor, when
+ * applicable), will affect this object's parts. However, only parts
+ * which, at the EDC language level, were declared which the "scale"
+ * attribute set to 1 (default is zero) will be affected.
+ *
+ * This scale factor can be retrieved with edje_object_scale_get().
+ * @see edje_object_scale_get().
+ *
+ */
+EAPI Eina_Bool
+edje_object_scale_set(Evas_Object *obj, double scale)
+{
+   Edje *ed;
+
+   ed = _edje_fetch(obj);
+   if (!ed) return EINA_FALSE;
+   if (ed->scale == scale) return EINA_TRUE;
+   ed->scale = FROM_DOUBLE(scale);
+   edje_object_calc_force(obj);
+   return EINA_TRUE;
+}
+
+/**
+ * @brief Get the edje object's scaling factor.
+ *
+ * @param obj The edje object's reference.
+ *
+ * This function returns the individual scale factor of the @a obj
+ * edje object, which can be set by edje_object_scale_set().
+ *
+ * @see edje_object_scale_set().
+ *
+ */
+EAPI double
+edje_object_scale_get(const Evas_Object *obj)
+{
+   Edje *ed;
+
+   ed = _edje_fetch(obj);
+   if (!ed) return 0.0;
+   return TO_DOUBLE(ed->scale);
+}
+
+/**
+ * @brief Get Edje object data.
+ *
+ * @param obj A valid Evas_Object handle
+ * @param key The data key
+ * @return The data string
+ *
+ * This function fetches data specified at the object level.
+ *
+ * In EDC this comes from a data block within the group block that @a
+ * obj was loaded from. E.g.
+ *
+ * @code
+ * collections {
+ *   group {
+ *     name: "a_group";
+ *     data {
+ *      item: "key1" "value1";
+ *      item: "key2" "value2";
+ *     }
+ *   }
+ * }
+ * @endcode
+ */
+EAPI const char *
+edje_object_data_get(const Evas_Object *obj, const char *key)
+{
+   Edje *ed;
+   Eina_List *l;
+   Edje_Data *di;
+
+   ed = _edje_fetch(obj);
+   if ((!ed) || (!key))
+     return NULL;
+   if (!ed->collection) return NULL;
+   EINA_LIST_FOREACH(ed->collection->data, l, di)
+     if ((di->key) && (!strcmp(di->key, key)))
+       return (const char *)di->value;
+   return NULL;
+}
+
+/**
+ * @brief Freeze object.
+ *
+ * @param obj A valid Evas_Object handle
+ * @return The frozen state or 0 on Error
+ *
+ * This function puts all changes on hold. Successive freezes will
+ * nest, requiring an equal number of thaws.
+ *
+ */
+EAPI int
+edje_object_freeze(Evas_Object *obj)
+{
+   Edje *ed;
+   int i;
+
+   ed = _edje_fetch(obj);
+   if (!ed) return 0;
+   for (i = 0; i < ed->table_parts_size; i++)
+     {
+       Edje_Real_Part *rp;
+       rp = ed->table_parts[i];
+       if (rp->part->type == EDJE_PART_TYPE_GROUP && rp->swallowed_object)
+         edje_object_freeze(rp->swallowed_object);
+     }
+   return _edje_freeze(ed);
+}
+
+/**
+ * @brief Thaw object.
+ *
+ * @param obj A valid Evas_Object handle
+ * @return The frozen state or 0 on Error
+ *
+ * This allows frozen changes to occur.
+ *
+ */
+EAPI int
+edje_object_thaw(Evas_Object *obj)
+{
+   Edje *ed;
+   int i;
+
+   ed = _edje_fetch(obj);
+   if (!ed) return 0;
+   for (i = 0; i < ed->table_parts_size; i++)
+     {
+       Edje_Real_Part *rp;
+
+       rp = ed->table_parts[i];
+       if (rp->part->type == EDJE_PART_TYPE_GROUP && rp->swallowed_object)
+         edje_object_thaw(rp->swallowed_object);
+     }
+   return _edje_thaw(ed);
+}
+
+/**
+ * @brief Set Edje color class.
+ *
+ * @param color_class
+ * @param r Object Red value
+ * @param g Object Green value
+ * @param b Object Blue value
+ * @param a Object Alpha value
+ * @param r2 Outline Red value
+ * @param g2 Outline Green value
+ * @param b2 Outline Blue value
+ * @param a2 Outline Alpha value
+ * @param r3 Shadow Red value
+ * @param g3 Shadow Green value
+ * @param b3 Shadow Blue value
+ * @param a3 Shadow Alpha value
+ *
+ * This function sets the color values for a process level color
+ * class.  This will cause all edje parts in the current process that
+ * have the specified color class to have their colors multiplied by
+ * these values.  (Object level color classes set by
+ * edje_object_color_class_set() will override the values set by this
+ * function).
+ *
+ * The first color is the object, the second is the text outline, and
+ * the third is the text shadow. (Note that the second two only apply
+ * to text parts).
+ *
+ * Setting color emits a signal "color_class,set" with source being
+ * the given color class in all objects.
+ *
+ * @see edje_color_class_set().
+ *
+ * @note unlike Evas, Edje colors are @b not pre-multiplied. That is,
+ *       half-transparent white is 255 255 255 128.
+ */
+EAPI Eina_Bool
+edje_color_class_set(const char *color_class, int r, int g, int b, int a, int r2, int g2, int b2, int a2, int r3, int g3, int b3, int a3)
+{
+   Eina_List *members;
+   Edje_Color_Class *cc;
+
+   if (!color_class) return EINA_FALSE;
+
+   cc = eina_hash_find(_edje_color_class_hash, color_class);
+   if (!cc)
+     {
+        cc = calloc(1, sizeof(Edje_Color_Class));
+       if (!cc) return EINA_FALSE;
+       cc->name = eina_stringshare_add(color_class);
+       if (!cc->name)
+         {
+            free(cc);
+            return EINA_FALSE;
+         }
+       if (!_edje_color_class_hash) 
+          _edje_color_class_hash = eina_hash_string_superfast_new(NULL);
+        eina_hash_add(_edje_color_class_hash, color_class, cc);
+     }
+
+   if (r < 0)        r = 0;
+   else if (r > 255) r = 255;
+   if (g < 0)        g = 0;
+   else if (g > 255) g = 255;
+   if (b < 0)        b = 0;
+   else if (b > 255) b = 255;
+   if (a < 0)        a = 0;
+   else if (a > 255) a = 255;
+   if ((cc->r == r) && (cc->g == g) &&
+       (cc->b == b) && (cc->a == a) &&
+       (cc->r2 == r2) && (cc->g2 == g2) &&
+       (cc->b2 == b2) && (cc->a2 == a2) &&
+       (cc->r3 == r3) && (cc->g3 == g3) &&
+       (cc->b3 == b3) && (cc->a3 == a3))
+     return EINA_TRUE;
+   cc->r = r;
+   cc->g = g;
+   cc->b = b;
+   cc->a = a;
+   cc->r2 = r2;
+   cc->g2 = g2;
+   cc->b2 = b2;
+   cc->a2 = a2;
+   cc->r3 = r3;
+   cc->g3 = g3;
+   cc->b3 = b3;
+   cc->a3 = a3;
+
+   members = eina_hash_find(_edje_color_class_member_hash, color_class);
+   while (members)
+     {
+       Edje *ed;
+
+       ed = eina_list_data_get(members);
+       ed->dirty = 1;
+#ifdef EDJE_CALC_CACHE
+       ed->all_part_change = 1;
+#endif
+       _edje_recalc(ed);
+       _edje_emit(ed, "color_class,set", color_class);
+       members = eina_list_next(members);
+     }
+   return EINA_TRUE;
+}
+
+/**
+ * @brief Get Edje color class.
+ *
+ * @param color_class
+ * @param r Object Red value
+ * @param g Object Green value
+ * @param b Object Blue value
+ * @param a Object Alpha value
+ * @param r2 Outline Red value
+ * @param g2 Outline Green value
+ * @param b2 Outline Blue value
+ * @param a2 Outline Alpha value
+ * @param r3 Shadow Red value
+ * @param g3 Shadow Green value
+ * @param b3 Shadow Blue value
+ * @param a3 Shadow Alpha value
+ *
+ * @return EINA_TRUE if found or EINA_FALSE if not found and all
+ *         values are zeroed.
+ *
+ * This function gets the color values for a process level color
+ * class. This value is the globally set and not per-object, that is,
+ * the value that would be used by objects if they did not override with
+ * edje_object_color_class_set().
+ *
+ * The first color is the object, the second is the text outline, and
+ * the third is the text shadow. (Note that the second two only apply
+ * to text parts).
+ *
+ * @see edje_color_class_set().
+ *
+ * @note unlike Evas, Edje colors are @b not pre-multiplied. That is,
+ *       half-transparent white is 255 255 255 128.
+ */
+EAPI Eina_Bool
+edje_color_class_get(const char *color_class, int *r, int *g, int *b, int *a, int *r2, int *g2, int *b2, int *a2, int *r3, int *g3, int *b3, int *a3)
+{
+   Edje_Color_Class *cc;
+
+   if (!color_class)
+     cc = NULL;
+   else
+     cc = eina_hash_find(_edje_color_class_hash, color_class);
+
+   if (cc)
+     {
+#define X(C) if (C) *C = cc->C
+#define S(_r, _g, _b, _a) X(_r); X(_g); X(_b); X(_a)
+       S(r, g, b, a);
+       S(r2, g2, b2, a2);
+       S(r3, g3, b3, a3);
+#undef S
+#undef X
+       return EINA_TRUE;
+     }
+   else
+     {
+#define X(C) if (C) *C = 0
+#define S(_r, _g, _b, _a) X(_r); X(_g); X(_b); X(_a)
+       S(r, g, b, a);
+       S(r2, g2, b2, a2);
+       S(r3, g3, b3, a3);
+#undef S
+#undef X
+       return EINA_FALSE;
+     }
+}
+
+/**
+ * @brief Delete edje color class.
+ *
+ * @param color_class
+ *
+ * This function deletes any values at the process level for the
+ * specified color class.
+ *
+ * Deleting color emits a signal "color_class,del" with source being
+ * the given color class in all objects.
+ */
+void
+edje_color_class_del(const char *color_class)
+{
+   Edje_Color_Class *cc;
+   Eina_List *members;
+
+   if (!color_class) return;
+
+   cc = eina_hash_find(_edje_color_class_hash, color_class);
+   if (!cc) return;
+
+   eina_hash_del(_edje_color_class_hash, color_class, cc);
+   eina_stringshare_del(cc->name);
+   free(cc);
+
+   members = eina_hash_find(_edje_color_class_member_hash, color_class);
+   while (members)
+     {
+       Edje *ed;
+
+       ed = eina_list_data_get(members);
+       ed->dirty = 1;
+#ifdef EDJE_CALC_CACHE
+       ed->all_part_change = 1;
+#endif
+       _edje_recalc(ed);
+       _edje_emit(ed, "color_class,del", color_class);
+       members = eina_list_next(members);
+     }
+}
+
+/**
+ * @brief Lists color classes.
+ *
+ * @return A list of color class names (strings). These strings and
+ * the list must be free()'d by the caller.
+ *
+ * This function lists all color classes known about by the current
+ * process.
+ *
+ */
+Eina_List *
+edje_color_class_list(void)
+{
+   Edje_List_Foreach_Data fdata;
+
+   memset(&fdata, 0, sizeof(Edje_List_Foreach_Data));
+   eina_hash_foreach(_edje_color_class_member_hash,
+                     _edje_color_class_list_foreach, &fdata);
+
+   return fdata.list;
+}
+
+static Eina_Bool
+_edje_color_class_list_foreach(const Eina_Hash *hash __UNUSED__, const void *key, void *data __UNUSED__, void *fdata)
+{
+   Edje_List_Foreach_Data *fd;
+
+   fd = fdata;
+   fd->list = eina_list_append(fd->list, strdup(key));
+   return EINA_TRUE;
+}
+
+/**
+ * @brief Sets the object color class.
+ *
+ * @param obj A valid Evas_Object handle
+ * @param color_class
+ * @param r Object Red value
+ * @param g Object Green value
+ * @param b Object Blue value
+ * @param a Object Alpha value
+ * @param r2 Outline Red value
+ * @param g2 Outline Green value
+ * @param b2 Outline Blue value
+ * @param a2 Outline Alpha value
+ * @param r3 Shadow Red value
+ * @param g3 Shadow Green value
+ * @param b3 Shadow Blue value
+ * @param a3 Shadow Alpha value
+ *
+ * This function sets the color values for an object level color
+ * class. This will cause all edje parts in the specified object that
+ * have the specified color class to have their colors multiplied by
+ * these values.
+ *
+ * The first color is the object, the second is the text outline, and
+ * the third is the text shadow. (Note that the second two only apply
+ * to text parts).
+ *
+ * Setting color emits a signal "color_class,set" with source being
+ * the given color.
+ *
+ * @note unlike Evas, Edje colors are @b not pre-multiplied. That is,
+ *       half-transparent white is 255 255 255 128.
+ */
+EAPI Eina_Bool
+edje_object_color_class_set(Evas_Object *obj, const char *color_class, int r, int g, int b, int a, int r2, int g2, int b2, int a2, int r3, int g3, int b3, int a3)
+{
+   Edje *ed;
+   Eina_List *l;
+   Edje_Color_Class *cc;
+   int i;
+
+   ed = _edje_fetch(obj);
+   if ((!ed) || (!color_class)) return EINA_FALSE;
+   if (r < 0)        r = 0;
+   else if (r > 255) r = 255;
+   if (g < 0)        g = 0;
+   else if (g > 255) g = 255;
+   if (b < 0)        b = 0;
+   else if (b > 255) b = 255;
+   if (a < 0)        a = 0;
+   else if (a > 255) a = 255;
+   color_class = eina_stringshare_add(color_class);
+   if (!color_class) return EINA_FALSE;
+   EINA_LIST_FOREACH(ed->color_classes, l, cc)
+     {
+       if (cc->name == color_class)
+         {
+            eina_stringshare_del(color_class);
+
+            if ((cc->r == r) && (cc->g == g) &&
+                (cc->b == b) && (cc->a == a) &&
+                (cc->r2 == r2) && (cc->g2 == g2) &&
+                (cc->b2 == b2) && (cc->a2 == a2) &&
+                (cc->r3 == r3) && (cc->g3 == g3) &&
+                (cc->b3 == b3) && (cc->a3 == a3))
+              return EINA_TRUE;
+            cc->r = r;
+            cc->g = g;
+            cc->b = b;
+            cc->a = a;
+            cc->r2 = r2;
+            cc->g2 = g2;
+            cc->b2 = b2;
+            cc->a2 = a2;
+            cc->r3 = r3;
+            cc->g3 = g3;
+            cc->b3 = b3;
+            cc->a3 = a3;
+            ed->dirty = 1;
+#ifdef EDJE_CALC_CACHE
+            ed->all_part_change = 1;
+#endif
+            _edje_recalc(ed);
+            return EINA_TRUE;
+         }
+     }
+   cc = malloc(sizeof(Edje_Color_Class));
+   if (!cc)
+     {
+       eina_stringshare_del(color_class);
+       return EINA_FALSE;
+     }
+   cc->name = color_class;
+   cc->r = r;
+   cc->g = g;
+   cc->b = b;
+   cc->a = a;
+   cc->r2 = r2;
+   cc->g2 = g2;
+   cc->b2 = b2;
+   cc->a2 = a2;
+   cc->r3 = r3;
+   cc->g3 = g3;
+   cc->b3 = b3;
+   cc->a3 = a3;
+   ed->color_classes = eina_list_append(ed->color_classes, cc);
+   ed->dirty = 1;
+#ifdef EDJE_CALC_CACHE
+   ed->all_part_change = 1;
+#endif
+
+   for (i = 0; i < ed->table_parts_size; i++)
+     {
+       Edje_Real_Part *rp;
+
+       rp = ed->table_parts[i];
+       if (rp->part->type == EDJE_PART_TYPE_GROUP && rp->swallowed_object)
+         edje_object_color_class_set(rp->swallowed_object, color_class, 
+                                      r, g, b, a, r2, g2, b2, a2, r3, g3, b3, 
+                                      a3);
+     }
+
+   _edje_recalc(ed);
+   _edje_emit(ed, "color_class,set", color_class);
+   return EINA_TRUE;
+}
+
+/**
+ * @brief Gets the object color class.
+ *
+ * @param obj A valid Evas_Object handle
+ * @param color_class
+ * @param r Object Red value
+ * @param g Object Green value
+ * @param b Object Blue value
+ * @param a Object Alpha value
+ * @param r2 Outline Red value
+ * @param g2 Outline Green value
+ * @param b2 Outline Blue value
+ * @param a2 Outline Alpha value
+ * @param r3 Shadow Red value
+ * @param g3 Shadow Green value
+ * @param b3 Shadow Blue value
+ * @param a3 Shadow Alpha value
+ *
+ * @return EINA_TRUE if found or EINA_FALSE if not found and all
+ *         values are zeroed.
+ *
+ * This function gets the color values for an object level color
+ * class. If no explicit object color is set, then global values will
+ * be used.
+ *
+ * The first color is the object, the second is the text outline, and
+ * the third is the text shadow. (Note that the second two only apply
+ * to text parts).
+ *
+ * @note unlike Evas, Edje colors are @b not pre-multiplied. That is,
+ *       half-transparent white is 255 255 255 128.
+ */
+EAPI Eina_Bool
+edje_object_color_class_get(const Evas_Object *obj, const char *color_class, int *r, int *g, int *b, int *a, int *r2, int *g2, int *b2, int *a2, int *r3, int *g3, int *b3, int *a3)
+{
+   Edje *ed = _edje_fetch(obj);
+   Edje_Color_Class *cc = _edje_color_class_find(ed, color_class);
+
+   if (cc)
+     {
+#define X(C) if (C) *C = cc->C
+#define S(_r, _g, _b, _a) X(_r); X(_g); X(_b); X(_a)
+       S(r, g, b, a);
+       S(r2, g2, b2, a2);
+       S(r3, g3, b3, a3);
+#undef S
+#undef X
+       return EINA_TRUE;
+     }
+   else
+     {
+#define X(C) if (C) *C = 0
+#define S(_r, _g, _b, _a) X(_r); X(_g); X(_b); X(_a)
+       S(r, g, b, a);
+       S(r2, g2, b2, a2);
+       S(r3, g3, b3, a3);
+#undef S
+#undef X
+       return EINA_FALSE;
+     }
+}
+
+/**
+ * @brief Delete the object color class.
+ *
+ * @param obj The edje object's reference.
+ * @param color_class The color class to be deleted.
+ *
+ * This function deletes any values at the object level for the
+ * specified object and color class.
+ *
+ * Deleting color emits a signal "color_class,del" with source being
+ * the given color.
+ */
+void
+edje_object_color_class_del(Evas_Object *obj, const char *color_class)
+{
+   Edje *ed;
+   Eina_List *l;
+   Edje_Color_Class *cc = NULL;
+   int i;
+
+   if (!color_class) return;
+
+   ed = _edje_fetch(obj);
+   EINA_LIST_FOREACH(ed->color_classes, l, cc)
+     {
+       if (!strcmp(cc->name, color_class))
+         {
+            ed->color_classes = eina_list_remove(ed->color_classes, cc);
+            eina_stringshare_del(cc->name);
+            free(cc);
+            return;
+         }
+     }
+
+   for (i = 0; i < ed->table_parts_size; i++)
+     {
+       Edje_Real_Part *rp;
+
+       rp = ed->table_parts[i];
+       if (rp->part->type == EDJE_PART_TYPE_GROUP && rp->swallowed_object)
+         edje_object_color_class_del(rp->swallowed_object, color_class);
+     }
+
+   ed->dirty = 1;
+#ifdef EDJE_CALC_CACHE
+   ed->all_part_change = 1;
+#endif
+   _edje_recalc(ed);
+   _edje_emit(ed, "color_class,del", color_class);
+}
+
+/**
+ * @brief Set the Edje text class.
+ *
+ * @param text_class The text class name
+ * @param font The font name
+ * @param size The font size
+ *
+ * This function sets updates all edje members which belong to this
+ * text class with the new font attributes.
+ *
+ * @see edje_text_class_get().
+ *
+ */
+EAPI Eina_Bool
+edje_text_class_set(const char *text_class, const char *font, Evas_Font_Size size)
+{
+   Eina_List *members;
+   Edje_Text_Class *tc;
+
+   if (!text_class) return EINA_FALSE;
+   if (!font) font = "";
+
+   tc = eina_hash_find(_edje_text_class_hash, text_class);
+   /* Create new text class */
+   if (!tc)
+     {
+        tc = calloc(1, sizeof(Edje_Text_Class));
+       if (!tc) return EINA_FALSE;
+       tc->name = eina_stringshare_add(text_class);
+       if (!tc->name)
+         {
+            free(tc);
+            return EINA_FALSE;
+         }
+       if (!_edje_text_class_hash) _edje_text_class_hash = eina_hash_string_superfast_new(NULL);
+        eina_hash_add(_edje_text_class_hash, text_class, tc);
+
+       tc->font = eina_stringshare_add(font);
+       tc->size = size;
+       return EINA_FALSE;
+     }
+
+   /* If the class found is the same just return */
+   if ((tc->size == size) && (tc->font) && (!strcmp(tc->font, font)))
+     return EINA_TRUE;
+
+   /* Update the class found */
+   eina_stringshare_del(tc->font);
+   tc->font = eina_stringshare_add(font);
+   if (!tc->font)
+     {
+        eina_hash_del(_edje_text_class_hash, text_class, tc);
+       free(tc);
+       return EINA_FALSE;
+     }
+   tc->size = size;
+
+   /* Tell all members of the text class to recalc */
+   members = eina_hash_find(_edje_text_class_member_hash, text_class);
+   while (members)
+     {
+       Edje *ed;
+
+       ed = eina_list_data_get(members);
+       ed->dirty = 1;
+       _edje_textblock_style_all_update(ed);
+#ifdef EDJE_CALC_CACHE
+       ed->text_part_change = 1;
+#endif
+       _edje_recalc(ed);
+       members = eina_list_next(members);
+     }
+   return EINA_TRUE;
+}
+
+/**
+ * @brief Delete the text class.
+ *
+ * @param text_class The text class name string
+ *
+ * This function deletes any values at the process level for the
+ * specified text class.
+ *
+ */
+void
+edje_text_class_del(const char *text_class)
+{
+   Edje_Text_Class *tc;
+   Eina_List *members;
+
+   if (!text_class) return;
+
+   tc = eina_hash_find(_edje_text_class_hash, text_class);
+   if (!tc) return;
+
+   eina_hash_del(_edje_text_class_hash, text_class, tc);
+   eina_stringshare_del(tc->name);
+   eina_stringshare_del(tc->font);
+   free(tc);
+
+   members = eina_hash_find(_edje_text_class_member_hash, text_class);
+   while (members)
+     {
+       Edje *ed;
+
+       ed = eina_list_data_get(members);
+       ed->dirty = 1;
+       _edje_textblock_style_all_update(ed);
+#ifdef EDJE_CALC_CACHE
+       ed->text_part_change = 1;
+#endif
+       _edje_recalc(ed);
+       members = eina_list_next(members);
+     }
+}
+
+/**
+ * @brief List text classes.
+ *
+ * @return A list of text class names (strings). These strings are
+ * stringshares and the list must be free()'d by the caller.
+ *
+ * This function lists all text classes known about by the current
+ * process.
+ *
+ */
+Eina_List *
+edje_text_class_list(void)
+{
+   Edje_List_Foreach_Data fdata;
+
+   memset(&fdata, 0, sizeof(Edje_List_Foreach_Data));
+   eina_hash_foreach(_edje_text_class_member_hash,
+                     _edje_text_class_list_foreach, &fdata);
+   return fdata.list;
+}
+
+static Eina_Bool
+_edje_text_class_list_foreach(const Eina_Hash *hash __UNUSED__, const void *key, void *data __UNUSED__, void *fdata)
+{
+   Edje_List_Foreach_Data *fd;
+
+   fd = fdata;
+   fd->list = eina_list_append(fd->list, eina_stringshare_add(key));
+   return EINA_TRUE;
+}
+
+/**
+ * @brief Sets Edje text class.
+ *
+ * @param obj A valid Evas_Object handle
+ * @param text_class The text class name
+ * @param font Font name
+ * @param size Font Size
+ *
+ * This function sets the text class for the Edje.
+ *
+ */
+EAPI Eina_Bool
+edje_object_text_class_set(Evas_Object *obj, const char *text_class, const char *font, Evas_Font_Size size)
+{
+   Edje *ed;
+   Eina_List *l;
+   Edje_Text_Class *tc;
+   int i;
+
+   ed = _edje_fetch(obj);
+   if ((!ed) || (!text_class)) return EINA_FALSE;
+
+   /* for each text_class in the edje */
+   EINA_LIST_FOREACH(ed->text_classes, l, tc)
+     {
+       if ((tc->name) && (!strcmp(tc->name, text_class)))
+         {
+            /* Match and the same, return */
+            if ((tc->font) && (font) && (!strcmp(tc->font, font)) &&
+                (tc->size == size))
+              return EINA_TRUE;
+
+            /* No font but size is the same, return */
+            if ((!tc->font) && (!font) && (tc->size == size)) return EINA_TRUE;
+
+            /* Update new text class properties */
+            if (tc->font) eina_stringshare_del(tc->font);
+            if (font) tc->font = eina_stringshare_add(font);
+            else tc->font = NULL;
+            tc->size = size;
+
+            /* Update edje */
+            ed->dirty = 1;
+#ifdef EDJE_CALC_CACHE
+            ed->text_part_change = 1;
+#endif
+            _edje_recalc(ed);
+            return EINA_TRUE;
+         }
+     }
+
+   /* No matches, create a new text class */
+   tc = calloc(1, sizeof(Edje_Text_Class));
+   if (!tc) return EINA_FALSE;
+   tc->name = eina_stringshare_add(text_class);
+   if (!tc->name)
+     {
+       free(tc);
+       return EINA_FALSE;
+     }
+   if (font) tc->font = eina_stringshare_add(font);
+   else tc->font = NULL;
+   tc->size = size;
+
+   for (i = 0; i < ed->table_parts_size; i++)
+     {
+       Edje_Real_Part *rp;
+
+       rp = ed->table_parts[i];
+       if (rp->part->type == EDJE_PART_TYPE_GROUP && rp->swallowed_object)
+         edje_object_text_class_set(rp->swallowed_object, text_class, 
+                                     font, size);
+     }
+
+   /* Add to edje's text class list */
+   ed->text_classes = eina_list_append(ed->text_classes, tc);
+   ed->dirty = 1;
+#ifdef EDJE_CALC_CACHE
+   ed->text_part_change = 1;
+#endif
+   _edje_textblock_style_all_update(ed);
+   _edje_recalc(ed);
+   return EINA_TRUE;
+}
+
+/**
+ * @brief Check if Edje part exists.
+ *
+ * @param obj A valid Evas_Object handle
+ * @param part The part name to check
+ *
+ * @return 0 on Error, 1 if Edje part exists.
+ *
+ * This function returns if a part exists in the edje.
+ *
+ */
+EAPI Eina_Bool
+edje_object_part_exists(const Evas_Object *obj, const char *part)
+{
+   Edje *ed;
+   Edje_Real_Part *rp;
+
+   ed = _edje_fetch(obj);
+   if ((!ed) || (!part)) return 0;
+   rp = _edje_real_part_recursive_get(ed, (char *)part);
+   if (!rp) return 0;
+   return 1;
+}
+
+/**
+ * @brief Gets the evas object from a part.
+ *
+ * @param obj A valid Evas_Object handle
+ * @param part The Edje part
+ * @return Returns the Evas_Object corresponding to the given part, or
+ * NULL on failure (if the part doesn't exist)
+ *
+ * This functio gets the Evas_Object corresponding to a given part.
+ *
+ * You should never modify the state of the returned object (with
+ * evas_object_move() or evas_object_hide() for example), but you can
+ * safely query info about its current state (with
+ * evas_object_visible_get() or evas_object_color_get() for example)
+ *
+ **/
+EAPI const Evas_Object *
+edje_object_part_object_get(const Evas_Object *obj, const char *part)
+{
+   Edje *ed;
+   Edje_Real_Part *rp;
+
+   ed = _edje_fetch(obj);
+   if ((!ed) || (!part)) return NULL;
+
+   /* Need to recalc before providing the object. */
+   _edje_recalc_do(ed);
+
+   rp = _edje_real_part_recursive_get(ed, (char *)part);
+   if (!rp) return NULL;
+   return rp->object;
+}
+
+/**
+ * @brief Get the geometry of an Edje part.
+ *
+ * @param obj A valid Evas_Object handle
+ * @param part The Edje part
+ * @param x The x coordinate pointer
+ * @param y The y coordinate pointer
+ * @param w The width pointer
+ * @param h The height pointer
+ *
+ * This function gets the geometry of an Edje part.
+ *
+ * It is valid to pass NULL as any of @a x, @a y, @a w or @a h, whose
+ * values you are uninterested in.
+ */
+EAPI Eina_Bool
+edje_object_part_geometry_get(const Evas_Object *obj, const char *part, Evas_Coord *x, Evas_Coord *y, Evas_Coord *w, Evas_Coord *h )
+{
+   Edje *ed;
+   Edje_Real_Part *rp;
+
+   ed = _edje_fetch(obj);
+   if ((!ed) || (!part))
+     {
+       if (x) *x = 0;
+       if (y) *y = 0;
+       if (w) *w = 0;
+       if (h) *h = 0;
+       return EINA_FALSE;
+     }
+
+   /* Need to recalc before providing the object. */
+   _edje_recalc_do(ed);
+
+   rp = _edje_real_part_recursive_get(ed, (char *)part);
+   if (!rp)
+     {
+       if (x) *x = 0;
+       if (y) *y = 0;
+       if (w) *w = 0;
+       if (h) *h = 0;
+       return EINA_FALSE;
+     }
+   if (x) *x = rp->x;
+   if (y) *y = rp->y;
+   if (w) *w = rp->w;
+   if (h) *h = rp->h;
+   return EINA_TRUE;
+}
+
+/* FIXDOC: New Function */
+/**
+ * @brief Set the object text callback.
+ *
+ * @param obj A valid Evas_Object handle
+ * @param func The callback function to handle the text change
+ * @param data The data associated to the callback function.
+ *
+ * This function gets the geometry of an Edje part
+ *
+ * It is valid to pass NULL as any of @a x, @a y, @a w or @a h, whose
+ * values you are uninterested in.
+ *
+ */
+EAPI void
+edje_object_text_change_cb_set(Evas_Object *obj, void (*func) (void *data, Evas_Object *obj, const char *part), void *data)
+{
+   Edje *ed;
+   int i;
+
+   ed = _edje_fetch(obj);
+   if (!ed) return;
+   ed->text_change.func = func;
+   ed->text_change.data = data;
+
+   for (i = 0; i < ed->table_parts_size; i++)
+     {
+       Edje_Real_Part *rp;
+
+       rp = ed->table_parts[i];
+       if (rp->part->type == EDJE_PART_TYPE_GROUP && rp->swallowed_object)
+         edje_object_text_change_cb_set(rp->swallowed_object, func, data);
+     }
+}
+
+Eina_Bool
+_edje_object_part_text_raw_set(Evas_Object *obj, Edje_Real_Part *rp, const char *part, const char *text)
+{
+   if ((!rp->text.text) && (!text))
+     return EINA_FALSE;
+   if ((rp->text.text) && (text) &&
+       (!strcmp(rp->text.text, text)))
+     return EINA_FALSE;
+   if (rp->text.text)
+     {
+       eina_stringshare_del(rp->text.text);
+       rp->text.text = NULL;
+     }
+   if (rp->part->entry_mode > EDJE_ENTRY_EDIT_MODE_NONE)
+     _edje_entry_text_markup_set(rp, text);
+   else
+     if (text) rp->text.text = eina_stringshare_add(text);
+   rp->edje->dirty = 1;
+#ifdef EDJE_CALC_CACHE
+   rp->invalidate = 1;
+#endif
+   _edje_recalc(rp->edje);
+   if (rp->edje->text_change.func)
+     rp->edje->text_change.func(rp->edje->text_change.data, obj, part);
+   return EINA_TRUE;
+}
+
+/** Sets the text for an object part
+ * @param obj A valid Evas Object handle
+ * @param part The part name
+ * @param text The text string
+ */
+EAPI Eina_Bool
+edje_object_part_text_set(Evas_Object *obj, const char *part, const char *text)
+{
+   Edje *ed;
+   Edje_Real_Part *rp;
+
+   ed = _edje_fetch(obj);
+   if ((!ed) || (!part)) return EINA_FALSE;
+   rp = _edje_real_part_recursive_get(ed, (char *)part);
+   if (!rp) return EINA_FALSE;
+   if ((rp->part->type != EDJE_PART_TYPE_TEXT) &&
+       (rp->part->type != EDJE_PART_TYPE_TEXTBLOCK)) return EINA_FALSE;
+   return _edje_object_part_text_raw_set(obj, rp, part, text);
+}
+
+/**
+ * @brief Return the text of the object part.
+ *
+ * @param obj A valid Evas_Object handle
+ * @param part The part name
+ *
+ * @return The text string
+ *
+ * This function returns the text associated to the object part.
+ *
+ */
+EAPI const char *
+edje_object_part_text_get(const Evas_Object *obj, const char *part)
+{
+   Edje *ed;
+   Edje_Real_Part *rp;
+
+   ed = _edje_fetch(obj);
+   if ((!ed) || (!part)) return NULL;
+
+   /* Need to recalc before providing the object. */
+   _edje_recalc_do(ed);
+
+   rp = _edje_real_part_recursive_get(ed, (char *)part);
+   if (!rp) return NULL;
+   if (rp->part->entry_mode > EDJE_ENTRY_EDIT_MODE_NONE)
+     return _edje_entry_text_get(rp);
+   else
+     {
+       if (rp->part->type == EDJE_PART_TYPE_TEXT) return rp->text.text;
+       if (rp->part->type == EDJE_PART_TYPE_TEXTBLOCK)
+         return evas_object_textblock_text_markup_get(rp->object);
+     }
+   return NULL;
+}
+
+char *
+_edje_text_escape(const char *text)
+{
+   Eina_Strbuf *txt;
+   char *ret;
+   const char *text_end;
+   size_t text_len;
+
+   if (!text) return NULL;
+
+   txt = eina_strbuf_new();
+   text_len = strlen(text);
+
+   text_end = text + text_len;
+   while (text < text_end)
+     {
+       int advance;
+       const char *escaped = evas_textblock_string_escape_get(text, &advance);
+       if (!escaped)
+         {
+            eina_strbuf_append_char(txt, text[0]);
+            advance = 1;
+         }
+       else
+         eina_strbuf_append(txt, escaped);
+
+       text += advance;
+     }
+
+   ret = eina_strbuf_string_steal(txt);
+   eina_strbuf_free(txt);
+   return ret;
+}
+
+char *
+_edje_text_unescape(const char *text)
+{
+   Eina_Strbuf *txt;
+   char *ret;
+   const char *text_end, *last, *escape_start;
+   size_t text_len;
+
+   if (!text) return NULL;
+
+   txt = eina_strbuf_new();
+   text_len = strlen(text);
+
+   text_end = text + text_len;
+   last = text;
+   escape_start = NULL;
+   for (; text < text_end; text++)
+     {
+       if (*text == '&')
+         {
+            size_t len;
+            const char *str;
+
+            if (last)
+              {
+                 len = text - last;
+                 str = last;
+              }
+            else
+              {
+                 len = text - escape_start;
+                 str = escape_start;
+              }
+
+            if (len > 0)
+              eina_strbuf_append_n(txt, str, len);
+
+            escape_start = text;
+            last = NULL;
+         }
+       else if ((*text == ';') && (escape_start))
+         {
+            size_t len;
+            const char *str = evas_textblock_escape_string_range_get(escape_start, text);
+
+            if (str)
+              len = strlen(str);
+            else
+              {
+                 str = escape_start;
+                 len = text + 1 - escape_start;
+              }
+
+            eina_strbuf_append_n(txt, str, len);
+
+            escape_start = NULL;
+            last = text + 1;
+         }
+     }
+
+   if (!last && escape_start)
+     last = escape_start;
+
+   if (last && (text > last))
+     {
+       size_t len = text - last;
+       eina_strbuf_append_n(txt, last, len);
+     }
+
+   ret = eina_strbuf_string_steal(txt);
+   eina_strbuf_free(txt);
+   return ret;
+}
+
+/**
+ * @brief Sets the raw (non escaped) text for an object part.
+ *
+ * @param obj A valid Evas Object handle
+ * @param part The part name
+ * @param text_to_escape The text string
+ *
+ * This funciton will do escape for you if it is a TEXTBLOCK part,
+ * that is, if text contain tags, these tags will not be
+ * interpreted/parsed by TEXTBLOCK.
+ *
+ * @see edje_object_part_text_unescaped_get().
+ *
+ */
+EAPI Eina_Bool
+edje_object_part_text_unescaped_set(Evas_Object *obj, const char *part, const char *text_to_escape)
+{
+   Edje *ed;
+   Edje_Real_Part *rp;
+   Eina_Bool ret = EINA_FALSE;
+
+   ed = _edje_fetch(obj);
+   if ((!ed) || (!part)) return ret;
+   rp = _edje_real_part_recursive_get(ed, part);
+   if (!rp) return ret;
+   if (rp->part->type == EDJE_PART_TYPE_TEXT)
+     ret = _edje_object_part_text_raw_set(obj, rp, part, text_to_escape);
+   else if (rp->part->type == EDJE_PART_TYPE_TEXTBLOCK)
+     {
+       char *text = _edje_text_escape(text_to_escape);
+
+       ret = _edje_object_part_text_raw_set(obj, rp, part, text);
+       free(text);
+     }
+   return ret;
+}
+
+/**
+ * @brief Returns the text of the object part, without escaping.
+ *
+ * @param obj A valid Evas_Object handle
+ * @param part The part name
+ * @return The @b allocated text string without escaping, or NULL on
+ * problems.
+ *
+ * This function is the counterpart of
+ * edje_object_part_text_unescaped_set(). Please notice that the
+ * result is newly allocated memory and should be released with free()
+ * when done.
+ *
+ * @see edje_object_part_text_unescaped_set().
+ *
+ */
+EAPI char *
+edje_object_part_text_unescaped_get(const Evas_Object *obj, const char *part)
+{
+   Edje *ed;
+   Edje_Real_Part *rp;
+
+   ed = _edje_fetch(obj);
+   if ((!ed) || (!part)) return NULL;
+
+   /* Need to recalc before providing the object. */
+   _edje_recalc_do(ed);
+
+   rp = _edje_real_part_recursive_get(ed, (char *)part);
+   if (!rp) return NULL;
+   if (rp->part->entry_mode > EDJE_ENTRY_EDIT_MODE_NONE)
+     {
+       const char *t = _edje_entry_text_get(rp);
+       return _edje_text_unescape(t);
+     }
+   else
+     {
+       if (rp->part->type == EDJE_PART_TYPE_TEXT) return strdup(rp->text.text);
+       if (rp->part->type == EDJE_PART_TYPE_TEXTBLOCK)
+         {
+            const char *t = evas_object_textblock_text_markup_get(rp->object);
+            return _edje_text_unescape(t);
+         }
+     }
+   return NULL;
+}
+
+/**
+ * @brief Return the selection text of the object part.
+ *
+ * @param obj A valid Evas_Object handle
+ * @param part The part name
+ * @return The text string
+ *
+ * This function returns selection text of the object part.
+ *
+ */
+EAPI const char *
+edje_object_part_text_selection_get(const Evas_Object *obj, const char *part)
+{
+   Edje *ed;
+   Edje_Real_Part *rp;
+
+   ed = _edje_fetch(obj);
+   if ((!ed) || (!part)) return NULL;
+   rp = _edje_real_part_recursive_get(ed, (char *)part);
+   if (!rp) return NULL;
+   if (rp->part->entry_mode > EDJE_ENTRY_EDIT_MODE_NONE)
+     return _edje_entry_selection_get(rp);
+   return NULL;
+}
+
+/**
+ * @brief Set the selection to be none.
+ *
+ * @param obj A valid Evas_Object handle
+ * @param part The part name
+ *
+ * This function sets the selection text to be none.
+ *
+ */
+EAPI void
+edje_object_part_text_select_none(const Evas_Object *obj, const char *part)
+{
+   Edje *ed;
+   Edje_Real_Part *rp;
+
+   ed = _edje_fetch(obj);
+   if ((!ed) || (!part)) return;
+   rp = _edje_real_part_recursive_get(ed, (char *)part);
+   if (!rp) return;
+   if (rp->part->entry_mode > EDJE_ENTRY_EDIT_MODE_NONE)
+     _edje_entry_select_none(rp);
+}
+
+/**
+ * @brief Set the selection to be everything.
+ *
+ * @param obj A valid Evas_Object handle
+ * @param part The part name
+ *
+ * This function selects all text of the object of the part.
+ *
+ */
+EAPI void
+edje_object_part_text_select_all(const Evas_Object *obj, const char *part)
+{
+   Edje *ed;
+   Edje_Real_Part *rp;
+
+   ed = _edje_fetch(obj);
+   if ((!ed) || (!part)) return;
+   rp = _edje_real_part_recursive_get(ed, (char *)part);
+   if (!rp) return;
+   if (rp->part->entry_mode > EDJE_ENTRY_EDIT_MODE_NONE)
+     _edje_entry_select_all(rp);
+}
+
+/**
+ * @brief Insert text for an object part.
+ *
+ * @param obj A valid Evas Object handle
+ * @param part The part name
+ * @param text The text string
+ *
+ * This function inserts the text for an object part just before the
+ * cursor position.
+ *
+ */
+EAPI void
+edje_object_part_text_insert(Evas_Object *obj, const char *part, const char *text)
+{
+   Edje *ed;
+   Edje_Real_Part *rp;
+
+   ed = _edje_fetch(obj);
+   if ((!ed) || (!part)) return;
+   rp = _edje_real_part_recursive_get(ed, (char *)part);
+   if (!rp) return;
+   if ((rp->part->type != EDJE_PART_TYPE_TEXTBLOCK)) return;
+   if (rp->part->entry_mode <= EDJE_ENTRY_EDIT_MODE_NONE) return;
+   _edje_entry_text_markup_insert(rp, text);
+   rp->edje->dirty = 1;
+#ifdef EDJE_CALC_CACHE
+   rp->invalidate = 1;
+#endif
+   _edje_recalc(rp->edje);
+   if (rp->edje->text_change.func)
+     rp->edje->text_change.func(rp->edje->text_change.data, obj, part);
+}
+
+/**
+ * @brief Set the function that provides item objects for named items in an edje entry text
+ * 
+ * @param obj A valid Evas Object handle
+ * @param func The function to call (or NULL to disable) to get item objects
+ * @param data The data pointer to pass to the @p func callback
+ * 
+ * Item objects may be deleted any time by Edje, and will be deleted when the
+ * Edje object is deleted (or file is set to a new file).
+ */
+EAPI void
+edje_object_item_provider_set(Evas_Object *obj, Evas_Object *(*func) (void *data, Evas_Object *obj, const char *part, const char *item), void *data)
+{
+   Edje *ed;
+
+   ed = _edje_fetch(obj);
+   if (!ed) return;
+   ed->item_provider.func = func;
+   ed->item_provider.data = data;
+}
+
+/**
+ * @brief Return a list of char anchor names.
+ *
+ * @param obj A valid Evas_Object handle
+ * @param part The part name
+ *
+ * @return The list of anchors (const char *), do not modify!
+ *
+ * This function returns a list of char anchor names.
+ *
+ */
+EAPI const Eina_List *
+edje_object_part_text_anchor_list_get(const Evas_Object *obj, const char *part)
+{
+   Edje *ed;
+   Edje_Real_Part *rp;
+
+   ed = _edje_fetch(obj);
+   if ((!ed) || (!part)) return NULL;
+   rp = _edje_real_part_recursive_get(ed, (char *)part);
+   if (!rp) return NULL;
+   if (rp->part->entry_mode > EDJE_ENTRY_EDIT_MODE_NONE)
+     return _edje_entry_anchors_list(rp);
+   return NULL;
+}
+
+/**
+ * @brief Return a list of Evas_Textblock_Rectangle anchor rectangles.
+ *
+ * @param obj A valid Evas_Object handle
+ * @param part The part name
+ * @param anchor The anchor name
+ *
+ * @return The list of anchor rects (const Evas_Textblock_Rectangle
+ * *), do not modify! Geometry is relative to entry part.
+ *
+ * This function return a list of Evas_Textblock_Rectangle anchor
+ * rectangles.
+ *
+ */
+EAPI const Eina_List *
+edje_object_part_text_anchor_geometry_get(const Evas_Object *obj, const char *part, const char *anchor)
+{
+   Edje *ed;
+   Edje_Real_Part *rp;
+
+   ed = _edje_fetch(obj);
+   if ((!ed) || (!part)) return NULL;
+   rp = _edje_real_part_recursive_get(ed, (char *)part);
+   if (!rp) return NULL;
+   if (rp->part->entry_mode > EDJE_ENTRY_EDIT_MODE_NONE)
+     return _edje_entry_anchor_geometry_get(rp, anchor);
+   return NULL;
+}
+
+/**
+ * @brief Return a list of char item names.
+ *
+ * @param obj A valid Evas_Object handle
+ * @param part The part name
+ *
+ * @return The list of items (const char *), do not modify!
+ *
+ * This function returns a list of char item names.
+ *
+ */
+EAPI const Eina_List *
+edje_object_part_text_item_list_get(const Evas_Object *obj, const char *part)
+{
+   Edje *ed;
+   Edje_Real_Part *rp;
+
+   ed = _edje_fetch(obj);
+   if ((!ed) || (!part)) return NULL;
+   rp = _edje_real_part_recursive_get(ed, (char *)part);
+   if (!rp) return NULL;
+   if (rp->part->entry_mode > EDJE_ENTRY_EDIT_MODE_NONE)
+     return _edje_entry_items_list(rp);
+   return NULL;
+}
+
+/**
+ * @brief Return item geometry.
+ *
+ * @param obj A valid Evas_Object handle
+ * @param part The part name
+ * @param item The item name
+ * @param cx Item x return (relative to entry part)
+ * @param cy Item y return (relative to entry part)
+ * @param cw Item width return
+ * @param ch Item height return
+ *
+ * @return 1 if item exists, 0 if not
+ *
+ * This function return a list of Evas_Textblock_Rectangle item
+ * rectangles.
+ *
+ */
+EAPI Eina_Bool
+edje_object_part_text_item_geometry_get(const Evas_Object *obj, const char *part, const char *item, Evas_Coord *cx, Evas_Coord *cy, Evas_Coord *cw, Evas_Coord *ch)
+{
+   Edje *ed;
+   Edje_Real_Part *rp;
+
+   ed = _edje_fetch(obj);
+   if ((!ed) || (!part)) return 0;
+   rp = _edje_real_part_recursive_get(ed, (char *)part);
+   if (!rp) return 0;
+   if (rp->part->entry_mode > EDJE_ENTRY_EDIT_MODE_NONE)
+     return _edje_entry_item_geometry_get(rp, item, cx, cy, cw, ch);
+   return 0;
+}
+
+/**
+ * @brief Returns the cursor geometry of the part relative to the edje
+ * object.
+ *
+ * @param obj A valid Evas_Object handle
+ * @param part The part name
+ * @param x Cursor X position
+ * @param y Cursor Y position
+ * @param w Cursor width
+ * @param h Cursor height
+ *
+ */
+EAPI void
+edje_object_part_text_cursor_geometry_get(const Evas_Object *obj, const char *part, Evas_Coord *x, Evas_Coord *y, Evas_Coord *w, Evas_Coord *h)
+{
+   Edje *ed;
+   Edje_Real_Part *rp;
+
+   ed = _edje_fetch(obj);
+   if (x) *x = 0;
+   if (y) *y = 0;
+   if (w) *w = 0;
+   if (h) *h = 0;
+   if ((!ed) || (!part)) return;
+   rp = _edje_real_part_recursive_get(ed, (char *)part);
+   if (!rp) return;
+   if (rp->part->entry_mode > EDJE_ENTRY_EDIT_MODE_NONE)
+     {
+       _edje_entry_cursor_geometry_get(rp, x, y, w, h);
+       if (x) *x -= rp->edje->x;
+       if (y) *y -= rp->edje->y;
+     }
+   return;
+}
+
+/**
+ * @brief Enables selection if the entry is an EXPLICIT selection mode
+ * type.
+ *
+ * @param obj A valid Evas_Object handle
+ * @param part The part name
+ * @param allow EINA_TRUE to enable, EINA_FALSE otherwise
+ */
+EAPI void
+edje_object_part_text_select_allow_set(const Evas_Object *obj, const char *part, Eina_Bool allow)
+{
+   Edje *ed;
+   Edje_Real_Part *rp;
+
+   ed = _edje_fetch(obj);
+   if ((!ed) || (!part)) return;
+   rp = _edje_real_part_recursive_get(ed, (char *)part);
+   if (!rp) return;
+   if (rp->part->entry_mode > EDJE_ENTRY_EDIT_MODE_NONE)
+     _edje_entry_select_allow_set(rp, allow);
+}
+
+/**
+ * @brief Aborts any selection action on a part.
+ *
+ * @param obj A valid Evas_Object handle
+ * @param part The part name
+ */
+EAPI void
+edje_object_part_text_select_abort(const Evas_Object *obj, const char *part)
+{
+   Edje *ed;
+   Edje_Real_Part *rp;
+
+   ed = _edje_fetch(obj);
+   if ((!ed) || (!part)) return;
+   rp = _edje_real_part_recursive_get(ed, (char *)part);
+   if (!rp) return;
+   if (rp->part->entry_mode > EDJE_ENTRY_EDIT_MODE_NONE)
+     _edje_entry_select_abort(rp);
+}
+
+/**
+ * @brief Starts selecting at current cursor position
+ *
+ * @param obj A valid Evas_Object handle
+ * @param part The part name
+ */
+EAPI void
+edje_object_part_text_select_begin(const Evas_Object *obj, const char *part)
+{
+   Edje *ed;
+   Edje_Real_Part *rp;
+
+   ed = _edje_fetch(obj);
+   if ((!ed) || (!part)) return;
+   rp = _edje_real_part_recursive_get(ed, (char *)part);
+   if (!rp) return;
+   if (rp->part->entry_mode > EDJE_ENTRY_EDIT_MODE_NONE)
+     _edje_entry_select_begin(rp);
+}
+
+/**
+ * @brief Extends the current selection to the current cursor position
+ *
+ * @param obj A valid Evas_Object handle
+ * @param part The part name
+ */
+EAPI void
+edje_object_part_text_select_extend(const Evas_Object *obj, const char *part)
+{
+   Edje *ed;
+   Edje_Real_Part *rp;
+
+   ed = _edje_fetch(obj);
+   if ((!ed) || (!part)) return;
+   rp = _edje_real_part_recursive_get(ed, (char *)part);
+   if (!rp) return;
+   if (rp->part->entry_mode > EDJE_ENTRY_EDIT_MODE_NONE)
+     _edje_entry_select_extend(rp);
+}
+
+/**
+ * @brief XX
+ * 
+ * @param obj A valid Evas_Object handle
+ * @param part The part name
+ */
+EAPI Eina_Bool
+edje_object_part_text_cursor_next(const Evas_Object *obj, const char *part, Edje_Cursor cur)
+{
+   Edje *ed;
+   Edje_Real_Part *rp;
+
+   ed = _edje_fetch(obj);
+   if ((!ed) || (!part)) return 0;
+   rp = _edje_real_part_recursive_get(ed, (char *)part);
+   if (!rp) return 0;
+   if (rp->part->entry_mode > EDJE_ENTRY_EDIT_MODE_NONE)
+     {
+        return _edje_entry_cursor_next(rp, cur);
+     }
+   return 0;
+}
+
+/**
+ * @brief XX
+ * 
+ * @param obj A valid Evas_Object handle
+ * @param part The part name
+ */
+EAPI Eina_Bool
+edje_object_part_text_cursor_prev(const Evas_Object *obj, const char *part, Edje_Cursor cur)
+{
+   Edje *ed;
+   Edje_Real_Part *rp;
+
+   ed = _edje_fetch(obj);
+   if ((!ed) || (!part)) return 0;
+   rp = _edje_real_part_recursive_get(ed, (char *)part);
+   if (!rp) return 0;
+   if (rp->part->entry_mode > EDJE_ENTRY_EDIT_MODE_NONE)
+     {
+        return _edje_entry_cursor_prev(rp, cur);
+     }
+   return 0;
+}
+
+/**
+ * @brief XX
+ * 
+ * @param obj A valid Evas_Object handle
+ * @param part The part name
+ */
+EAPI Eina_Bool
+edje_object_part_text_cursor_up(const Evas_Object *obj, const char *part, Edje_Cursor cur)
+{
+   Edje *ed;
+   Edje_Real_Part *rp;
+
+   ed = _edje_fetch(obj);
+   if ((!ed) || (!part)) return 0;
+   rp = _edje_real_part_recursive_get(ed, (char *)part);
+   if (!rp) return 0;
+   if (rp->part->entry_mode > EDJE_ENTRY_EDIT_MODE_NONE)
+     {
+        return _edje_entry_cursor_up(rp, cur);
+     }
+   return 0;
+}
+
+/**
+ * @brief XX
+ * 
+ * @param obj A valid Evas_Object handle
+ * @param part The part name
+ */
+EAPI Eina_Bool
+edje_object_part_text_cursor_down(const Evas_Object *obj, const char *part, Edje_Cursor cur)
+{
+   Edje *ed;
+   Edje_Real_Part *rp;
+
+   ed = _edje_fetch(obj);
+   if ((!ed) || (!part)) return 0;
+   rp = _edje_real_part_recursive_get(ed, (char *)part);
+   if (!rp) return 0;
+   if (rp->part->entry_mode > EDJE_ENTRY_EDIT_MODE_NONE)
+     {
+        return _edje_entry_cursor_down(rp, cur);
+     }
+   return 0;
+}
+
+/**
+ * @brief XX
+ * 
+ * @param obj A valid Evas_Object handle
+ * @param part The part name
+ */
+EAPI void
+edje_object_part_text_cursor_begin_set(const Evas_Object *obj, const char *part, Edje_Cursor cur)
+{
+   Edje *ed;
+   Edje_Real_Part *rp;
+
+   ed = _edje_fetch(obj);
+   if ((!ed) || (!part)) return;
+   rp = _edje_real_part_recursive_get(ed, (char *)part);
+   if (!rp) return;
+   if (rp->part->entry_mode > EDJE_ENTRY_EDIT_MODE_NONE)
+     {
+        _edje_entry_cursor_begin(rp, cur);
+     }
+}
+
+/**
+ * @brief XX
+ * 
+ * @param obj A valid Evas_Object handle
+ * @param part The part name
+ */
+EAPI void
+edje_object_part_text_cursor_end_set(const Evas_Object *obj, const char *part, Edje_Cursor cur)
+{
+   Edje *ed;
+   Edje_Real_Part *rp;
+
+   ed = _edje_fetch(obj);
+   if ((!ed) || (!part)) return;
+   rp = _edje_real_part_recursive_get(ed, (char *)part);
+   if (!rp) return;
+   if (rp->part->entry_mode > EDJE_ENTRY_EDIT_MODE_NONE)
+     {
+        _edje_entry_cursor_end(rp, cur);
+     }
+}
+
+/**
+ * @brief XX
+ * 
+ * @param obj A valid Evas_Object handle
+ * @param part The part name
+ */
+EAPI void
+edje_object_part_text_cursor_copy(const Evas_Object *obj, const char *part, Edje_Cursor src, Edje_Cursor dst)
+{
+   Edje *ed;
+   Edje_Real_Part *rp;
+
+   ed = _edje_fetch(obj);
+   if ((!ed) || (!part)) return;
+   rp = _edje_real_part_recursive_get(ed, (char *)part);
+   if (!rp) return;
+   if (rp->part->entry_mode > EDJE_ENTRY_EDIT_MODE_NONE)
+     {
+        _edje_entry_cursor_copy(rp, src, dst);
+     }
+}
+
+/**
+ * @brief XX
+ * 
+ * @param obj A valid Evas_Object handle
+ * @param part The part name
+ */
+EAPI void
+edje_object_part_text_cursor_line_begin_set(const Evas_Object *obj, const char *part, Edje_Cursor cur)
+{
+   Edje *ed;
+   Edje_Real_Part *rp;
+
+   ed = _edje_fetch(obj);
+   if ((!ed) || (!part)) return;
+   rp = _edje_real_part_recursive_get(ed, (char *)part);
+   if (!rp) return;
+   if (rp->part->entry_mode > EDJE_ENTRY_EDIT_MODE_NONE)
+     {
+        _edje_entry_cursor_line_begin(rp, cur);
+     }
+}
+
+/**
+ * @brief XX
+ * 
+ * @param obj A valid Evas_Object handle
+ * @param part The part name
+ */
+EAPI void
+edje_object_part_text_cursor_line_end_set(const Evas_Object *obj, const char *part, Edje_Cursor cur)
+{
+   Edje *ed;
+   Edje_Real_Part *rp;
+
+   ed = _edje_fetch(obj);
+   if ((!ed) || (!part)) return;
+   rp = _edje_real_part_recursive_get(ed, (char *)part);
+   if (!rp) return;
+   if (rp->part->entry_mode > EDJE_ENTRY_EDIT_MODE_NONE)
+     {
+        _edje_entry_cursor_line_end(rp, cur);
+     }
+}
+
+/**
+ * @brief XX
+ * 
+ * @param obj A valid Evas_Object handle
+ * @param part The part name
+ */
+EAPI Eina_Bool
+edje_object_part_text_cursor_is_format_get(const Evas_Object *obj, const char *part, Edje_Cursor cur)
+{
+   Edje *ed;
+   Edje_Real_Part *rp;
+
+   ed = _edje_fetch(obj);
+   if ((!ed) || (!part)) return 0;
+   rp = _edje_real_part_recursive_get(ed, (char *)part);
+   if (!rp) return 0;
+   if (rp->part->entry_mode > EDJE_ENTRY_EDIT_MODE_NONE)
+     {
+        return _edje_entry_cursor_is_format_get(rp, cur);
+     }
+   return 0;
+}
+
+/**
+ * @brief XX
+ * 
+ * @param obj A valid Evas_Object handle
+ * @param part The part name
+ */
+EAPI Eina_Bool
+edje_object_part_text_cursor_is_visible_format_get(const Evas_Object *obj, const char *part, Edje_Cursor cur)
+{
+   Edje *ed;
+   Edje_Real_Part *rp;
+
+   ed = _edje_fetch(obj);
+   if ((!ed) || (!part)) return 0;
+   rp = _edje_real_part_recursive_get(ed, (char *)part);
+   if (!rp) return 0;
+   if (rp->part->entry_mode > EDJE_ENTRY_EDIT_MODE_NONE)
+     {
+        return _edje_entry_cursor_is_visible_format_get(rp, cur);
+     }
+   return 0;
+}
+
+/**
+ * @brief XX
+ * 
+ * @param obj A valid Evas_Object handle
+ * @param part The part name
+ */
+EAPI const char *
+edje_object_part_text_cursor_content_get(const Evas_Object *obj, const char *part, Edje_Cursor cur)
+{
+   Edje *ed;
+   Edje_Real_Part *rp;
+
+   ed = _edje_fetch(obj);
+   if ((!ed) || (!part)) return NULL;
+   rp = _edje_real_part_recursive_get(ed, (char *)part);
+   if (!rp) return NULL;
+   if (rp->part->entry_mode > EDJE_ENTRY_EDIT_MODE_NONE)
+     {
+        return _edje_entry_cursor_content_get(rp, cur);
+     }
+   return NULL;
+}
+
+/**
+ * @brief Swallows an object into the edje.
+ *
+ * @param obj A valid Evas_Object handle
+ * @param part The part name
+ * @param obj_swallow The object to swallow
+ *
+ * Swallows the object into the edje part so that all geometry changes
+ * for the part affect the swallowed object. (e.g. resize, move, show,
+ * raise/lower, etc.).
+ *
+ * If an object has already been swallowed into this part, then it
+ * will first be unswallowed before the new object is swallowed.
+ */
+EAPI Eina_Bool
+edje_object_part_swallow(Evas_Object *obj, const char *part, Evas_Object *obj_swallow)
+{
+   Edje *ed;
+   Edje_Real_Part *rp;
+
+   ed = _edje_fetch(obj);
+   if ((!ed) || (!part)) return EINA_FALSE;
+
+   /* Need to recalc before providing the object. */
+   // XXX: I guess this is not required, removing for testing purposes
+   // XXX: uncomment if you see glitches in e17 or others.
+   // XXX: by Gustavo, January 21th 2009.
+   // XXX: I got a backtrace with over 30000 calls without this,
+   // XXX: only with 32px shelves. The problem is probably somewhere else,
+   // XXX: but until it's found, leave this here.
+   // XXX: by Sachiel, January 21th 2009, 19:30 UTC
+   _edje_recalc_do(ed);
+
+   rp = _edje_real_part_recursive_get(ed, (char *)part);
+   if (!rp) return EINA_FALSE;
+   if (rp->part->type != EDJE_PART_TYPE_SWALLOW)
+     {
+       ERR("cannot unswallow part %s: not swallow type!", rp->part->name);
+       return EINA_FALSE;
+     }
+   _edje_real_part_swallow(rp, obj_swallow);
+   return EINA_TRUE;
+}
+
+static void
+_recalc_extern_parent(Evas_Object *obj)
+{
+   Evas_Object *parent;
+   Edje *ed;
+
+   parent = evas_object_smart_parent_get(obj);
+   ed = _edje_fetch(parent);
+
+   ed->dirty = 1;
+   _edje_recalc(ed);
+}
+
+/**
+ * @brief Set the object minimum size.
+ *
+ * @param obj A valid Evas_Object handle
+ * @param minw The minimum width
+ * @param minh The minimum height
+ *
+ * This sets the minimum size restriction for the object.
+ */
+EAPI void
+edje_extern_object_min_size_set(Evas_Object *obj, Evas_Coord minw, Evas_Coord minh)
+{
+   Edje_Real_Part *rp;
+
+   evas_object_size_hint_min_set(obj, minw, minh);
+   rp = evas_object_data_get(obj, "\377 edje.swallowing_part");
+   if (rp)
+     {
+       rp->swallow_params.min.w = minw;
+       rp->swallow_params.min.h = minh;
+
+       _recalc_extern_parent(obj);
+     }
+}
+
+/**
+ * @brief Set the object maximum size.
+ *
+ * @param obj A valid Evas_Object handle
+ * @param maxw The maximum width
+ * @param maxh The maximum height
+ *
+ * This sets the maximum size restriction for the object.
+ */
+EAPI void
+edje_extern_object_max_size_set(Evas_Object *obj, Evas_Coord maxw, Evas_Coord maxh)
+{
+   Edje_Real_Part *rp;
+
+   evas_object_size_hint_max_set(obj, maxw, maxh);
+   rp = evas_object_data_get(obj, "\377 edje.swallowing_part");
+   if (rp)
+     {
+       rp->swallow_params.max.w = maxw;
+       rp->swallow_params.max.h = maxh;
+
+       _recalc_extern_parent(obj);
+     }
+}
+
+/**
+ * @brief Set the object aspect size.
+ *
+ * @param obj A valid Evas_Object handle
+ * @param aspect The aspect control axes
+ * @param aw The aspect radio width
+ * @param ah The aspect ratio height
+ *
+ * This sets the desired aspect ratio to keep an object that will be
+ * swallowed by Edje. The width and height define a preferred size
+ * ASPECT and the object may be scaled to be larger or smaller, but
+ * retaining the relative scale of both aspect width and height.
+ */
+EAPI void
+edje_extern_object_aspect_set(Evas_Object *obj, Edje_Aspect_Control aspect, Evas_Coord aw, Evas_Coord ah)
+{
+   Edje_Real_Part *rp;
+   Evas_Aspect_Control asp;
+
+   asp = EVAS_ASPECT_CONTROL_NONE;
+   switch (aspect)
+     {
+      case EDJE_ASPECT_CONTROL_NONE: asp = EVAS_ASPECT_CONTROL_NONE; break;
+      case EDJE_ASPECT_CONTROL_NEITHER: asp = EVAS_ASPECT_CONTROL_NEITHER; break;
+      case EDJE_ASPECT_CONTROL_HORIZONTAL: asp = EVAS_ASPECT_CONTROL_HORIZONTAL; break;
+      case EDJE_ASPECT_CONTROL_VERTICAL: asp = EVAS_ASPECT_CONTROL_VERTICAL; break;
+      case EDJE_ASPECT_CONTROL_BOTH: asp = EVAS_ASPECT_CONTROL_BOTH; break;
+      default: break;
+     }
+   if (aw < 1) aw = 1;
+   if (ah < 1) ah = 1;
+   evas_object_size_hint_aspect_set(obj, asp, aw, ah);
+   rp = evas_object_data_get(obj, "\377 edje.swallowing_part");
+   if (rp)
+     {
+       rp->swallow_params.aspect.mode = aspect;
+       rp->swallow_params.aspect.w = aw;
+       rp->swallow_params.aspect.h = ah;
+        _recalc_extern_parent(obj);
+     }
+}
+
+struct edje_box_layout_builtin {
+   const char *name;
+   Evas_Object_Box_Layout cb;
+};
+
+static Evas_Object_Box_Layout
+_edje_box_layout_builtin_find(const char *name)
+{
+   const struct edje_box_layout_builtin _edje_box_layout_builtin[] = {
+     {"horizontal", evas_object_box_layout_horizontal},
+     {"horizontal_flow", evas_object_box_layout_flow_horizontal},
+     {"horizontal_homogeneous", evas_object_box_layout_homogeneous_horizontal},
+     {"horizontal_max", evas_object_box_layout_homogeneous_max_size_horizontal},
+     {"stack", evas_object_box_layout_stack},
+     {"vertical", evas_object_box_layout_vertical},
+     {"vertical_flow", evas_object_box_layout_flow_vertical},
+     {"vertical_homogeneous", evas_object_box_layout_homogeneous_vertical},
+     {"vertical_max", evas_object_box_layout_homogeneous_max_size_vertical},
+     {NULL, NULL}
+   };
+   const struct edje_box_layout_builtin *base;
+
+   switch (name[0])
+     {
+      case 'h':
+        base = _edje_box_layout_builtin + 0;
+        break;
+      case 's':
+        base = _edje_box_layout_builtin + 4;
+        break;
+      case 'v':
+        base = _edje_box_layout_builtin + 5;
+        break;
+      default:
+        return NULL;
+     }
+
+   for (; (base->name != NULL) && (base->name[0] == name[0]); base++)
+     if (strcmp(base->name, name) == 0)
+       return base->cb;
+
+   return NULL;
+}
+
+static Eina_Rbtree_Direction
+_edje_box_layout_external_node_cmp(const Eina_Rbtree *left, const Eina_Rbtree *right, __UNUSED__ void *data)
+{
+   Edje_Box_Layout *l = (Edje_Box_Layout *)left;
+   Edje_Box_Layout *r = (Edje_Box_Layout *)right;
+
+   if (strcmp(l->name, r->name) < 0)
+     return EINA_RBTREE_RIGHT;
+   else
+     return EINA_RBTREE_LEFT;
+}
+
+static int
+_edje_box_layout_external_find_cmp(const Eina_Rbtree *node, const void *key, __UNUSED__ int length, __UNUSED__ void *data)
+{
+   Edje_Box_Layout *l = (Edje_Box_Layout *)node;
+   return strcmp(key, l->name);
+}
+
+static Edje_Box_Layout *
+_edje_box_layout_external_find(const char *name)
+{
+   return (Edje_Box_Layout *)eina_rbtree_inline_lookup
+     (_edje_box_layout_registry, name, 0, _edje_box_layout_external_find_cmp,
+      NULL);
+}
+
+Eina_Bool
+_edje_box_layout_find(const char *name, Evas_Object_Box_Layout *cb, void **data, void (**free_data)(void *data))
+{
+   const Edje_Box_Layout *l;
+
+   if (!name) return EINA_FALSE;
+
+   *cb = _edje_box_layout_builtin_find(name);
+   if (*cb)
+     {
+       *free_data = NULL;
+       *data = NULL;
+       return EINA_TRUE;
+     }
+
+   l = _edje_box_layout_external_find(name);
+   if (!l) return EINA_FALSE;
+
+   *cb = l->func;
+   *free_data = l->layout_data_free;
+   if (l->layout_data_get)
+     *data = l->layout_data_get(l->data);
+   else
+     *data = NULL;
+
+   return EINA_TRUE;
+}
+
+void
+_edje_box_layout_external_free(Eina_Rbtree *node, __UNUSED__ void *data)
+{
+   Edje_Box_Layout *l = (Edje_Box_Layout *)node;
+
+   if (l->data && l->free_data)
+     l->free_data(l->data);
+   free(l);
+}
+
+static Edje_Box_Layout *
+_edje_box_layout_external_new(const char *name, Evas_Object_Box_Layout func, void *(*layout_data_get)(void *), void (*layout_data_free)(void *), void (*free_data)(void *), void *data)
+{
+   Edje_Box_Layout *l;
+   int name_len;
+
+   name_len = strlen(name) + 1;
+   l = malloc(sizeof(Edje_Box_Layout) + name_len);
+   if (!l)
+     {
+       perror("malloc");
+       return NULL;
+     }
+
+   l->func = func;
+   l->layout_data_get = layout_data_get;
+   l->layout_data_free = layout_data_free;
+   l->free_data = free_data;
+   l->data = data;
+
+   memcpy(l->name, name, name_len);
+
+   return l;
+}
+
+/**
+ * @brief Registers a custom layout to be used in edje boxes.
+ *
+ * @param name The name of the layout
+ * @param func The function defining the layout
+ * @param layout_data_get This function gets the custom data pointer
+ * for func
+ * @param layout_data_free Passed to func to free its private data
+ * when needed
+ * @param free_data Frees data
+ * @param data Private pointer passed to layout_data_get
+ *
+ * This function registers custom layouts that can be referred from
+ * themes by the registered name. The Evas_Object_Box_Layout
+ * functions receive two pointers for internal use, one being private
+ * data, and the other the function to free that data when it's not
+ * longer needed. From Edje, this private data will be retrieved by
+ * calling layout_data_get, and layout_data_free will be the free
+ * function passed to func. layout_data_get will be called with data
+ * as its parameter, and this one will be freed by free_data whenever
+ * the layout is unregistered from Edje.
+ */
+EAPI void
+edje_box_layout_register(const char *name, Evas_Object_Box_Layout func, void *(*layout_data_get)(void *), void (*layout_data_free)(void *), void (*free_data)(void *), void *data)
+{
+   Edje_Box_Layout *l;
+
+   if (!name) return;
+
+   if (_edje_box_layout_builtin_find(name))
+     {
+       ERR("Cannot register layout '%s': would override builtin!",
+           name);
+
+       if (data && free_data) free_data(data);
+       return;
+     }
+
+   l = _edje_box_layout_external_find(name);
+   if (!l)
+     {
+       if (!func)
+         {
+            if (data && free_data) free_data(data);
+            return;
+         }
+
+       l = _edje_box_layout_external_new
+         (name, func, layout_data_get, layout_data_free, free_data, data);
+       if (!l)
+         return;
+
+       _edje_box_layout_registry = eina_rbtree_inline_insert
+         (_edje_box_layout_registry, (Eina_Rbtree *)l,
+          _edje_box_layout_external_node_cmp, NULL);
+     }
+   else
+     {
+       if (func)
+         {
+            if (l->data && l->free_data) l->free_data(l->data);
+
+            l->func = func;
+            l->layout_data_get = layout_data_get;
+            l->layout_data_free = layout_data_free;
+            l->free_data = free_data;
+            l->data = data;
+         }
+       else
+         {
+            if (data && free_data) free_data(data);
+
+            _edje_box_layout_registry = eina_rbtree_inline_remove
+              (_edje_box_layout_registry, (Eina_Rbtree *)l,
+               _edje_box_layout_external_node_cmp, NULL);
+            _edje_box_layout_external_free((Eina_Rbtree *)l, NULL);
+         }
+     }
+}
+
+/**
+ * @brief Unswallow an object.
+ *
+ * @param obj A valid Evas_Object handle
+ * @param obj_swallow The swallowed object
+ *
+ * Causes the edje to regurgitate a previously swallowed object.  :)
+ */
+EAPI void
+edje_object_part_unswallow(Evas_Object *obj __UNUSED__, Evas_Object *obj_swallow)
+{
+   Edje_Real_Part *rp;
+
+   if (!obj_swallow) return;
+
+   rp = (Edje_Real_Part *)evas_object_data_get(obj_swallow, "\377 edje.swallowing_part");
+   if (!rp)
+     return;
+   if (rp->part->type != EDJE_PART_TYPE_SWALLOW)
+     {
+       ERR("cannot unswallow part %s: not swallow type!", rp->part->name);
+       return;
+     }
+   if (rp->swallowed_object == obj_swallow)
+     {
+       evas_object_smart_member_del(rp->swallowed_object);
+       evas_object_event_callback_del_full(rp->swallowed_object,
+                                            EVAS_CALLBACK_FREE,
+                                            _edje_object_part_swallow_free_cb,
+                                            rp->edje->obj);
+       evas_object_event_callback_del_full(rp->swallowed_object,
+                                            EVAS_CALLBACK_CHANGED_SIZE_HINTS,
+                                            _edje_object_part_swallow_changed_hints_cb,
+                                            rp);
+       evas_object_clip_unset(rp->swallowed_object);
+       evas_object_data_del(rp->swallowed_object, "\377 edje.swallowing_part");
+
+       if (rp->part->mouse_events)
+         _edje_callbacks_del(rp->swallowed_object, rp->edje);
+       _edje_callbacks_focus_del(rp->swallowed_object, rp->edje);
+
+       rp->swallowed_object = NULL;
+       rp->swallow_params.min.w = 0;
+       rp->swallow_params.min.h = 0;
+       rp->swallow_params.max.w = 0;
+       rp->swallow_params.max.h = 0;
+       rp->edje->dirty = 1;
+#ifdef EDJE_CALC_CACHE
+       rp->invalidate = 1;
+#endif
+       _edje_recalc_do(rp->edje);
+       return;
+     }
+}
+
+/**
+ * @brief Get the object currently swallowed by a part.
+ *
+ * @param obj A valid Evas_Object handle
+ * @param part The part name
+ * @return The swallowed object, or NULL if there is none.
+ */
+EAPI Evas_Object *
+edje_object_part_swallow_get(const Evas_Object *obj, const char *part)
+{
+   Edje *ed;
+   Edje_Real_Part *rp;
+
+   ed = _edje_fetch(obj);
+   if ((!ed) || (!part)) return NULL;
+
+   /* Need to recalc before providing the object. */
+   _edje_recalc_do(ed);
+
+   rp = _edje_real_part_recursive_get(ed, (char *)part);
+   if (!rp) return NULL;
+   return rp->swallowed_object;
+}
+
+/**
+ * @brief Get the minimum size for an object.
+ *
+ * @param obj A valid Evas_Object handle
+ * @param minw Minimum width pointer
+ * @param minh Minimum height pointer
+ *
+ * Gets the object's minimum size values from the Edje. These are set
+ * to zero if no Edje is connected to the Evas Object.
+ */
+EAPI void
+edje_object_size_min_get(const Evas_Object *obj, Evas_Coord *minw, Evas_Coord *minh)
+{
+   Edje *ed;
+
+   ed = _edje_fetch(obj);
+   if ((!ed) || (!ed->collection))
+     {
+       if (minw) *minw = 0;
+       if (minh) *minh = 0;
+       return;
+     }
+   if (minw) *minw = ed->collection->prop.min.w;
+   if (minh) *minh = ed->collection->prop.min.h;
+}
+
+/**
+ * @brief Get the maximum size for an object.
+ *
+ * @param obj A valid Evas_Object handle
+ * @param maxw Maximum width pointer
+ * @param maxh Maximum height pointer
+ *
+ * Gets the object's maximum size values from the Edje. These are set
+ * to zero if no Edje is connected to the Evas Object.
+ */
+EAPI void
+edje_object_size_max_get(const Evas_Object *obj, Evas_Coord *maxw, Evas_Coord *maxh)
+{
+   Edje *ed;
+
+   ed = _edje_fetch(obj);
+   if ((!ed) || (!ed->collection))
+     {
+       if (maxw) *maxw = 0;
+       if (maxh) *maxh = 0;
+       return;
+     }
+
+   /* Need to recalc before providing the object. */
+   _edje_recalc_do(ed);
+
+   if (ed->collection->prop.max.w == 0)
+     {
+       /* XXX TODO: convert maxw to 0, fix things that break. */
+       if (maxw) *maxw = EDJE_INF_MAX_W;
+     }
+   else
+     {
+       if (maxw) *maxw = ed->collection->prop.max.w;
+     }
+   if (ed->collection->prop.max.h == 0)
+     {
+       /* XXX TODO: convert maxh to 0, fix things that break. */
+       if (maxh) *maxh = EDJE_INF_MAX_H;
+     }
+   else
+     {
+       if (maxh) *maxh = ed->collection->prop.max.h;
+     }
+}
+
+/**
+ * @brief Force a Size/Geometry calculation.
+ *
+ * @param obj A valid Evas_Object handle
+ *
+ * Forces the object @p obj to recalculation layout regardless of
+ * freeze/thaw.
+ */
+EAPI void
+edje_object_calc_force(Evas_Object *obj)
+{
+   Edje *ed;
+   int pf, pf2;
+
+   ed = _edje_fetch(obj);
+   if (!ed) return;
+   ed->dirty = 1;
+#ifdef EDJE_CALC_CACHE
+   ed->all_part_change = 1;
+#endif
+
+   pf2 = _edje_freeze_val;
+   pf = ed->freeze;
+   
+   _edje_freeze_val = 0;
+   ed->freeze = 0;
+   
+   _edje_recalc_do(ed);
+   
+   ed->freeze = pf;
+   _edje_freeze_val = pf2;
+}
+
+/**
+ * @brief Calculate minimum size.
+ *
+ * @param obj A valid Evas_Object handle
+ * @param minw Minimum width pointer
+ * @param minh Minimum height pointer
+ *
+ * Calculates the object's minimum size ?!
+ */
+EAPI void
+edje_object_size_min_calc(Evas_Object *obj, Evas_Coord *minw, Evas_Coord *minh)
+{
+   edje_object_size_min_restricted_calc(obj, minw, minh, 0, 0);
+}
+
+/** Calculate the geometry used by all parts
+ * @param obj A valid Evas_Object handle
+ * @param x The x coordinate pointer
+ * @param y The y coordinate pointer
+ * @param w The width pointer
+ * @param h The height pointer
+ *
+ * Calculates the geometry used by all object parts. Including out of bounds parts.
+ */
+EAPI Eina_Bool
+edje_object_parts_extends_calc(Evas_Object *obj, Evas_Coord *x, Evas_Coord *y, Evas_Coord *w, Evas_Coord *h)
+{
+   Edje *ed;
+   Evas_Coord x1 = INT_MAX, y1 = INT_MAX;
+   Evas_Coord x2 = 0, y2 = 0;
+   int i;
+
+   ed = _edje_fetch(obj);
+   if (!ed)
+     {
+       if (x) *x = 0;
+       if (y) *y = 0;
+       if (w) *w = 0;
+       if (h) *h = 0;
+       return EINA_FALSE;
+     }
+
+   ed->calc_only = 1;
+
+   /* Need to recalc before providing the object. */
+   ed->dirty = 1;
+   _edje_recalc_do(ed);
+
+   for (i = 0; i < ed->table_parts_size; i++)
+     {
+        Edje_Real_Part *rp;
+        Evas_Coord rpx1, rpy1;
+        Evas_Coord rpx2, rpy2;
+
+        rp = ed->table_parts[i];
+
+       rpx1 = rp->x;
+       rpy1 = rp->y;
+       rpx2 = rpx1 + rp->w;
+       rpy2 = rpy1 + rp->h;
+
+       if (x1 > rpx1) x1 = rpx1;
+       if (y1 > rpy1) y1 = rpy1;
+       if (x2 < rpx2) x2 = rpx2;
+       if (y2 < rpy2) y2 = rpy2;
+     }
+
+   ed->calc_only = 0;
+
+   *x = x1;
+   *y = y1;
+   *w = x2 - x1;
+   *h = y2 - y1;
+
+   return EINA_TRUE;
+}
+
+/** Calculate minimum size
+ * @param obj A valid Evas_Object handle
+ * @param minw Minimum width pointer
+ * @param minh Minimum height pointer
+ * @param restrictedw Do not allow object min width calc to be less than this
+ * @param restrictedh Do not allow object min height calc to be less than this
+ *
+ * Calculates the object's minimum size ?!
+ */
+EAPI void
+edje_object_size_min_restricted_calc(Evas_Object *obj, Evas_Coord *minw, Evas_Coord *minh, Evas_Coord restrictedw, Evas_Coord restrictedh)
+{
+   Edje *ed;
+   Evas_Coord pw, ph;
+   int maxw, maxh;
+   int ok;
+   int reset_maxwh;
+   Edje_Real_Part *pep = NULL;
+
+   ed = _edje_fetch(obj);
+   if ((!ed) || (!ed->collection))
+     {
+       if (minw) *minw = restrictedw;
+       if (minh) *minh = restrictedh;
+       return;
+     }
+   reset_maxwh = 1;
+   ed->calc_only = 1;
+   pw = ed->w;
+   ph = ed->h;
+
+   again:
+   ed->w = restrictedw;
+   ed->h = restrictedh;
+
+   maxw = 0;
+   maxh = 0;
+
+   ok = 1;
+   while (ok)
+     {
+       int i;
+
+       ok = 0;
+       ed->dirty = 1;
+#ifdef EDJE_CALC_CACHE
+       ed->all_part_change = 1;
+#endif
+       _edje_recalc_do(ed);
+       if (reset_maxwh)
+         {
+            maxw = 0;
+            maxh = 0;
+         }
+       pep = NULL;
+       for (i = 0; i < ed->table_parts_size; i++)
+         {
+            Edje_Real_Part *ep;
+            int w, h;
+            int didw;
+
+            ep = ed->table_parts[i];
+            w = ep->w - ep->req.w;
+            h = ep->h - ep->req.h;
+            didw = 0;
+            if (ep->chosen_description)
+              {
+                 if (!ep->chosen_description->fixed.w)
+                   {
+                      if (w > maxw)
+                        {
+                           maxw = w;
+                           ok = 1;
+                           pep = ep;
+                           didw = 1;
+                        }
+                      if ((ep->part->type == EDJE_PART_TYPE_TEXTBLOCK))
+                        {
+                           /* FIXME: do something */
+                        }
+                   }
+                 if (!ep->chosen_description->fixed.h)
+                   {
+                      if (!((ep->part->type == EDJE_PART_TYPE_TEXTBLOCK) &&
+                            (!ep->chosen_description->text.min_x) &&
+                            (didw)))
+                        {
+                           if (h > maxh)
+                             {
+                                maxh = h;
+                                ok = 1;
+                                pep = ep;
+                             }
+                        }
+                   }
+              }
+         }
+       if (ok)
+         {
+            ed->w += maxw;
+            ed->h += maxh;
+            if (ed->w < restrictedw) ed->w = restrictedw;
+            if (ed->h < restrictedh) ed->h = restrictedh;
+         }
+       if ((ed->w > 4000) || (ed->h > 4000))
+         {
+            ERR("file %s, group %s has a non-fixed part. add fixed: 1 1; ???",
+                   ed->path, ed->group);
+            if (pep)
+              ERR("  Problem part is: %s", pep->part->name);
+            ERR("  Will recalc min size not allowing broken parts to affect the result.");
+            if (reset_maxwh)
+              {
+                 reset_maxwh = 0;
+                 goto again;
+              }
+         }
+     }
+   ed->min.w = ed->w;
+   ed->min.h = ed->h;
+
+   if (minw) *minw = ed->min.w;
+   if (minh) *minh = ed->min.h;
+
+   ed->w = pw;
+   ed->h = ph;
+   ed->dirty = 1;
+#ifdef EDJE_CALC_CACHE
+   ed->all_part_change = 1;
+#endif
+   _edje_recalc(ed);
+   ed->calc_only = 0;
+}
+
+/**
+ * @brief Returns the state of the Edje part.
+ *
+ * @param obj A valid Evas_Object handle
+ * @param part The part name
+ * @param val_ret
+ *
+ * @return The part state:\n
+ * "default" for the default state\n
+ * "" for other states
+ */
+/* FIXME: Correctly return other states */
+EAPI const char *
+edje_object_part_state_get(const Evas_Object *obj, const char *part, double *val_ret)
+{
+   Edje *ed;
+   Edje_Real_Part *rp;
+
+   ed = _edje_fetch(obj);
+   if ((!ed) || (!part))
+     {
+       if (val_ret) *val_ret = 0;
+       return "";
+     }
+
+   /* Need to recalc before providing the object. */
+   _edje_recalc_do(ed);
+
+   rp = _edje_real_part_recursive_get(ed, (char *)part);
+   if (!rp)
+     {
+       if (val_ret) *val_ret = 0;
+       INF("part not found");
+       return "";
+     }
+   if (rp->chosen_description)
+     {
+       if (val_ret) *val_ret = rp->chosen_description->state.value;
+       if (rp->chosen_description->state.name)
+         return rp->chosen_description->state.name;
+       return "default";
+     }
+   else
+     {
+       if (rp->param1.description)
+         {
+            if (val_ret) *val_ret = rp->param1.description->state.value;
+            if (rp->param1.description->state.name)
+              return rp->param1.description->state.name;
+            return "default";
+         }
+     }
+   if (val_ret) *val_ret = 0;
+   return "";
+}
+
+/**
+ * @brief Determine dragable directions.
+ *
+ * @param obj A valid Evas_Object handle
+ * @param part The part name
+ *
+ * @return 0: Not dragable\n
+ * 1: Dragable in X direction\n
+ * 2: Dragable in Y direction\n
+ * 3: Dragable in X & Y directions
+ */
+EAPI int
+edje_object_part_drag_dir_get(const Evas_Object *obj, const char *part)
+{
+   Edje *ed;
+   Edje_Real_Part *rp;
+
+   ed = _edje_fetch(obj);
+   if ((!ed) || (!part)) return EDJE_DRAG_DIR_NONE;
+
+   /* Need to recalc before providing the object. */
+   _edje_recalc_do(ed);
+
+   rp = _edje_real_part_recursive_get(ed, (char *)part);
+   if (!rp) return EDJE_DRAG_DIR_NONE;
+   if ((rp->part->dragable.x) && (rp->part->dragable.y)) return EDJE_DRAG_DIR_XY;
+   else if (rp->part->dragable.x) return EDJE_DRAG_DIR_X;
+   else if (rp->part->dragable.y) return EDJE_DRAG_DIR_Y;
+   return EDJE_DRAG_DIR_NONE;
+}
+
+/**
+ * @brief Set the dragable object location.
+ *
+ * @param obj A valid Evas_Object handle
+ * @param part The part name
+ * @param dx The x value
+ * @param dy The y value
+ *
+ * Places the dragable object at the given location.
+ */
+EAPI Eina_Bool
+edje_object_part_drag_value_set(Evas_Object *obj, const char *part, double dx, double dy)
+{
+   Edje *ed;
+   Edje_Real_Part *rp;
+
+   ed = _edje_fetch(obj);
+   if ((!ed) || (!part)) return EINA_FALSE;
+   rp = _edje_real_part_recursive_get(ed, (char *)part);
+   if (!rp) return EINA_FALSE;
+   if (!rp->drag) return EINA_FALSE;
+   if (rp->drag->down.count > 0) return EINA_FALSE;
+   if (rp->part->dragable.confine_id != -1)
+     {
+       dx = CLAMP(dx, 0.0, 1.0);
+       dy = CLAMP(dy, 0.0, 1.0);
+     }
+   if (rp->part->dragable.x < 0) dx = 1.0 - dx;
+   if (rp->part->dragable.y < 0) dy = 1.0 - dy;
+   if ((rp->drag->val.x == FROM_DOUBLE(dx)) && (rp->drag->val.y == FROM_DOUBLE(dy))) return EINA_TRUE;
+   rp->drag->val.x = FROM_DOUBLE(dx);
+   rp->drag->val.y = FROM_DOUBLE(dy);
+#ifdef EDJE_CALC_CACHE
+   rp->invalidate = 1;
+#endif
+   _edje_dragable_pos_set(rp->edje, rp, rp->drag->val.x, rp->drag->val.y);
+   _edje_emit(rp->edje, "drag,set", rp->part->name);
+   return EINA_TRUE;
+}
+
+/**
+ * @brief Get the dragable object location.
+ *
+ * @param obj A valid Evas_Object handle
+ * @param part The part name
+ * @param dx The X value pointer
+ * @param dy The Y value pointer
+ *
+ * Gets the drag location values.
+ */
+/* FIXME: Should this be x and y instead of dx/dy? */
+EAPI Eina_Bool
+edje_object_part_drag_value_get(const Evas_Object *obj, const char *part, double *dx, double *dy)
+{
+   Edje *ed;
+   Edje_Real_Part *rp;
+   double ddx, ddy;
+
+   ed = _edje_fetch(obj);
+   if ((!ed) || (!part))
+     {
+       if (dx) *dx = 0;
+       if (dy) *dy = 0;
+       return EINA_FALSE;
+     }
+
+   /* Need to recalc before providing the object. */
+   _edje_recalc_do(ed);
+
+   rp = _edje_real_part_recursive_get(ed, (char *)part);
+   if (!rp || !rp->drag)
+     {
+       if (dx) *dx = 0;
+       if (dy) *dy = 0;
+       return EINA_FALSE;
+     }
+   ddx = TO_DOUBLE(rp->drag->val.x);
+   ddy = TO_DOUBLE(rp->drag->val.y);
+   if (rp->part->dragable.x < 0) ddx = 1.0 - ddx;
+   if (rp->part->dragable.y < 0) ddy = 1.0 - ddy;
+   if (dx) *dx = ddx;
+   if (dy) *dy = ddy;
+   return EINA_TRUE;
+}
+
+/**
+ * @brief Set the dragable object size.
+ *
+ * @param obj A valid Evas_Object handle
+ * @param part The part name
+ * @param dw The drag width
+ * @param dh The drag height
+ *
+ * Sets the size of the dragable object.
+ */
+EAPI Eina_Bool
+edje_object_part_drag_size_set(Evas_Object *obj, const char *part, double dw, double dh)
+{
+   Edje *ed;
+   Edje_Real_Part *rp;
+
+   ed = _edje_fetch(obj);
+   if ((!ed) || (!part)) return EINA_FALSE;
+   rp = _edje_real_part_recursive_get(ed, (char *)part);
+   if (!rp) return EINA_FALSE;
+   if (!rp->drag) return EINA_FALSE;
+   if (dw < 0.0) dw = 0.0;
+   else if (dw > 1.0) dw = 1.0;
+   if (dh < 0.0) dh = 0.0;
+   else if (dh > 1.0) dh = 1.0;
+   if ((rp->drag->size.x == FROM_DOUBLE(dw)) && (rp->drag->size.y == FROM_DOUBLE(dh))) return EINA_TRUE;
+   rp->drag->size.x = FROM_DOUBLE(dw);
+   rp->drag->size.y = FROM_DOUBLE(dh);
+   rp->edje->dirty = 1;
+#ifdef EDJE_CALC_CACHE
+   rp->invalidate = 1;
+#endif
+   _edje_recalc(rp->edje);
+   return EINA_TRUE;
+}
+
+/**
+ * @brief Get the dragable object size.
+ *
+ * @param obj A valid Evas_Object handle
+ * @param part The part name
+ * @param dw The drag width pointer
+ * @param dh The drag height pointer
+ *
+ * Gets the dragable object size.
+ */
+EAPI Eina_Bool
+edje_object_part_drag_size_get(const Evas_Object *obj, const char *part, double *dw, double *dh)
+{
+   Edje *ed;
+   Edje_Real_Part *rp;
+
+   ed = _edje_fetch(obj);
+   if ((!ed) || (!part))
+     {
+       if (dw) *dw = 0;
+       if (dh) *dh = 0;
+       return EINA_FALSE;
+     }
+
+   /* Need to recalc before providing the object. */
+   _edje_recalc_do(ed);
+
+   rp = _edje_real_part_recursive_get(ed, (char *)part);
+   if (!rp || !rp->drag)
+     {
+       if (dw) *dw = 0;
+       if (dh) *dh = 0;
+       return EINA_FALSE;
+     }
+   if (dw) *dw = TO_DOUBLE(rp->drag->size.x);
+   if (dh) *dh = TO_DOUBLE(rp->drag->size.y);
+   return EINA_TRUE;
+}
+
+/**
+ * @brief Sets the drag step increment.
+ *
+ * @param obj A valid Evas_Object handle
+ * @param part The part name
+ * @param dx The x step ammount
+ * @param dy The y step ammount
+ *
+ * Sets the x,y step increments for a dragable object.
+ */
+EAPI Eina_Bool
+edje_object_part_drag_step_set(Evas_Object *obj, const char *part, double dx, double dy)
+{
+   Edje *ed;
+   Edje_Real_Part *rp;
+
+   ed = _edje_fetch(obj);
+   if ((!ed) || (!part)) return EINA_FALSE;
+   rp = _edje_real_part_recursive_get(ed, (char *)part);
+   if (!rp) return EINA_FALSE;
+   if (!rp->drag) return EINA_FALSE;
+   if (dx < 0.0) dx = 0.0;
+   else if (dx > 1.0) dx = 1.0;
+   if (dy < 0.0) dy = 0.0;
+   else if (dy > 1.0) dy = 1.0;
+   rp->drag->step.x = FROM_DOUBLE(dx);
+   rp->drag->step.y = FROM_DOUBLE(dy);
+#ifdef EDJE_CALC_CACHE
+   rp->invalidate = 1;
+#endif
+   return EINA_TRUE;
+}
+
+/**
+ * @brief Gets the drag step increment values.
+ *
+ * @param obj A valid Evas_Object handle
+ * @param part The part
+ * @param dx The x step increment pointer
+ * @param dy The y step increment pointer
+ *
+ * Gets the x and y step increments for the dragable object.
+ */
+EAPI Eina_Bool
+edje_object_part_drag_step_get(const Evas_Object *obj, const char *part, double *dx, double *dy)
+{
+   Edje *ed;
+   Edje_Real_Part *rp;
+
+   ed = _edje_fetch(obj);
+   if ((!ed) || (!part))
+     {
+       if (dx) *dx = 0;
+       if (dy) *dy = 0;
+       return EINA_FALSE;
+     }
+
+   /* Need to recalc before providing the object. */
+   _edje_recalc_do(ed);
+
+   rp = _edje_real_part_recursive_get(ed, (char *)part);
+   if (!rp || !rp->drag)
+     {
+       if (dx) *dx = 0;
+       if (dy) *dy = 0;
+       return EINA_FALSE;
+     }
+   if (dx) *dx = TO_DOUBLE(rp->drag->step.x);
+   if (dy) *dy = TO_DOUBLE(rp->drag->step.y);
+   return EINA_TRUE;
+}
+
+/**
+ * @brief Sets the page step increments.
+ *
+ * @param obj A valid Evas_Object handle
+ * @param part The part name
+ * @param dx The x page step increment
+ * @param dy The y page step increment
+ *
+ * Sets the x,y page step increment values.
+ */
+EAPI Eina_Bool
+edje_object_part_drag_page_set(Evas_Object *obj, const char *part, double dx, double dy)
+{
+   Edje *ed;
+   Edje_Real_Part *rp;
+
+   ed = _edje_fetch(obj);
+   if ((!ed) || (!part)) return EINA_FALSE;
+   rp = _edje_real_part_recursive_get(ed, (char *)part);
+   if (!rp) return EINA_FALSE;
+   if (!rp->drag) return EINA_FALSE;
+   if (dx < 0.0) dx = 0.0;
+   else if (dx > 1.0) dx = 1.0;
+   if (dy < 0.0) dy = 0.0;
+   else if (dy > 1.0) dy = 1.0;
+   rp->drag->page.x = FROM_DOUBLE(dx);
+   rp->drag->page.y = FROM_DOUBLE(dy);
+#ifdef EDJE_CALC_CACHE
+   rp->invalidate = 1;
+#endif
+   return EINA_TRUE;
+}
+
+/**
+ * @brief Gets the page step increments.
+ *
+ * @param obj A valid Evas_Object handle
+ * @param part The part name
+ * @param dx The dx page increment pointer
+ * @param dy The dy page increment pointer
+ *
+ * Gets the x,y page step increments for the dragable object.
+ */
+EAPI Eina_Bool
+edje_object_part_drag_page_get(const Evas_Object *obj, const char *part, double *dx, double *dy)
+{
+   Edje *ed;
+   Edje_Real_Part *rp;
+
+   ed = _edje_fetch(obj);
+   if ((!ed) || (!part))
+     {
+       if (dx) *dx = 0;
+       if (dy) *dy = 0;
+       return EINA_FALSE;
+     }
+
+   /* Need to recalc before providing the object. */
+   _edje_recalc_do(ed);
+
+   rp = _edje_real_part_recursive_get(ed, (char *)part);
+   if (!rp || !rp->drag)
+     {
+       if (dx) *dx = 0;
+       if (dy) *dy = 0;
+       return EINA_FALSE;
+     }
+   if (dx) *dx = TO_DOUBLE(rp->drag->page.x);
+   if (dy) *dy = TO_DOUBLE(rp->drag->page.y);
+   return EINA_TRUE;
+}
+
+/**
+ * @brief Steps the dragable x,y steps.
+ *
+ * @param obj A valid Evas_Object handle
+ * @param part The part name
+ * @param dx The x step
+ * @param dy The y step
+ *
+ * Steps x,y where the step increment is the amount set by
+ * edje_object_part_drag_step_set.
+ */
+EAPI Eina_Bool
+edje_object_part_drag_step(Evas_Object *obj, const char *part, double dx, double dy)
+{
+   Edje *ed;
+   Edje_Real_Part *rp;
+   FLOAT_T px, py;
+
+   ed = _edje_fetch(obj);
+   if ((!ed) || (!part)) return EINA_FALSE;
+   rp = _edje_real_part_recursive_get(ed, (char *)part);
+   if (!rp) return EINA_FALSE;
+   if (!rp->drag) return EINA_FALSE;
+   if (rp->drag->down.count > 0) return EINA_FALSE;
+   px = rp->drag->val.x;
+   py = rp->drag->val.y;
+   rp->drag->val.x = ADD(px, MUL(FROM_DOUBLE(dx),
+                                MUL(rp->drag->step.x, rp->part->dragable.x)));
+   rp->drag->val.y = ADD(py, MUL(FROM_DOUBLE(dy),
+                                MUL(rp->drag->step.y, rp->part->dragable.y)));
+   rp->drag->val.x = CLAMP (rp->drag->val.x, ZERO, FROM_DOUBLE(1.0));
+   rp->drag->val.y = CLAMP (rp->drag->val.y, ZERO, FROM_DOUBLE(1.0));
+   if ((px == rp->drag->val.x) && (py == rp->drag->val.y)) return EINA_TRUE;
+#ifdef EDJE_CALC_CACHE
+   rp->invalidate = 1;
+#endif
+   _edje_dragable_pos_set(rp->edje, rp, rp->drag->val.x, rp->drag->val.y);
+   _edje_emit(rp->edje, "drag,step", rp->part->name);
+   return EINA_TRUE;
+}
+
+/**
+ * @brief Pages x,y steps.
+ *
+ * @param obj A valid Evas_Object handle
+ * @param part The part name
+ * @param dx The x step
+ * @param dy The y step
+ *
+ * Pages x,y where the increment is defined by
+ * edje_object_part_drag_page_set.\n WARNING: Paging is bugged!
+ */
+EAPI Eina_Bool
+edje_object_part_drag_page(Evas_Object *obj, const char *part, double dx, double dy)
+{
+   Edje *ed;
+   Edje_Real_Part *rp;
+   FLOAT_T px, py;
+
+   ed = _edje_fetch(obj);
+   if ((!ed) || (!part)) return EINA_FALSE;
+   rp = _edje_real_part_recursive_get(ed, (char *)part);
+   if (!rp) return EINA_FALSE;
+   if (!rp->drag) return EINA_FALSE;
+   if (rp->drag->down.count > 0) return EINA_FALSE;
+   px = rp->drag->val.x;
+   py = rp->drag->val.y;
+   rp->drag->val.x = ADD(px, MUL(FROM_DOUBLE(dx), MUL(rp->drag->page.x, rp->part->dragable.x)));
+   rp->drag->val.y = ADD(py, MUL(FROM_DOUBLE(dy), MUL(rp->drag->page.y, rp->part->dragable.y)));
+   rp->drag->val.x = CLAMP (rp->drag->val.x, ZERO, FROM_DOUBLE(1.0));
+   rp->drag->val.y = CLAMP (rp->drag->val.y, ZERO, FROM_DOUBLE(1.0));
+   if ((px == rp->drag->val.x) && (py == rp->drag->val.y)) return EINA_TRUE;
+#ifdef EDJE_CALC_CACHE
+   rp->invalidate = 1;
+#endif
+   _edje_dragable_pos_set(rp->edje, rp, rp->drag->val.x, rp->drag->val.y);
+   _edje_emit(rp->edje, "drag,page", rp->part->name);
+   return EINA_TRUE;
+}
+
+void
+_edje_box_init(void)
+{
+
+}
+
+void
+_edje_box_shutdown(void)
+{
+   if (!_edje_box_layout_registry)
+     return;
+
+   eina_rbtree_delete
+     (_edje_box_layout_registry, _edje_box_layout_external_free, NULL);
+   _edje_box_layout_registry = NULL;
+}
+
+/**
+ * @brief Appends an object to the box.
+ *
+ * @param obj A valid Evas_Object handle
+ * @param part The part name
+ * @param child The object to append
+ *
+ * @return 1: Successfully added.\n
+ * 0: An error occured.
+ *
+ * Appends child to the box indicated by part.
+ */
+EAPI Eina_Bool
+edje_object_part_box_append(Evas_Object *obj, const char *part, Evas_Object *child)
+{
+   Edje *ed;
+   Edje_Real_Part *rp;
+
+   ed = _edje_fetch(obj);
+   if ((!ed) || (!part) || (!child)) return EINA_FALSE;
+
+   rp = _edje_real_part_recursive_get(ed, part);
+   if (!rp) return EINA_FALSE;
+   if (rp->part->type != EDJE_PART_TYPE_BOX) return EINA_FALSE;
+
+   return _edje_real_part_box_append(rp, child);
+}
+
+/**
+ * @brief Prepends an object to the box.
+ *
+ * @param obj A valid Evas_Object handle
+ * @param part The part name
+ * @param child The object to prepend
+ *
+ * @return 1: Successfully added.\n
+ * 0: An error occured.
+ *
+ * Prepends child to the box indicated by part.
+ */
+EAPI Eina_Bool
+edje_object_part_box_prepend(Evas_Object *obj, const char *part, Evas_Object *child)
+{
+   Edje *ed;
+   Edje_Real_Part *rp;
+
+   ed = _edje_fetch(obj);
+   if ((!ed) || (!part)) return EINA_FALSE;
+
+   rp = _edje_real_part_recursive_get(ed, part);
+   if (!rp) return EINA_FALSE;
+   if (rp->part->type != EDJE_PART_TYPE_BOX) return EINA_FALSE;
+
+   return _edje_real_part_box_prepend(rp, child);
+}
+
+/**
+ * @brief Adds an object to the box.
+ *
+ * @param obj A valid Evas_Object handle
+ * @param part The part name
+ * @param child The object to insert
+ * @param reference The object to be used as reference
+ *
+ * @return 1: Successfully added.\n
+ * 0: An error occured.
+ *
+ * Inserts child in the box given by part, in the position marked by
+ * reference.
+ */
+EAPI Eina_Bool
+edje_object_part_box_insert_before(Evas_Object *obj, const char *part, Evas_Object *child, const Evas_Object *reference)
+{
+   Edje *ed;
+   Edje_Real_Part *rp;
+
+   ed = _edje_fetch(obj);
+   if ((!ed) || (!part)) return EINA_FALSE;
+
+   rp = _edje_real_part_recursive_get(ed, part);
+   if (!rp) return EINA_FALSE;
+   if (rp->part->type != EDJE_PART_TYPE_BOX) return EINA_FALSE;
+
+   return _edje_real_part_box_insert_before(rp, child, reference);
+}
+
+/**
+ * @brief Inserts an object to the box.
+ *
+ * @param obj A valid Evas_Object handle
+ * @param part The part name
+ * @param child The object to insert
+ * @param pos The position where to insert child
+ *
+ * @return 1: Successfully added.\n
+ * 0: An error occured.
+ *
+ * Adds child to the box indicated by part, in the position given by
+ * pos.
+ */
+EAPI Eina_Bool
+edje_object_part_box_insert_at(Evas_Object *obj, const char *part, Evas_Object *child, unsigned int pos)
+{
+   Edje *ed;
+   Edje_Real_Part *rp;
+
+   ed = _edje_fetch(obj);
+   if ((!ed) || (!part)) return EINA_FALSE;
+
+   rp = _edje_real_part_recursive_get(ed, part);
+   if (!rp) return EINA_FALSE;
+   if (rp->part->type != EDJE_PART_TYPE_BOX) return EINA_FALSE;
+
+   return _edje_real_part_box_insert_at(rp, child, pos);
+}
+
+/**
+ * @brief Removes an object from the box.
+ *
+ * @param obj A valid Evas_Object handle
+ * @param part The part name
+ * @param child The object to remove
+ *
+ * @return Pointer to the object removed, or NULL.
+ *
+ * Removes child from the box indicated by part.
+ */
+EAPI Evas_Object *
+edje_object_part_box_remove(Evas_Object *obj, const char *part, Evas_Object *child)
+{
+   Edje *ed;
+   Edje_Real_Part *rp;
+
+   ed = _edje_fetch(obj);
+   if ((!ed) || (!part)) return NULL;
+
+   rp = _edje_real_part_recursive_get(ed, part);
+   if (!rp) return NULL;
+   if (rp->part->type != EDJE_PART_TYPE_BOX) return NULL;
+
+   return _edje_real_part_box_remove(rp, child);
+}
+
+/**
+ * @brief Removes an object from the box.
+ *
+ * @param obj A valid Evas_Object handle
+ * @param part The part name
+ * @param pos
+ *
+ * @return Pointer to the object removed, or NULL.
+ *
+ * Removes from the box indicated by part, the object in the position
+ * pos.
+ */
+EAPI Evas_Object *
+edje_object_part_box_remove_at(Evas_Object *obj, const char *part, unsigned int pos)
+{
+   Edje *ed;
+   Edje_Real_Part *rp;
+
+   ed = _edje_fetch(obj);
+   if ((!ed) || (!part)) return NULL;
+
+   rp = _edje_real_part_recursive_get(ed, part);
+   if (!rp) return NULL;
+   if (rp->part->type != EDJE_PART_TYPE_BOX) return NULL;
+
+   return _edje_real_part_box_remove_at(rp, pos);
+}
+
+/**
+ * @brief Removes all elements from the box.
+ *
+ * @param obj A valid Evas_Object handle
+ * @param part The part name
+ * @param clear Delete objects on removal
+ *
+ * @return 1: Successfully cleared.\n
+ * 0: An error occured.
+ *
+ * Removes all the external objects from the box indicated by part.
+ * Elements created from the theme will not be removed.
+ */
+EAPI Eina_Bool
+edje_object_part_box_remove_all(Evas_Object *obj, const char *part, Eina_Bool clear)
+{
+   Edje *ed;
+   Edje_Real_Part *rp;
+
+   ed = _edje_fetch(obj);
+   if ((!ed) || (!part)) return EINA_FALSE;
+
+   rp = _edje_real_part_recursive_get(ed, part);
+   if (!rp) return EINA_FALSE;
+   if (rp->part->type != EDJE_PART_TYPE_BOX) return EINA_FALSE;
+
+   return _edje_real_part_box_remove_all(rp, clear);
+
+}
+
+static void
+_edje_box_child_del_cb(void *data, Evas *e __UNUSED__, Evas_Object *child __UNUSED__, void *einfo __UNUSED__)
+{
+   Edje_Real_Part *rp = data;
+
+   rp->edje->dirty = 1;
+#ifdef EDJE_CALC_CACHE
+   rp->invalidate = 1;
+#endif
+   _edje_recalc(rp->edje);
+}
+
+static void
+_edje_box_child_add(Edje_Real_Part *rp, Evas_Object *child)
+{
+   evas_object_event_callback_add
+     (child, EVAS_CALLBACK_DEL, _edje_box_child_del_cb, rp);
+
+   rp->edje->dirty = 1;
+#ifdef EDJE_CALC_CACHE
+   rp->invalidate = 1;
+#endif
+   _edje_recalc(rp->edje);
+}
+
+static void
+_edje_box_child_remove(Edje_Real_Part *rp, Evas_Object *child)
+{
+   evas_object_event_callback_del_full
+     (child, EVAS_CALLBACK_DEL, _edje_box_child_del_cb, rp);
+
+   rp->edje->dirty = 1;
+#ifdef EDJE_CALC_CACHE
+   rp->invalidate = 1;
+#endif
+   _edje_recalc(rp->edje);
+}
+
+Eina_Bool
+_edje_real_part_box_append(Edje_Real_Part *rp, Evas_Object *child_obj)
+{
+   Evas_Object_Box_Option *opt;
+
+   opt = evas_object_box_append(rp->object, child_obj);
+   if (!opt) return EINA_FALSE;
+
+   _edje_box_child_add(rp, child_obj);
+
+   return EINA_TRUE;
+}
+
+Eina_Bool
+_edje_real_part_box_prepend(Edje_Real_Part *rp, Evas_Object *child_obj)
+{
+   Evas_Object_Box_Option *opt;
+
+   opt = evas_object_box_prepend(rp->object, child_obj);
+   if (!opt) return EINA_FALSE;
+
+   _edje_box_child_add(rp, child_obj);
+
+   return EINA_TRUE;
+}
+
+Eina_Bool
+_edje_real_part_box_insert_before(Edje_Real_Part *rp, Evas_Object *child_obj, const Evas_Object *ref)
+{
+   Evas_Object_Box_Option *opt;
+
+   opt = evas_object_box_insert_before(rp->object, child_obj, ref);
+   if (!opt) return EINA_FALSE;
+
+   _edje_box_child_add(rp, child_obj);
+
+   return EINA_TRUE;
+}
+
+Eina_Bool
+_edje_real_part_box_insert_at(Edje_Real_Part *rp, Evas_Object *child_obj, unsigned int pos)
+{
+   Evas_Object_Box_Option *opt;
+
+   opt = evas_object_box_insert_at(rp->object, child_obj, pos);
+   if (!opt) return EINA_FALSE;
+
+   _edje_box_child_add(rp, child_obj);
+
+   return EINA_TRUE;
+}
+
+Evas_Object *
+_edje_real_part_box_remove(Edje_Real_Part *rp, Evas_Object *child_obj)
+{
+   if (evas_object_data_get(child_obj, "\377 edje.box_item")) return NULL;
+   if (!evas_object_box_remove(rp->object, child_obj)) return NULL;
+   _edje_box_child_remove(rp, child_obj);
+   return child_obj;
+}
+
+Evas_Object *
+_edje_real_part_box_remove_at(Edje_Real_Part *rp, unsigned int pos)
+{
+   Evas_Object_Box_Option *opt;
+   Evas_Object_Box_Data *priv;
+   Evas_Object *child_obj;
+
+   priv = evas_object_smart_data_get(rp->object);
+   opt = eina_list_nth(priv->children, pos);
+   if (!opt) return NULL;
+   child_obj = opt->obj;
+   if (evas_object_data_get(child_obj, "\377 edje.box_item")) return NULL;
+   if (!evas_object_box_remove_at(rp->object, pos)) return NULL;
+   _edje_box_child_remove(rp, child_obj);
+   return child_obj;
+}
+
+Eina_Bool
+_edje_real_part_box_remove_all(Edje_Real_Part *rp, Eina_Bool clear)
+{
+   Eina_List *children;
+   int i = 0;
+
+   children = evas_object_box_children_get(rp->object);
+   while (children)
+     {
+       Evas_Object *child_obj = children->data;
+       if (evas_object_data_get(child_obj, "\377 edje.box_item"))
+         i++;
+       else
+         {
+            _edje_box_child_remove(rp, child_obj);
+            if (!evas_object_box_remove_at(rp->object, i))
+              return EINA_FALSE;
+            if (clear)
+              evas_object_del(child_obj);
+         }
+       children = eina_list_remove_list(children, children);
+     }
+   return EINA_TRUE;
+}
+
+static void
+_edje_table_child_del_cb(void *data, Evas *e __UNUSED__, Evas_Object *child __UNUSED__, void *einfo __UNUSED__)
+{
+   Edje_Real_Part *rp = data;
+
+   rp->edje->dirty = 1;
+#ifdef EDJE_CALC_CACHE
+   rp->invalidate = 1;
+#endif
+   _edje_recalc(rp->edje);
+}
+
+static void
+_edje_table_child_add(Edje_Real_Part *rp, Evas_Object *child)
+{
+   evas_object_event_callback_add
+     (child, EVAS_CALLBACK_DEL, _edje_table_child_del_cb, rp);
+
+   rp->edje->dirty = 1;
+#ifdef EDJE_CALC_CACHE
+   rp->invalidate = 1;
+#endif
+   _edje_recalc(rp->edje);
+}
+
+static void
+_edje_table_child_remove(Edje_Real_Part *rp, Evas_Object *child)
+{
+   evas_object_event_callback_del_full
+     (child, EVAS_CALLBACK_DEL, _edje_table_child_del_cb, rp);
+
+   rp->edje->dirty = 1;
+#ifdef EDJE_CALC_CACHE
+   rp->invalidate = 1;
+#endif
+   _edje_recalc(rp->edje);
+}
+
+/**
+ * @brief Retrieve a child from a table
+ *
+ * @param obj A valid Evas_Object handle
+ * @param part The part name
+ * @param col The column of the child to get
+ * @param row The row of the child to get
+ * @return The child Evas_Object
+ */
+EAPI Evas_Object *
+edje_object_part_table_child_get(Evas_Object *obj, const char *part, unsigned int col, unsigned int row)
+{
+   Edje *ed;
+   Edje_Real_Part *rp;
+
+   ed = _edje_fetch(obj);
+   if ((!ed) || (!part)) return NULL;
+
+   rp = _edje_real_part_recursive_get(ed, part);
+   if (!rp) return NULL;
+   if (rp->part->type != EDJE_PART_TYPE_TABLE) return NULL;
+
+   return evas_object_table_child_get(rp->object, col, row);
+}
+
+/**
+ * @brief Packs an object into the table.
+ *
+ * @param obj A valid Evas_Object handle
+ * @param part The part name
+ * @param child_obj The object to pack in
+ * @param col The column to place it in
+ * @param row The row to place it in
+ * @param colspan Columns the child will take
+ * @param rowspan Rows the child will take
+ *
+ * @return 1: Successfully added.\n
+ * 0: An error occured.
+ *
+ * Packs an object into the table indicated by part.
+ */
+EAPI Eina_Bool
+edje_object_part_table_pack(Evas_Object *obj, const char *part, Evas_Object *child_obj, unsigned short col, unsigned short row, unsigned short colspan, unsigned short rowspan)
+{
+   Edje *ed;
+   Edje_Real_Part *rp;
+
+   ed = _edje_fetch(obj);
+   if ((!ed) || (!part)) return EINA_FALSE;
+
+   rp = _edje_real_part_recursive_get(ed, part);
+   if (!rp) return EINA_FALSE;
+   if (rp->part->type != EDJE_PART_TYPE_TABLE) return EINA_FALSE;
+
+   return _edje_real_part_table_pack(rp, child_obj, col, row, colspan, rowspan);
+}
+
+/**
+ * @brief Removes an object from the table.
+ *
+ * @param obj A valid Evas_Object handle
+ * @param part The part name
+ * @param child_obj The object to pack in
+ *
+ * @return 1: Successfully removed.\n
+ * 0: An error occured.
+ *
+ * Removes an object from the table indicated by part.
+ */
+EAPI Eina_Bool
+edje_object_part_table_unpack(Evas_Object *obj, const char *part, Evas_Object *child_obj)
+{
+   Edje *ed;
+   Edje_Real_Part *rp;
+
+   ed = _edje_fetch(obj);
+   if ((!ed) || (!part)) return EINA_FALSE;
+
+   rp = _edje_real_part_recursive_get(ed, part);
+   if (!rp) return EINA_FALSE;
+   if (rp->part->type != EDJE_PART_TYPE_TABLE) return EINA_FALSE;
+
+   return _edje_real_part_table_unpack(rp, child_obj);
+}
+
+/**
+ * @brief Gets the number of columns and rows the table has.
+ *
+ * @param obj A valid Evas_Object handle
+ * @param part The part name
+ * @param cols Pointer where to store number of columns (can be NULL)
+ * @param rows Pointer where to store number of rows (can be NULL)
+ *
+ * @return 1: Successfully get some data.\n
+ * 0: An error occured.
+ *
+ * Retrieves the size of the table in number of columns and rows.
+ */
+EAPI Eina_Bool
+edje_object_part_table_col_row_size_get(const Evas_Object *obj, const char *part, int *cols, int *rows)
+{
+   Edje *ed;
+   Edje_Real_Part *rp;
+
+   ed = _edje_fetch(obj);
+   if ((!ed) || (!part)) return EINA_FALSE;
+
+   rp = _edje_real_part_recursive_get(ed, part);
+   if (!rp) return EINA_FALSE;
+   if (rp->part->type != EDJE_PART_TYPE_TABLE) return EINA_FALSE;
+
+   evas_object_table_col_row_size_get(rp->object, cols, rows);
+   return EINA_TRUE;
+}
+
+/**
+ * @brief Removes all object from the table.
+ *
+ * @param obj A valid Evas_Object handle
+ * @param part The part name
+ * @param clear If set, will delete subobjs on remove
+ *
+ * @return 1: Successfully clear table.\n
+ * 0: An error occured.
+ *
+ * Removes all object from the table indicated by part, except the
+ * internal ones set from the theme.
+ */
+EAPI Eina_Bool
+edje_object_part_table_clear(Evas_Object *obj, const char *part, Eina_Bool clear)
+{
+   Edje *ed;
+   Edje_Real_Part *rp;
+
+   ed = _edje_fetch(obj);
+   if ((!ed) || (!part)) return EINA_FALSE;
+
+   rp = _edje_real_part_recursive_get(ed, part);
+   if (!rp) return EINA_FALSE;
+   if (rp->part->type != EDJE_PART_TYPE_TABLE) return EINA_FALSE;
+
+   _edje_real_part_table_clear(rp, clear);
+   return EINA_TRUE;
+}
+
+
+
+
+
+
+
+
+
+static void
+_edje_perspective_obj_del(void *data, Evas *e, Evas_Object *obj, void *event_info)
+{
+   Edje_Perspective *ps = data;   
+   Evas_Object *o;
+   
+   EINA_LIST_FREE(ps->users, o)
+     {
+        Edje *ed;
+        
+        ed = evas_object_smart_data_get(o);
+        if (!ed) continue;
+        ed->persp = NULL;
+        ed->dirty = 1;
+        _edje_recalc_do(ed);
+     }
+   free(ps);
+}
+
+EAPI Edje_Perspective *
+edje_perspective_new(Evas *e)
+{
+   Edje_Perspective *ps;
+   Evas_Coord vx, vy, vw, vh;
+   
+   if (!e) return NULL;
+   ps = calloc(1, sizeof(Edje_Perspective));
+   ps->obj = evas_object_rectangle_add(e);
+   evas_object_data_set(ps->obj, "_edje_perspective", ps);
+   evas_object_event_callback_add(ps->obj, EVAS_CALLBACK_DEL, _edje_perspective_obj_del, ps);
+   evas_output_viewport_get(e, &vx, &vy, &vw, &vh);
+   ps->e = e;
+   ps->px = vx + (vw / 2);
+   ps->py = vy + (vh / 2);
+   ps->z0 = 0;
+   ps->foc = 1000;
+   return ps;
+}
+
+EAPI void
+edje_perspective_free(Edje_Perspective *ps)
+{
+   if (!ps) return;
+   evas_object_del(ps->obj);
+}
+
+EAPI void
+edje_perspective_set(Edje_Perspective *ps, Evas_Coord px, Evas_Coord py, Evas_Coord z0, Evas_Coord foc)
+{
+   Eina_List *l;
+   Evas_Object *o;
+   
+   if (!ps) return;
+   if ((ps->px == px) && (ps->py == py) && (ps->z0 == z0) && (ps->foc == foc)) return;
+   ps->px = px;
+   ps->py = py;
+   ps->z0 = z0;
+   ps->foc = foc;
+   EINA_LIST_FOREACH(ps->users, l, o)
+     {
+        Edje *ed;
+        
+        ed = evas_object_smart_data_get(o);
+        if (!ed) continue;
+        if (!ed->persp)
+          {
+             ed->dirty = 1;
+             _edje_recalc_do(ed);
+          }
+     }
+   if (ps->global)
+     {
+        EINA_LIST_FOREACH(_edje_edjes, l, o)
+          {
+             Edje *ed;
+             
+             ed = evas_object_smart_data_get(o);
+             if (!ed) continue;
+             if (!ed->persp)
+               {
+                  ed->dirty = 1;
+                  _edje_recalc_do(ed);
+               }
+          }
+     }
+}
+
+EAPI void
+edje_perspective_global_set(Edje_Perspective *ps, Eina_Bool global)
+{
+   Evas_Object *o;
+   Eina_List *l;
+   
+   if (!ps) return;
+   if (ps->global == global) return;
+   if (global)
+     {
+        o = evas_object_name_find(evas_object_evas_get(ps->obj), 
+                                  "_edje_perspective");
+        if (o) evas_object_name_set(o, NULL);
+        evas_object_name_set(ps->obj, "_edje_perspective");
+     }
+   else
+     evas_object_name_set(ps->obj, NULL);
+   ps->global = global;
+   EINA_LIST_FOREACH(_edje_edjes, l, o)
+     {
+        Edje *ed;
+        
+        ed = evas_object_smart_data_get(o);
+        if (!ed) continue;
+        if (!ed->persp)
+          {
+             ed->dirty = 1;
+             _edje_recalc_do(ed);
+          }
+     }
+}
+
+EAPI Eina_Bool
+edje_perspective_global_get(const Edje_Perspective *ps)
+{
+   if (!ps) return 0;
+   return ps->global;
+}
+
+EAPI const Edje_Perspective *
+edje_evas_global_perspective_get(const Evas *e)
+{
+   Evas_Object *obj;
+   
+   if (!e) return NULL;
+   obj = evas_object_name_find(e, "_edje_perspective");
+   if (!obj) return NULL;
+   return evas_object_data_get(obj, "_edje_perspective");
+}
+
+EAPI void
+edje_object_perspective_set(Evas_Object *obj, Edje_Perspective *ps)
+{
+   Edje *ed;
+   
+   ed = evas_object_smart_data_get(obj);
+   if (!ed) return;
+   if (ed->persp == ps) return;
+   if (ed->persp != ps)
+     {
+        if (ed->persp)
+          ed->persp->users = eina_list_remove(ed->persp->users, obj);
+     }
+   ed->persp = ps;
+   if (ps) ps->users = eina_list_append(ps->users, obj);
+   ed->dirty = 1;
+   _edje_recalc_do(ed);
+}
+
+EAPI const Edje_Perspective *
+edje_object_perspective_get(const Evas_Object *obj)
+{
+   Edje *ed;
+   
+   ed = evas_object_smart_data_get(obj);
+   if (!ed) return NULL;
+   return ed->persp;
+}
+
+
+
+
+#define EDJE_PRELOAD_EMISSION "preload,done"
+#define EDJE_PRELOAD_SOURCE NULL
+
+EAPI Eina_Bool
+edje_object_preload(Evas_Object *obj, Eina_Bool cancel)
+{
+   Edje *ed;
+   int count;
+   int i;
+
+   ed = _edje_fetch(obj);
+   if (!ed) return EINA_FALSE;
+
+   _edje_recalc_do(ed);
+
+   for (i = 0, count = 0; i < ed->table_parts_size; i++)
+     {
+       Edje_Real_Part *rp;
+       Edje_Part *ep;
+
+       rp = ed->table_parts[i];
+       ep = rp->part;
+
+       if (ep->type == EDJE_PART_TYPE_IMAGE ||
+           (ep->type == EDJE_PART_TYPE_GROUP && rp->swallowed_object))
+         count++;
+     }
+
+   ed->preload_count = count;
+
+   if (count > 0)
+     {
+       for (i = 0; i < ed->table_parts_size; i++)
+         {
+            Edje_Real_Part *rp;
+            Edje_Part *ep;
+
+            rp = ed->table_parts[i];
+            ep = rp->part;
+
+            if (ep->type == EDJE_PART_TYPE_IMAGE)
+              {
+                 const char *file = NULL;
+                 const char *key = NULL;
+
+                 evas_object_event_callback_del_full(rp->object, EVAS_CALLBACK_IMAGE_PRELOADED, _edje_object_image_preload_cb, ed);
+
+                 evas_object_image_file_get(rp->object, &file, &key);
+                 if (!file && !key)
+                   {
+                      ed->preload_count--;
+                   }
+                 else
+                   {
+                      evas_object_event_callback_add(rp->object, EVAS_CALLBACK_IMAGE_PRELOADED, _edje_object_image_preload_cb, ed);
+                      evas_object_image_preload(rp->object, cancel);
+                   }
+                 count--;
+              }
+            else if (ep->type == EDJE_PART_TYPE_GROUP)
+              {
+                 if (rp->swallowed_object) {
+                    edje_object_signal_callback_del(rp->swallowed_object, EDJE_PRELOAD_EMISSION, EDJE_PRELOAD_SOURCE, _edje_object_signal_preload_cb);
+                    edje_object_signal_callback_add(rp->swallowed_object, EDJE_PRELOAD_EMISSION, EDJE_PRELOAD_SOURCE, _edje_object_signal_preload_cb, ed);
+                    edje_object_preload(rp->swallowed_object, cancel);
+
+                    count--;
+                 }
+              }
+         }
+     }
+   else
+     {
+       _edje_emit(ed, EDJE_PRELOAD_EMISSION, EDJE_PRELOAD_SOURCE);
+     }
+
+   return EINA_TRUE;
+}
+
+Eina_Bool
+_edje_real_part_table_pack(Edje_Real_Part *rp, Evas_Object *child_obj, unsigned short col, unsigned short row, unsigned short colspan, unsigned short rowspan)
+{
+   Eina_Bool ret = 
+     evas_object_table_pack(rp->object, child_obj, col, row, colspan, rowspan);
+
+   _edje_table_child_add(rp, child_obj);
+
+   return ret;
+}
+
+Eina_Bool
+_edje_real_part_table_unpack(Edje_Real_Part *rp, Evas_Object *child_obj)
+{
+   Eina_Bool ret = evas_object_table_unpack(rp->object, child_obj);
+
+   if (ret)
+     _edje_table_child_remove(rp, child_obj);
+
+   return ret;
+}
+
+void
+_edje_real_part_table_clear(Edje_Real_Part *rp, Eina_Bool clear)
+{
+   Eina_List *children;
+
+   children = evas_object_table_children_get(rp->object);
+   while (children)
+     {
+       Evas_Object *child_obj = children->data;
+
+       _edje_table_child_remove(rp, child_obj);
+       if (!evas_object_data_get(child_obj, "\377 edje.table_item"))
+         {
+            evas_object_table_unpack(rp->object, child_obj);
+            if (clear)
+              evas_object_del(child_obj);
+         }
+       children = eina_list_remove_list(children, children);
+     }
+}
+
+Edje_Real_Part *
+_edje_real_part_recursive_get(Edje *ed, const char *part)
+{
+   Edje_Real_Part *rp;
+   char **path;
+
+   path = eina_str_split(part, EDJE_PART_PATH_SEPARATOR_STRING, 0);
+   if (!path) return NULL;
+
+   //printf("recursive get: %s\n", part);
+   rp = _edje_real_part_recursive_get_helper(ed, path);
+
+   free(*path);
+   free(path);
+   return rp;
+}
+
+Edje_Real_Part *
+_edje_real_part_recursive_get_helper(Edje *ed, char **path)
+{
+   Edje_Real_Part *rp;
+   Evas_Object *o;
+   Eina_List *l;
+
+   //printf("  lookup: %s on %s\n", path[0], ed->parent ? ed->parent : "-");
+   rp = _edje_real_part_get(ed, path[0]);
+   if (path[1] == NULL) return rp;
+
+   if (!rp) return NULL;
+   switch (rp->part->type)
+     {
+      case EDJE_PART_TYPE_GROUP:
+       if (!rp->swallowed_object) return NULL;
+       ed = _edje_fetch(rp->swallowed_object);
+       if (!ed) return NULL;
+       path++;
+       return _edje_real_part_recursive_get_helper(ed, path);
+      case EDJE_PART_TYPE_BOX: case EDJE_PART_TYPE_TABLE:
+       if (!rp->items) return NULL;
+       path++;
+       EINA_LIST_FOREACH(rp->items, l, o)
+          {
+             ed = _edje_fetch(o);
+             if (!ed) return NULL;
+             if ((rp = _edje_real_part_recursive_get_helper(ed, path)))
+               return rp;
+          }
+       return NULL;
+      default:
+       return NULL;
+     }
+}
+
+
+/* Private Routines */
+
+Edje_Real_Part *
+_edje_real_part_get(Edje *ed, const char *part)
+{
+   int i;
+
+   for (i = 0; i < ed->table_parts_size; i++)
+     {
+       Edje_Real_Part *rp;
+
+       rp = ed->table_parts[i];
+       if ((rp->part->name) && (!strcmp(rp->part->name, part))) return rp;
+     }
+   return NULL;
+}
+
+Edje_Color_Class *
+_edje_color_class_find(Edje *ed, const char *color_class)
+{
+   Eina_List *l;
+   Edje_Color_Class *cc = NULL;
+
+   if ((!ed) || (!color_class)) return NULL;
+
+   /* first look through the object scope */
+   EINA_LIST_FOREACH(ed->color_classes, l, cc)
+     if ((cc->name) && (!strcmp(color_class, cc->name))) return cc;
+
+   /* next look through the global scope */
+   cc = eina_hash_find(_edje_color_class_hash, color_class);
+   if (cc) return cc;
+
+   /* finally, look through the file scope */
+   EINA_LIST_FOREACH(ed->file->color_classes, l, cc)
+     if ((cc->name) && (!strcmp(color_class, cc->name))) return cc;
+
+   return NULL;
+}
+
+void
+_edje_color_class_member_add(Edje *ed, const char *color_class)
+{
+   Eina_List *members;
+
+   if ((!ed) || (!color_class)) return;
+   members = eina_hash_find(_edje_color_class_member_hash, color_class);
+   if (members)
+     eina_hash_del(_edje_color_class_member_hash, color_class, members);
+
+   members = eina_list_prepend(members, ed);
+   if (!_edje_color_class_member_hash) _edje_color_class_member_hash = eina_hash_string_superfast_new(NULL);
+   eina_hash_add(_edje_color_class_member_hash, color_class, members);
+}
+
+void
+_edje_color_class_member_del(Edje *ed, const char *color_class)
+{
+   Eina_List *members;
+
+   if ((!ed) || (!color_class)) return;
+   members = eina_hash_find(_edje_color_class_member_hash, color_class);
+   if (!members) return;
+
+   eina_hash_del(_edje_color_class_member_hash, color_class, members);
+   members = eina_list_remove(members, ed);
+   if (members)
+     eina_hash_add(_edje_color_class_member_hash, color_class, members);
+}
+
+/**
+ * Used to free the member lists that are stored in the text_class and
+ * color_class hashtables.
+ */
+static Eina_Bool
+member_list_free(const Eina_Hash *hash __UNUSED__, const void *key __UNUSED__, void *data, void *fdata __UNUSED__)
+{
+   eina_list_free(data);
+   return EINA_TRUE;
+}
+
+void
+_edje_color_class_members_free(void)
+{
+   if (!_edje_color_class_member_hash) return;
+   eina_hash_foreach(_edje_color_class_member_hash, member_list_free, NULL);
+   eina_hash_free(_edje_color_class_member_hash);
+   _edje_color_class_member_hash = NULL;
+}
+
+static Eina_Bool
+color_class_hash_list_free(const Eina_Hash *hash __UNUSED__, const void *key __UNUSED__, void *data, void *fdata __UNUSED__)
+{
+   Edje_Color_Class *cc;
+
+   cc = data;
+   if (cc->name) eina_stringshare_del(cc->name);
+   free(cc);
+   return EINA_TRUE;
+}
+
+void
+_edje_color_class_hash_free(void)
+{
+   if (!_edje_color_class_hash) return;
+   eina_hash_foreach(_edje_color_class_hash, color_class_hash_list_free, NULL);
+   eina_hash_free(_edje_color_class_hash);
+   _edje_color_class_hash = NULL;
+}
+
+void
+_edje_color_class_on_del(Edje *ed, Edje_Part *ep)
+{
+   Eina_List *tmp;
+   Edje_Part_Description *desc;
+
+   if ((ep->default_desc) && (ep->default_desc->color_class))
+     _edje_color_class_member_del(ed, ep->default_desc->color_class);
+
+   EINA_LIST_FOREACH(ep->other_desc, tmp, desc)
+     if (desc->color_class)
+       _edje_color_class_member_del(ed, desc->color_class);
+}
+
+Edje_Text_Class *
+_edje_text_class_find(Edje *ed, const char *text_class)
+{
+   Eina_List *l;
+   Edje_Text_Class *tc;
+
+   if ((!ed) || (!text_class)) return NULL;
+   EINA_LIST_FOREACH(ed->text_classes, l, tc)
+     if ((tc->name) && (!strcmp(text_class, tc->name))) return tc;
+   return eina_hash_find(_edje_text_class_hash, text_class);
+}
+
+void
+_edje_text_class_member_add(Edje *ed, const char *text_class)
+{
+   Eina_List *members;
+
+   if ((!ed) || (!text_class)) return;
+
+   /* Get members list */
+   members = eina_hash_find(_edje_text_class_member_hash, text_class);
+
+   /* Remove members list */
+   if (members)
+     eina_hash_del(_edje_text_class_member_hash, text_class, members);
+
+   /* Update the member list */
+   members = eina_list_prepend(members, ed);
+
+   /* Add the member list back */
+   if (!_edje_text_class_member_hash) 
+     _edje_text_class_member_hash = eina_hash_string_superfast_new(NULL);
+   eina_hash_add(_edje_text_class_member_hash, text_class, members);
+}
+
+void
+_edje_text_class_member_del(Edje *ed, const char *text_class)
+{
+   Eina_List *members;
+
+   if ((!ed) || (!text_class)) return;
+   members = eina_hash_find(_edje_text_class_member_hash, text_class);
+   if (!members) return;
+
+   eina_hash_del(_edje_text_class_member_hash, text_class, members);
+
+   members = eina_list_remove(members, ed);
+   if (members)
+     eina_hash_add(_edje_text_class_member_hash, text_class, members);
+}
+
+void
+_edje_text_class_members_free(void)
+{
+   if (!_edje_text_class_member_hash) return;
+   eina_hash_foreach(_edje_text_class_member_hash, member_list_free, NULL);
+   eina_hash_free(_edje_text_class_member_hash);
+   _edje_text_class_member_hash = NULL;
+}
+
+static Eina_Bool
+text_class_hash_list_free(const Eina_Hash *hash __UNUSED__, const void *key __UNUSED__, void *data, void *fdata __UNUSED__)
+{
+   Edje_Text_Class *tc;
+
+   tc = data;
+   if (tc->name) eina_stringshare_del(tc->name);
+   if (tc->font) eina_stringshare_del(tc->font);
+   free(tc);
+   return EINA_TRUE;
+}
+
+void
+_edje_text_class_hash_free(void)
+{
+   if (!_edje_text_class_hash) return;
+   eina_hash_foreach(_edje_text_class_hash, text_class_hash_list_free, NULL);
+   eina_hash_free(_edje_text_class_hash);
+   _edje_text_class_hash = NULL;
+}
+
+Edje *
+_edje_fetch(const Evas_Object *obj)
+{
+   Edje *ed;
+
+   if (!evas_object_smart_type_check(obj, "edje"))
+     return NULL;
+   ed = evas_object_smart_data_get(obj);
+   if ((ed) && (ed->delete_me)) return NULL;
+   return ed;
+}
+
+int
+_edje_freeze(Edje *ed)
+{
+   ed->freeze++;
+//   printf("FREEZE %i\n", ed->freeze);
+   return ed->freeze;
+}
+
+int
+_edje_thaw(Edje *ed)
+{
+   ed->freeze--;
+   if (ed->freeze < 0)
+     {
+//     printf("-------------########### OVER THAW\n");
+       ed->freeze = 0;
+     }
+   if ((ed->freeze == 0) && (ed->recalc))
+     {
+//     printf("thaw recalc\n");
+       _edje_recalc(ed);
+     }
+   return ed->freeze;
+}
+
+int
+_edje_block(Edje *ed)
+{
+   _edje_ref(ed);
+   ed->block++;
+   return ed->block;
+}
+
+int
+_edje_unblock(Edje *ed)
+{
+   int ret = 0;
+
+   if (!ed) return ret;
+
+   ed->block--;
+   if (ed->block == 0) ed->block_break = 0;
+   ret = ed->block;
+   _edje_unref(ed);
+   return ret;
+}
+
+int
+_edje_block_break(Edje *ed)
+{
+   if (ed->block_break) return 1;
+   return 0;
+}
+
+void
+_edje_block_violate(Edje *ed)
+{
+   if (ed->block > 0) ed->block_break = 1;
+}
+void
+_edje_object_part_swallow_free_cb(void *data, Evas *e, Evas_Object *obj, void *event_info)
+{
+   Evas_Object *edje_obj;
+
+   edje_obj = data;
+   edje_object_part_unswallow(edje_obj, obj);
+   return;
+   e = NULL;
+   event_info = NULL;
+}
+
+static void
+_edje_real_part_swallow_hints_update(Edje_Real_Part *rp)
+{
+   char *type;
+
+   type = (char *)evas_object_type_get(rp->swallowed_object);
+   
+   rp->swallow_params.min.w = 0;
+   rp->swallow_params.min.h = 0;
+   rp->swallow_params.max.w = -1;
+   rp->swallow_params.max.h = -1;
+   if ((type) && (!strcmp(type, "edje")))
+     {
+       Evas_Coord w, h;
+
+       edje_object_size_min_get(rp->swallowed_object, &w, &h);
+       rp->swallow_params.min.w = w;
+       rp->swallow_params.min.h = h;
+       edje_object_size_max_get(rp->swallowed_object, &w, &h);
+       rp->swallow_params.max.w = w;
+       rp->swallow_params.max.h = h;
+     }
+   else if ((type) && ((!strcmp(type, "text")) || (!strcmp(type, "polygon")) ||
+                      (!strcmp(type, "line"))))
+     {
+       Evas_Coord w, h;
+
+       evas_object_geometry_get(rp->swallowed_object, NULL, NULL, &w, &h);
+       rp->swallow_params.min.w = w;
+       rp->swallow_params.min.h = h;
+       rp->swallow_params.max.w = w;
+       rp->swallow_params.max.h = h;
+     }
+     {
+       Evas_Coord w1, h1, w2, h2, aw, ah;
+       Evas_Aspect_Control am;
+
+       evas_object_size_hint_min_get(rp->swallowed_object, &w1, &h1);
+       evas_object_size_hint_max_get(rp->swallowed_object, &w2, &h2);
+       evas_object_size_hint_aspect_get(rp->swallowed_object, &am, &aw, &ah);
+       rp->swallow_params.min.w = w1;
+       rp->swallow_params.min.h = h1;
+       if (w2 > 0) rp->swallow_params.max.w = w2;
+       if (h2 > 0) rp->swallow_params.max.h = h2;
+       switch (am)
+         {
+          case EVAS_ASPECT_CONTROL_NONE: 
+             rp->swallow_params.aspect.mode = EDJE_ASPECT_CONTROL_NONE; 
+             break;
+          case EVAS_ASPECT_CONTROL_NEITHER: 
+             rp->swallow_params.aspect.mode = EDJE_ASPECT_CONTROL_NEITHER; 
+             break;
+          case EVAS_ASPECT_CONTROL_HORIZONTAL: 
+             rp->swallow_params.aspect.mode = EDJE_ASPECT_CONTROL_HORIZONTAL; 
+             break;
+          case EVAS_ASPECT_CONTROL_VERTICAL: 
+             rp->swallow_params.aspect.mode = EDJE_ASPECT_CONTROL_VERTICAL;
+             break;
+          case EVAS_ASPECT_CONTROL_BOTH: 
+             rp->swallow_params.aspect.mode = EDJE_ASPECT_CONTROL_BOTH; 
+             break;
+          default: 
+             break;
+         }
+       rp->swallow_params.aspect.w = aw;
+       rp->swallow_params.aspect.h = ah;
+       evas_object_data_set(rp->swallowed_object, "\377 edje.swallowing_part", rp);
+     }
+
+#ifdef EDJE_CALC_CACHE
+     rp->invalidate = 1;
+#endif
+}
+
+void
+_edje_object_part_swallow_changed_hints_cb(void *data, Evas *e, Evas_Object *obj, void *event_info)
+{
+   Edje_Real_Part *rp;
+   
+   rp = data;
+   _edje_real_part_swallow_hints_update(rp);
+   rp->edje->dirty = 1;
+   _edje_recalc(rp->edje);
+   return;
+   e = NULL;
+   event_info = NULL;
+}
+
+void
+_edje_real_part_swallow(Edje_Real_Part *rp, Evas_Object *obj_swallow)
+{
+   if (rp->swallowed_object)
+     {
+        if (rp->swallowed_object != obj_swallow)
+          {
+             _edje_real_part_swallow_clear(rp);
+             rp->swallowed_object = NULL;
+          }
+        else
+          {
+             _edje_real_part_swallow_hints_update(rp);
+             rp->edje->dirty = 1;
+             _edje_recalc(rp->edje);
+             return;
+          }
+     }
+#ifdef EDJE_CALC_CACHE
+   rp->invalidate = 1;
+#endif
+   if (!obj_swallow) return;
+   rp->swallowed_object = obj_swallow;
+   evas_object_smart_member_add(rp->swallowed_object, rp->edje->obj);
+   if (rp->clip_to)
+     evas_object_clip_set(rp->swallowed_object, rp->clip_to->object);
+   else evas_object_clip_set(rp->swallowed_object, rp->edje->clipper);
+   evas_object_stack_above(rp->swallowed_object, rp->object);
+   evas_object_event_callback_add(rp->swallowed_object, 
+                                  EVAS_CALLBACK_FREE,
+                                 _edje_object_part_swallow_free_cb,
+                                 rp->edje->obj);
+   evas_object_event_callback_add(rp->swallowed_object, 
+                                  EVAS_CALLBACK_CHANGED_SIZE_HINTS,
+                                 _edje_object_part_swallow_changed_hints_cb,
+                                 rp);
+   
+   _edje_real_part_swallow_hints_update(rp);
+   
+   if (rp->part->mouse_events)
+     {
+        _edje_callbacks_add(obj_swallow, rp->edje, rp);
+       if (rp->part->repeat_events)
+           evas_object_repeat_events_set(obj_swallow, 1);
+       if (rp->part->pointer_mode != EVAS_OBJECT_POINTER_MODE_AUTOGRAB)
+         evas_object_pointer_mode_set(obj_swallow, rp->part->pointer_mode);
+       evas_object_pass_events_set(obj_swallow, 0);
+     }
+   else
+     evas_object_pass_events_set(obj_swallow, 1);
+   _edje_callbacks_focus_add(rp->swallowed_object, rp->edje, rp);
+
+   if (rp->part->precise_is_inside)
+     evas_object_precise_is_inside_set(obj_swallow, 1);
+
+   rp->edje->dirty = 1;
+   _edje_recalc(rp->edje);
+}
+
+void
+_edje_real_part_swallow_clear(Edje_Real_Part *rp)
+{
+   evas_object_smart_member_del(rp->swallowed_object);
+   evas_object_event_callback_del_full(rp->swallowed_object,
+                                       EVAS_CALLBACK_FREE,
+                                       _edje_object_part_swallow_free_cb,
+                                       rp->edje->obj);
+   evas_object_event_callback_del_full(rp->swallowed_object,
+                                       EVAS_CALLBACK_CHANGED_SIZE_HINTS,
+                                       _edje_object_part_swallow_changed_hints_cb,
+                                       rp);
+   evas_object_clip_unset(rp->swallowed_object);
+   evas_object_data_del(rp->swallowed_object, "\377 edje.swallowing_part");
+   if (rp->part->mouse_events)
+     _edje_callbacks_del(rp->swallowed_object, rp->edje);
+   _edje_callbacks_focus_del(rp->swallowed_object, rp->edje);
+}
+
+static void
+_edje_object_preload(Edje *ed)
+{
+   ed->preload_count--;
+   if (!ed->preload_count)
+     _edje_emit(ed, EDJE_PRELOAD_EMISSION, EDJE_PRELOAD_SOURCE);
+}
+
+static void
+_edje_object_image_preload_cb(void *data, Evas *e, Evas_Object *obj, void *event_info)
+{
+   Edje *ed = data;
+
+   evas_object_event_callback_del_full(obj, EVAS_CALLBACK_IMAGE_PRELOADED, _edje_object_image_preload_cb, ed);
+   _edje_object_preload(ed);
+}
+
+static void
+_edje_object_signal_preload_cb(void *data, Evas_Object *obj, const char *emission, const char *source)
+{
+   Edje *ed = data;
+
+   edje_object_signal_callback_del(obj, EDJE_PRELOAD_EMISSION, EDJE_PRELOAD_SOURCE, _edje_object_signal_preload_cb);
+   _edje_object_preload(ed);
+}
diff --git a/src/lib/edje_var.c b/src/lib/edje_var.c
new file mode 100644 (file)
index 0000000..4ba8b36
--- /dev/null
@@ -0,0 +1,1059 @@
+/*
+ * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
+ */
+
+#include <string.h>
+
+#include "edje_private.h"
+
+static int _edje_var_timer_cb(void *data);
+static int _edje_var_anim_cb(void *data);
+
+static Ecore_Animator *_edje_animator = NULL;
+static Eina_List   *_edje_anim_list = NULL;
+
+static int
+_edje_var_timer_cb(void *data)
+{
+   Edje_Var_Timer *et;
+   Edje *ed;
+   Embryo_Function fn;
+
+   et = data;
+   if (!et) return 0;
+   ed = et->edje;
+//      _edje_embryo_script_reset(ed);
+   embryo_program_vm_push(ed->collection->script);
+   _edje_embryo_globals_init(ed);
+   embryo_parameter_cell_push(ed->collection->script, (Embryo_Cell)et->val);
+   ed->var_pool->timers = eina_list_remove(ed->var_pool->timers, et);
+   fn = et->func;
+   free(et);
+     {
+       void *pdata;
+
+       pdata = embryo_program_data_get(ed->collection->script);
+       embryo_program_data_set(ed->collection->script, ed);
+        embryo_program_max_cycle_run_set(ed->collection->script, 5000000);
+       embryo_program_run(ed->collection->script, fn);
+       embryo_program_data_set(ed->collection->script, pdata);
+       embryo_program_vm_pop(ed->collection->script);
+       _edje_recalc(ed);
+     }
+   return 0;
+}
+
+static int
+_edje_var_anim_cb(void *data __UNUSED__)
+{
+   Eina_List *l, *tl = NULL;
+   double t;
+   const void *tmp;
+
+   t = ecore_loop_time_get();
+   EINA_LIST_FOREACH(_edje_anim_list, l, tmp)
+     tl = eina_list_append(tl, tmp);
+   while (tl)
+     {
+       Edje *ed;
+       Eina_List *tl2;
+       Edje_Var_Animator *ea;
+
+       ed = eina_list_data_get(tl);
+       _edje_ref(ed);
+       _edje_block(ed);
+       _edje_freeze(ed);
+       tl = eina_list_remove(tl, ed);
+       if (!ed->var_pool) continue;
+       tl2 = NULL;
+       EINA_LIST_FOREACH(ed->var_pool->animators, l, tmp)
+         tl2 = eina_list_append(tl2, tmp);
+       ed->var_pool->walking_list++;
+       while (tl2)
+         {
+            Edje_Var_Animator *ea;
+
+            ea = eina_list_data_get(tl2);
+            if ((ed->var_pool) && (!ea->delete_me))
+              {
+                 if ((!ed->paused) && (!ed->delete_me))
+                   {
+                      Embryo_Function fn;
+                      float v;
+
+                      v = (t - ea->start)  / ea->len;
+                      if (v > 1.0) v= 1.0;
+//                    _edje_embryo_script_reset(ed);
+                      embryo_program_vm_push(ed->collection->script);
+                      _edje_embryo_globals_init(ed);
+                      embryo_parameter_cell_push(ed->collection->script, (Embryo_Cell)ea->val);
+                      embryo_parameter_cell_push(ed->collection->script, EMBRYO_FLOAT_TO_CELL(v));
+                      fn = ea->func;
+                        {
+                           void *pdata;
+
+                           pdata = embryo_program_data_get(ed->collection->script);
+                           embryo_program_data_set(ed->collection->script, ed);
+                           embryo_program_max_cycle_run_set(ed->collection->script, 5000000);
+                           embryo_program_run(ed->collection->script, fn);
+                           embryo_program_data_set(ed->collection->script, pdata);
+                           embryo_program_vm_pop(ed->collection->script);
+                           _edje_recalc(ed);
+                        }
+                      if (v == 1.0) ea->delete_me = 1;
+                   }
+              }
+            tl2 = eina_list_remove(tl2, ea);
+            if (ed->block_break)
+              {
+                 eina_list_free(tl2);
+                 break;
+              }
+         }
+       ed->var_pool->walking_list--;
+       EINA_LIST_FOREACH(ed->var_pool->animators, l, ea)
+         {
+            if (ea->delete_me)
+              {
+                l = eina_list_next(l);
+                 ed->var_pool->animators = eina_list_remove(ed->var_pool->animators, ea);
+                 free(ea);
+              }
+            else
+              l = eina_list_next(l);
+         }
+       if (!ed->var_pool->animators)
+         _edje_anim_list = eina_list_remove(_edje_anim_list, ed);
+       _edje_unblock(ed);
+       _edje_thaw(ed);
+       _edje_unref(ed);
+     }
+   if (!_edje_anim_list)
+     {
+       if (_edje_animator)
+         {
+            ecore_animator_del(_edje_animator);
+            _edje_animator = NULL;
+         }
+     }
+   return !!_edje_animator;
+}
+
+Edje_Var *
+_edje_var_new(void)
+{
+   return calloc(1, sizeof(Edje_Var));
+}
+
+void
+_edje_var_free(Edje_Var *var)
+{
+   if (var->type == EDJE_VAR_STRING)
+     {
+       if (var->data.s.v)
+         {
+            free(var->data.s.v);
+         }
+     }
+   free(var);
+}
+
+void
+_edje_var_init(Edje *ed)
+{
+   if (!ed) return;
+   if (!ed->collection) return;
+   if (!ed->collection->script) return;
+   if (ed->var_pool) return;
+   ed->var_pool = calloc(1, sizeof(Edje_Var_Pool));
+   if (!ed->var_pool) return;
+   embryo_program_vm_push(ed->collection->script);
+   ed->var_pool->size = embryo_program_variable_count_get(ed->collection->script);
+   embryo_program_vm_pop(ed->collection->script);
+   if (ed->var_pool->size > 0)
+     ed->var_pool->vars = calloc(1, sizeof(Edje_Var) * ed->var_pool->size);
+}
+
+void
+_edje_var_shutdown(Edje *ed)
+{
+   if (!ed->var_pool) return;
+   if (ed->var_pool->vars)
+     {
+       int i;
+
+       for (i = 0; i < ed->var_pool->size; i++)
+         {
+            if (ed->var_pool->vars[i].type == EDJE_VAR_STRING)
+              {
+                 if (ed->var_pool->vars[i].data.s.v)
+                   {
+                      free(ed->var_pool->vars[i].data.s.v);
+                      ed->var_pool->vars[i].data.s.v = NULL;
+                   }
+              }
+            else if (ed->var_pool->vars[i].type == EDJE_VAR_LIST)
+              {
+                 while (ed->var_pool->vars[i].data.l.v)
+                   {
+                      _edje_var_free(eina_list_data_get(ed->var_pool->vars[i].data.l.v));
+                      ed->var_pool->vars[i].data.l.v = eina_list_remove_list(ed->var_pool->vars[i].data.l.v, ed->var_pool->vars[i].data.l.v);
+                   }
+              }
+         }
+       free(ed->var_pool->vars);
+     }
+   while (ed->var_pool->timers)
+     {
+       Edje_Var_Timer *et;
+
+       et = eina_list_data_get(ed->var_pool->timers);
+       ecore_timer_del(et->timer);
+       free(et);
+       ed->var_pool->timers = eina_list_remove(ed->var_pool->timers, et);
+     }
+   if (ed->var_pool->animators)
+     {
+       _edje_anim_list = eina_list_remove(_edje_anim_list, ed);
+       if (!_edje_anim_list)
+         {
+            if (_edje_animator)
+              {
+                 ecore_animator_del(_edje_animator);
+                 _edje_animator = NULL;
+              }
+         }
+     }
+   while (ed->var_pool->animators)
+     {
+       Edje_Var_Animator *ea;
+
+       ea = eina_list_data_get(ed->var_pool->animators);
+       free(ea);
+       ed->var_pool->animators = eina_list_remove(ed->var_pool->animators, ea);
+     }
+   free(ed->var_pool);
+   ed->var_pool = NULL;
+}
+
+int
+_edje_var_string_id_get(Edje *ed, const char *string)
+{
+   Embryo_Cell cell, *cptr;
+
+   if (!ed) return 0;
+   if (!ed->collection) return 0;
+   if (!ed->collection->script) return 0;
+   if (!string) return 0;
+   cell = embryo_program_variable_find(ed->collection->script, (char *)string);
+   if (cell == EMBRYO_CELL_NONE) return  0;
+   cptr = embryo_data_address_get(ed->collection->script, cell);
+   if (!cptr) return 0;
+   return (int)(*cptr);
+}
+
+int
+_edje_var_var_int_get(Edje *ed __UNUSED__, Edje_Var *var)
+{
+   /* auto-cast */
+   if (var->type == EDJE_VAR_STRING)
+     {
+       if (var->data.s.v)
+         {
+            double f;
+
+            f = atof(var->data.s.v);
+            free(var->data.s.v);
+            var->data.s.v = NULL;
+            var->data.i.v = (int)f;
+         }
+       var->type = EDJE_VAR_INT;
+     }
+   else if (var->type == EDJE_VAR_FLOAT)
+     {
+       var->data.i.v = (int)(var->data.f.v);
+       var->type = EDJE_VAR_INT;
+     }
+   else if (var->type == EDJE_VAR_NONE)
+     {
+       var->type = EDJE_VAR_INT;
+     }
+   else if (var->type == EDJE_VAR_LIST)
+     {
+       return 0;
+     }
+   else if (var->type == EDJE_VAR_HASH)
+     {
+       return 0;
+     }
+   return var->data.i.v;
+}
+
+void
+_edje_var_var_int_set(Edje *ed __UNUSED__, Edje_Var *var, int v)
+{
+   /* auto-cast */
+   if (var->type == EDJE_VAR_STRING)
+     {
+       if (var->data.s.v)
+         {
+            free(var->data.s.v);
+            var->data.s.v = NULL;
+         }
+       var->type = EDJE_VAR_INT;
+     }
+   else if (var->type == EDJE_VAR_FLOAT)
+     {
+       var->type = EDJE_VAR_INT;
+     }
+   else if (var->type == EDJE_VAR_NONE)
+     {
+       var->type = EDJE_VAR_INT;
+     }
+   else if (var->type == EDJE_VAR_LIST)
+     {
+       return;
+     }
+   else if (var->type == EDJE_VAR_HASH)
+     {
+       return;
+     }
+   var->data.i.v = v;
+}
+
+double
+_edje_var_var_float_get(Edje *ed __UNUSED__, Edje_Var *var)
+{
+   /* auto-cast */
+   if (var->type == EDJE_VAR_STRING)
+     {
+       if (var->data.s.v)
+         {
+            double f;
+
+            f = atof(var->data.s.v);
+            free(var->data.s.v);
+            var->data.s.v = NULL;
+            var->data.f.v = f;
+         }
+       var->type = EDJE_VAR_FLOAT;
+     }
+   else if (var->type == EDJE_VAR_INT)
+     {
+       var->data.f.v = (double)(var->data.i.v);
+       var->type = EDJE_VAR_FLOAT;
+     }
+   else if (var->type == EDJE_VAR_NONE)
+     {
+       var->type = EDJE_VAR_FLOAT;
+     }
+   else if (var->type == EDJE_VAR_LIST)
+     {
+       return 0.0;
+     }
+   else if (var->type == EDJE_VAR_HASH)
+     {
+       return 0.0;
+     }
+   return var->data.f.v;
+}
+
+void
+_edje_var_var_float_set(Edje *ed __UNUSED__, Edje_Var *var, double v)
+{
+   /* auto-cast */
+   if (var->type == EDJE_VAR_STRING)
+     {
+       if (var->data.s.v)
+         {
+            free(var->data.s.v);
+            var->data.s.v = NULL;
+         }
+       var->type = EDJE_VAR_FLOAT;
+     }
+   else if (var->type == EDJE_VAR_INT)
+     {
+       var->data.f.v = 0;
+       var->type = EDJE_VAR_FLOAT;
+     }
+   else if (var->type == EDJE_VAR_NONE)
+     {
+       var->type = EDJE_VAR_FLOAT;
+     }
+   else if (var->type == EDJE_VAR_LIST)
+     {
+       return;
+     }
+   else if (var->type == EDJE_VAR_HASH)
+     {
+       return;
+     }
+   var->data.f.v = v;
+}
+
+const char *
+_edje_var_var_str_get(Edje *ed __UNUSED__, Edje_Var *var)
+{
+   /* auto-cast */
+   if (var->type == EDJE_VAR_INT)
+     {
+       char buf[64];
+
+       snprintf(buf, sizeof(buf), "%i", var->data.i.v);
+       var->data.s.v = strdup(buf);
+       var->type = EDJE_VAR_STRING;
+     }
+   else if (var->type == EDJE_VAR_FLOAT)
+     {
+       char buf[64];
+
+       snprintf(buf, sizeof(buf), "%f", var->data.f.v);
+       var->data.s.v = strdup(buf);
+       var->type = EDJE_VAR_STRING;
+     }
+   else if (var->type == EDJE_VAR_NONE)
+     {
+       var->data.s.v = strdup("");
+       var->type = EDJE_VAR_STRING;
+     }
+   else if (var->type == EDJE_VAR_LIST)
+     {
+       return NULL;
+     }
+   else if (var->type == EDJE_VAR_HASH)
+     {
+       return NULL;
+     }
+   return var->data.s.v;
+}
+
+void
+_edje_var_var_str_set(Edje *ed __UNUSED__, Edje_Var *var, const char *str)
+{
+   /* auto-cast */
+   if (var->type == EDJE_VAR_STRING)
+     {
+       if (var->data.s.v)
+         {
+            free(var->data.s.v);
+            var->data.s.v = NULL;
+         }
+     }
+   else if (var->type == EDJE_VAR_INT)
+     {
+       var->type = EDJE_VAR_STRING;
+     }
+   else if (var->type == EDJE_VAR_FLOAT)
+     {
+       var->type = EDJE_VAR_STRING;
+     }
+   else if (var->type == EDJE_VAR_NONE)
+     {
+       var->type = EDJE_VAR_STRING;
+     }
+   else if (var->type == EDJE_VAR_LIST)
+     {
+       return;
+     }
+   else if (var->type == EDJE_VAR_HASH)
+     {
+       return;
+     }
+   var->data.s.v = strdup(str);
+}
+
+int
+_edje_var_int_get(Edje *ed, int id)
+{
+   if (!ed) return 0;
+   if (!ed->var_pool) return 0;
+   id -= EDJE_VAR_MAGIC_BASE;
+   if ((id < 0) || (id >= ed->var_pool->size)) return 0;
+   return _edje_var_var_int_get(ed, &(ed->var_pool->vars[id]));
+}
+
+void
+_edje_var_int_set(Edje *ed, int id, int v)
+{
+   if (!ed) return;
+   if (!ed->var_pool) return;
+   id -= EDJE_VAR_MAGIC_BASE;
+   if ((id < 0) || (id >= ed->var_pool->size)) return;
+   _edje_var_var_int_set(ed, &(ed->var_pool->vars[id]), v);
+}
+
+double
+_edje_var_float_get(Edje *ed, int id)
+{
+   if (!ed) return 0;
+   if (!ed->var_pool) return 0;
+   id -= EDJE_VAR_MAGIC_BASE;
+   if ((id < 0) || (id >= ed->var_pool->size)) return 0;
+   return _edje_var_var_float_get(ed, &(ed->var_pool->vars[id]));
+}
+
+void
+_edje_var_float_set(Edje *ed, int id, double v)
+{
+   if (!ed) return;
+   if (!ed->var_pool) return;
+   id -= EDJE_VAR_MAGIC_BASE;
+   if ((id < 0) || (id >= ed->var_pool->size)) return;
+   _edje_var_var_float_set(ed, &(ed->var_pool->vars[id]), v);
+}
+
+const char *
+_edje_var_str_get(Edje *ed, int id)
+{
+   if (!ed) return NULL;
+   if (!ed->var_pool) return NULL;
+   id -= EDJE_VAR_MAGIC_BASE;
+   if ((id < 0) || (id >= ed->var_pool->size)) return NULL;
+   return _edje_var_var_str_get(ed, &(ed->var_pool->vars[id]));
+}
+
+void
+_edje_var_str_set(Edje *ed, int id, const char *str)
+{
+   if (!ed) return;
+   if (!ed->var_pool) return;
+   if (!str) return;
+   id -= EDJE_VAR_MAGIC_BASE;
+   if ((id < 0) || (id >= ed->var_pool->size)) return;
+   _edje_var_var_str_set(ed, &(ed->var_pool->vars[id]), str);
+}
+
+/* list stuff */
+
+void
+_edje_var_list_var_append(Edje *ed, int id, Edje_Var *var)
+{
+   if (!ed) return;
+   if (!ed->var_pool) return;
+   id -= EDJE_VAR_MAGIC_BASE;
+   if ((id < 0) || (id >= ed->var_pool->size)) return;
+   if (ed->var_pool->vars[id].type != EDJE_VAR_LIST) return;
+   ed->var_pool->vars[id].data.l.v = eina_list_append(ed->var_pool->vars[id].data.l.v, var);
+}
+
+void
+_edje_var_list_var_prepend(Edje *ed, int id, Edje_Var *var)
+{
+   if (!ed) return;
+   if (!ed->var_pool) return;
+   id -= EDJE_VAR_MAGIC_BASE;
+   if ((id < 0) || (id >= ed->var_pool->size)) return;
+   if (ed->var_pool->vars[id].type != EDJE_VAR_LIST) return;
+   ed->var_pool->vars[id].data.l.v = eina_list_prepend(ed->var_pool->vars[id].data.l.v, var);
+}
+
+void
+_edje_var_list_var_append_relative(Edje *ed, int id, Edje_Var *var, Edje_Var *relative)
+{
+   if (!ed) return;
+   if (!ed->var_pool) return;
+   id -= EDJE_VAR_MAGIC_BASE;
+   if ((id < 0) || (id >= ed->var_pool->size)) return;
+   if (ed->var_pool->vars[id].type != EDJE_VAR_LIST) return;
+   ed->var_pool->vars[id].data.l.v = eina_list_append_relative(ed->var_pool->vars[id].data.l.v, var, relative);
+}
+
+void
+_edje_var_list_var_prepend_relative(Edje *ed, int id, Edje_Var *var, Edje_Var *relative)
+{
+   if (!ed) return;
+   if (!ed->var_pool) return;
+   id -= EDJE_VAR_MAGIC_BASE;
+   if ((id < 0) || (id >= ed->var_pool->size)) return;
+   if (ed->var_pool->vars[id].type != EDJE_VAR_LIST) return;
+   ed->var_pool->vars[id].data.l.v = eina_list_prepend_relative(ed->var_pool->vars[id].data.l.v, var, relative);
+}
+
+Edje_Var *
+_edje_var_list_nth(Edje *ed, int id, int n)
+{
+   if (!ed) return NULL;
+   if (!ed->var_pool) return NULL;
+   id -= EDJE_VAR_MAGIC_BASE;
+   if ((id < 0) || (id >= ed->var_pool->size)) return NULL;
+   if (ed->var_pool->vars[id].type != EDJE_VAR_LIST) return NULL;
+   return eina_list_nth(ed->var_pool->vars[id].data.l.v, n);
+}
+
+int
+_edje_var_list_count_get(Edje *ed, int id)
+{
+   if (!ed) return 0;
+   if (!ed->var_pool) return 0;
+   id -= EDJE_VAR_MAGIC_BASE;
+   if ((id < 0) || (id >= ed->var_pool->size)) return 0;
+   if (ed->var_pool->vars[id].type == EDJE_VAR_NONE)
+     ed->var_pool->vars[id].type = EDJE_VAR_LIST;
+   else if (ed->var_pool->vars[id].type != EDJE_VAR_LIST) return 0;
+   return eina_list_count(ed->var_pool->vars[id].data.l.v);
+}
+
+void
+_edje_var_list_remove_nth(Edje *ed, int id, int n)
+{
+   if (!ed) return;
+   if (!ed->var_pool) return;
+   id -= EDJE_VAR_MAGIC_BASE;
+   if ((id < 0) || (id >= ed->var_pool->size)) return;
+   if (ed->var_pool->vars[id].type == EDJE_VAR_NONE)
+     ed->var_pool->vars[id].type = EDJE_VAR_LIST;
+   else if (ed->var_pool->vars[id].type != EDJE_VAR_LIST) return;
+     {
+       Eina_List *nth;
+
+       nth = eina_list_nth_list(ed->var_pool->vars[id].data.l.v, n);
+       if (nth)
+         {
+            _edje_var_free(eina_list_data_get(nth));
+            ed->var_pool->vars[id].data.l.v = eina_list_remove_list(ed->var_pool->vars[id].data.l.v, nth);
+         }
+     }
+}
+
+int
+_edje_var_list_nth_int_get(Edje *ed, int id, int n)
+{
+   if (!ed) return 0;
+   if (!ed->var_pool) return 0;
+   id -= EDJE_VAR_MAGIC_BASE;
+   if ((id < 0) || (id >= ed->var_pool->size)) return 0;
+   if (ed->var_pool->vars[id].type == EDJE_VAR_NONE)
+     ed->var_pool->vars[id].type = EDJE_VAR_LIST;
+   else if (ed->var_pool->vars[id].type != EDJE_VAR_LIST) return 0;
+     {
+       Edje_Var *var;
+
+       id += EDJE_VAR_MAGIC_BASE;
+       var = _edje_var_list_nth(ed, id, n);
+       if (!var) return 0;
+       return _edje_var_var_int_get(ed, var);
+     }
+}
+
+void
+_edje_var_list_nth_int_set(Edje *ed, int id, int n, int v)
+{
+   if (!ed) return;
+   if (!ed->var_pool) return;
+   id -= EDJE_VAR_MAGIC_BASE;
+   if ((id < 0) || (id >= ed->var_pool->size)) return;
+   if (ed->var_pool->vars[id].type == EDJE_VAR_NONE)
+     ed->var_pool->vars[id].type = EDJE_VAR_LIST;
+   else if (ed->var_pool->vars[id].type != EDJE_VAR_LIST) return;
+     {
+       Edje_Var *var;
+
+       id += EDJE_VAR_MAGIC_BASE;
+       var = _edje_var_list_nth(ed, id, n);
+       if (!var) return;
+       _edje_var_var_int_set(ed, var, v);
+     }
+}
+
+void
+_edje_var_list_int_append(Edje *ed, int id, int v)
+{
+   if (!ed) return;
+   if (!ed->var_pool) return;
+   id -= EDJE_VAR_MAGIC_BASE;
+   if ((id < 0) || (id >= ed->var_pool->size)) return;
+   if (ed->var_pool->vars[id].type == EDJE_VAR_NONE)
+     ed->var_pool->vars[id].type = EDJE_VAR_LIST;
+   else if (ed->var_pool->vars[id].type != EDJE_VAR_LIST) return;
+     {
+       Edje_Var *var;
+
+       var = _edje_var_new();
+       if (!var) return;
+       id += EDJE_VAR_MAGIC_BASE;
+       _edje_var_var_int_set(ed, var, v);
+       _edje_var_list_var_append(ed, id, var);
+     }
+}
+
+void
+_edje_var_list_int_prepend(Edje *ed, int id, int v)
+{
+   if (!ed) return;
+   if (!ed->var_pool) return;
+   id -= EDJE_VAR_MAGIC_BASE;
+   if ((id < 0) || (id >= ed->var_pool->size)) return;
+   if (ed->var_pool->vars[id].type == EDJE_VAR_NONE)
+     ed->var_pool->vars[id].type = EDJE_VAR_LIST;
+   else if (ed->var_pool->vars[id].type != EDJE_VAR_LIST) return;
+     {
+       Edje_Var *var;
+
+       var = _edje_var_new();
+       if (!var) return;
+       id += EDJE_VAR_MAGIC_BASE;
+       _edje_var_var_int_set(ed, var, v);
+       _edje_var_list_var_prepend(ed, id, var);
+     }
+}
+
+void
+_edje_var_list_int_insert(Edje *ed, int id, int n, int v)
+{
+   if (!ed) return;
+   if (!ed->var_pool) return;
+   id -= EDJE_VAR_MAGIC_BASE;
+   if ((id < 0) || (id >= ed->var_pool->size)) return;
+   if (ed->var_pool->vars[id].type == EDJE_VAR_NONE)
+     ed->var_pool->vars[id].type = EDJE_VAR_LIST;
+   else if (ed->var_pool->vars[id].type != EDJE_VAR_LIST) return;
+     {
+       Edje_Var *var, *var_rel;
+
+       var = _edje_var_new();
+       if (!var) return;
+       id += EDJE_VAR_MAGIC_BASE;
+       _edje_var_var_int_set(ed, var, v);
+       var_rel = _edje_var_list_nth(ed, id, n);
+       if (!var_rel)
+         _edje_var_list_var_append(ed, id, var);
+       else
+         _edje_var_list_var_prepend_relative(ed, id, var, var_rel);
+     }
+}
+
+double
+_edje_var_list_nth_float_get(Edje *ed, int id, int n)
+{
+   if (!ed) return 0;
+   if (!ed->var_pool) return 0;
+   id -= EDJE_VAR_MAGIC_BASE;
+   if ((id < 0) || (id >= ed->var_pool->size)) return 0;
+   if (ed->var_pool->vars[id].type == EDJE_VAR_NONE)
+     ed->var_pool->vars[id].type = EDJE_VAR_LIST;
+   else if (ed->var_pool->vars[id].type != EDJE_VAR_LIST) return 0;
+     {
+       Edje_Var *var;
+
+       id += EDJE_VAR_MAGIC_BASE;
+       var = _edje_var_list_nth(ed, id, n);
+       if (!var) return 0;
+       return _edje_var_var_float_get(ed, var);
+     }
+}
+
+void
+_edje_var_list_nth_float_set(Edje *ed, int id, int n, double v)
+{
+   if (!ed) return;
+   if (!ed->var_pool) return;
+   id -= EDJE_VAR_MAGIC_BASE;
+   if ((id < 0) || (id >= ed->var_pool->size)) return;
+   if (ed->var_pool->vars[id].type == EDJE_VAR_NONE)
+     ed->var_pool->vars[id].type = EDJE_VAR_LIST;
+   else if (ed->var_pool->vars[id].type != EDJE_VAR_LIST) return;
+     {
+       Edje_Var *var;
+
+       id += EDJE_VAR_MAGIC_BASE;
+       var = _edje_var_list_nth(ed, id, n);
+       if (!var) return;
+       _edje_var_var_float_set(ed, var, v);
+     }
+}
+
+void
+_edje_var_list_float_append(Edje *ed, int id, double v)
+{
+   if (!ed) return;
+   if (!ed->var_pool) return;
+   id -= EDJE_VAR_MAGIC_BASE;
+   if ((id < 0) || (id >= ed->var_pool->size)) return;
+   if (ed->var_pool->vars[id].type == EDJE_VAR_NONE)
+     ed->var_pool->vars[id].type = EDJE_VAR_LIST;
+   else if (ed->var_pool->vars[id].type != EDJE_VAR_LIST) return;
+     {
+       Edje_Var *var;
+
+       var = _edje_var_new();
+       if (!var) return;
+       id += EDJE_VAR_MAGIC_BASE;
+       _edje_var_var_float_set(ed, var, v);
+       _edje_var_list_var_append(ed, id, var);
+     }
+}
+
+void
+_edje_var_list_float_prepend(Edje *ed, int id, double v)
+{
+   if (!ed) return;
+   if (!ed->var_pool) return;
+   id -= EDJE_VAR_MAGIC_BASE;
+   if ((id < 0) || (id >= ed->var_pool->size)) return;
+   if (ed->var_pool->vars[id].type == EDJE_VAR_NONE)
+     ed->var_pool->vars[id].type = EDJE_VAR_LIST;
+   else if (ed->var_pool->vars[id].type != EDJE_VAR_LIST) return;
+     {
+       Edje_Var *var;
+
+       var = _edje_var_new();
+       if (!var) return;
+       id += EDJE_VAR_MAGIC_BASE;
+       _edje_var_var_float_set(ed, var, v);
+       _edje_var_list_var_prepend(ed, id, var);
+     }
+}
+
+void
+_edje_var_list_float_insert(Edje *ed, int id, int n, double v)
+{
+   if (!ed) return;
+   if (!ed->var_pool) return;
+   id -= EDJE_VAR_MAGIC_BASE;
+   if ((id < 0) || (id >= ed->var_pool->size)) return;
+   if (ed->var_pool->vars[id].type == EDJE_VAR_NONE)
+     ed->var_pool->vars[id].type = EDJE_VAR_LIST;
+   else if (ed->var_pool->vars[id].type != EDJE_VAR_LIST) return;
+     {
+       Edje_Var *var, *var_rel;
+
+       var = _edje_var_new();
+       if (!var) return;
+       id += EDJE_VAR_MAGIC_BASE;
+       _edje_var_var_float_set(ed, var, v);
+       var_rel = _edje_var_list_nth(ed, id, n);
+       if (!var_rel)
+         _edje_var_list_var_append(ed, id, var);
+       else
+         _edje_var_list_var_prepend_relative(ed, id, var, var_rel);
+     }
+}
+
+const char *
+_edje_var_list_nth_str_get(Edje *ed, int id, int n)
+{
+   if (!ed) return NULL;
+   if (!ed->var_pool) return NULL;
+   id -= EDJE_VAR_MAGIC_BASE;
+   if ((id < 0) || (id >= ed->var_pool->size)) return NULL;
+   if (ed->var_pool->vars[id].type == EDJE_VAR_NONE)
+     ed->var_pool->vars[id].type = EDJE_VAR_LIST;
+   else if (ed->var_pool->vars[id].type != EDJE_VAR_LIST) return NULL;
+     {
+       Edje_Var *var;
+
+       id += EDJE_VAR_MAGIC_BASE;
+       var = _edje_var_list_nth(ed, id, n);
+       if (!var) return NULL;
+       return _edje_var_var_str_get(ed, var);
+     }
+}
+
+void
+_edje_var_list_nth_str_set(Edje *ed, int id, int n, const char *v)
+{
+   if (!ed) return;
+   if (!ed->var_pool) return;
+   id -= EDJE_VAR_MAGIC_BASE;
+   if ((id < 0) || (id >= ed->var_pool->size)) return;
+   if (ed->var_pool->vars[id].type == EDJE_VAR_NONE)
+     ed->var_pool->vars[id].type = EDJE_VAR_LIST;
+   else if (ed->var_pool->vars[id].type != EDJE_VAR_LIST) return;
+     {
+       Edje_Var *var;
+
+       id += EDJE_VAR_MAGIC_BASE;
+       var = _edje_var_list_nth(ed, id, n);
+       if (!var) return;
+       _edje_var_var_str_set(ed, var, v);
+     }
+}
+
+void
+_edje_var_list_str_append(Edje *ed, int id, const char *v)
+{
+   if (!ed) return;
+   if (!ed->var_pool) return;
+   id -= EDJE_VAR_MAGIC_BASE;
+   if ((id < 0) || (id >= ed->var_pool->size)) return;
+   if (ed->var_pool->vars[id].type == EDJE_VAR_NONE)
+     ed->var_pool->vars[id].type = EDJE_VAR_LIST;
+   else if (ed->var_pool->vars[id].type != EDJE_VAR_LIST) return;
+     {
+       Edje_Var *var;
+
+       var = _edje_var_new();
+       if (!var) return;
+       id += EDJE_VAR_MAGIC_BASE;
+       _edje_var_var_str_set(ed, var, v);
+       _edje_var_list_var_append(ed, id, var);
+     }
+}
+
+void
+_edje_var_list_str_prepend(Edje *ed, int id, const char *v)
+{
+   if (!ed) return;
+   if (!ed->var_pool) return;
+   id -= EDJE_VAR_MAGIC_BASE;
+   if ((id < 0) || (id >= ed->var_pool->size)) return;
+   if (ed->var_pool->vars[id].type == EDJE_VAR_NONE)
+     ed->var_pool->vars[id].type = EDJE_VAR_LIST;
+   else if (ed->var_pool->vars[id].type != EDJE_VAR_LIST) return;
+     {
+       Edje_Var *var;
+
+       var = _edje_var_new();
+       if (!var) return;
+       id += EDJE_VAR_MAGIC_BASE;
+       _edje_var_var_str_set(ed, var, v);
+       _edje_var_list_var_prepend(ed, id, var);
+     }
+}
+
+void
+_edje_var_list_str_insert(Edje *ed, int id, int n, const char *v)
+{
+   if (!ed) return;
+   if (!ed->var_pool) return;
+   id -= EDJE_VAR_MAGIC_BASE;
+   if ((id < 0) || (id >= ed->var_pool->size)) return;
+   if (ed->var_pool->vars[id].type == EDJE_VAR_NONE)
+     ed->var_pool->vars[id].type = EDJE_VAR_LIST;
+   else if (ed->var_pool->vars[id].type != EDJE_VAR_LIST) return;
+     {
+       Edje_Var *var, *var_rel;
+
+       var = _edje_var_new();
+       if (!var) return;
+       id += EDJE_VAR_MAGIC_BASE;
+       _edje_var_var_str_set(ed, var, v);
+       var_rel = _edje_var_list_nth(ed, id, n);
+       if (!var_rel)
+         _edje_var_list_var_append(ed, id, var);
+       else
+         _edje_var_list_var_prepend_relative(ed, id, var, var_rel);
+     }
+}
+
+int
+_edje_var_timer_add(Edje *ed, double in, const char *fname, int val)
+{
+   Edje_Var_Timer *et;
+   Embryo_Function fn;
+
+   if (!ed->var_pool) return 0;
+   fn = embryo_program_function_find(ed->collection->script, (char *)fname);
+   if (fn == EMBRYO_FUNCTION_NONE) return 0;
+   et = calloc(1, sizeof(Edje_Var_Timer));
+   if (!et) return 0;
+   et->id = ++ed->var_pool->id_count;
+   et->edje = ed;
+   et->func = fn;
+   et->val = val;
+   et->timer = ecore_timer_add(in, _edje_var_timer_cb, et);
+   if (!et->timer)
+     {
+       free(et);
+       return 0;
+     }
+   ed->var_pool->timers = eina_list_prepend(ed->var_pool->timers, et);
+   return et->id;
+}
+
+static Edje_Var_Timer *
+_edje_var_timer_find(Edje *ed, int id)
+{
+   Eina_List *l;
+   Edje_Var_Timer *et;
+
+   if (!ed->var_pool) return NULL;
+
+   EINA_LIST_FOREACH(ed->var_pool->timers, l, et)
+     if (et->id == id) return et;
+
+   return NULL;
+}
+
+void
+_edje_var_timer_del(Edje *ed, int id)
+{
+   Edje_Var_Timer *et;
+
+   et = _edje_var_timer_find(ed, id);
+   if (!et) return;
+
+   ed->var_pool->timers = eina_list_remove(ed->var_pool->timers, et);
+   ecore_timer_del(et->timer);
+   free(et);
+}
+
+int
+_edje_var_anim_add(Edje *ed, double len, const char *fname, int val)
+{
+   Edje_Var_Animator *ea;
+   Embryo_Function fn;
+
+   if (!ed->var_pool) return 0;
+   if (len <= 0.0) return 0;
+   fn = embryo_program_function_find(ed->collection->script, (char *)fname);
+   if (fn == EMBRYO_FUNCTION_NONE) return 0;
+   ea = calloc(1, sizeof(Edje_Var_Animator));
+   if (!ea) return 0;
+   ea->start = ecore_loop_time_get();
+   ea->len = len;
+   ea->id = ++ed->var_pool->id_count;
+   ea->edje = ed;
+   ea->func = fn;
+   ea->val = val;
+   if (!ed->var_pool->animators)
+     _edje_anim_list = eina_list_append(_edje_anim_list, ed);
+   ed->var_pool->animators = eina_list_prepend(ed->var_pool->animators, ea);
+   if (!_edje_animator)
+     _edje_animator = ecore_animator_add(_edje_var_anim_cb, NULL);
+   return ea->id;
+}
+
+static Edje_Var_Animator *
+_edje_var_anim_find(Edje *ed, int id)
+{
+   Eina_List *l;
+   Edje_Var_Animator *ea;
+
+   if (!ed->var_pool) return NULL;
+
+   EINA_LIST_FOREACH(ed->var_pool->animators, l, ea)
+     if (ea->id == id) return ea;
+
+   return NULL;
+}
+
+void
+_edje_var_anim_del(Edje *ed, int id)
+{
+   Edje_Var_Animator *ea;
+
+   ea = _edje_var_anim_find(ed, id);
+   if (!ea) return;
+
+   if (ed->var_pool->walking_list)
+     {
+       ea->delete_me = 1;
+       return;
+     }
+
+   ed->var_pool->animators = eina_list_remove(ed->var_pool->animators, ea);
+   free(ea);
+
+   if (ed->var_pool->animators) return;
+
+   _edje_anim_list = eina_list_remove(_edje_anim_list, ed);
+   if (!_edje_anim_list)
+     {
+       if (_edje_animator)
+         {
+            ecore_animator_del(_edje_animator);
+            _edje_animator = NULL;
+         }
+     }
+}
diff --git a/utils/Makefile.am b/utils/Makefile.am
new file mode 100644 (file)
index 0000000..81cbad4
--- /dev/null
@@ -0,0 +1,7 @@
+MAINTAINERCLEANFILES = Makefile.in
+
+if HAVE_PYTHON
+bin_SCRIPTS = inkscape2edc
+endif
+
+EXTRA_DIST = gimp-edje-export.py inkscape2edc
diff --git a/utils/gimp-edje-export.py b/utils/gimp-edje-export.py
new file mode 100755 (executable)
index 0000000..88e1cb6
--- /dev/null
@@ -0,0 +1,146 @@
+#!/usr/bin/env python
+
+#   Gimp-Python - allows the writing of Gimp plugins in Python.
+#   Copyright (C) 2007  Renato Chencarek <renato.chencarek@openbossa.org>
+#
+#   This program is free software; you can redistribute it and/or modify
+#   it under the terms of the GNU General Public License as published by
+#   the Free Software Foundation; either version 2 of the License, or
+#   (at your option) any later version.
+#
+#   This program is distributed in the hope that it will be useful,
+#   but WITHOUT ANY WARRANTY; without even the implied warranty of
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#   GNU General Public License for more details.
+#
+#   You should have received a copy of the GNU General Public License
+#   along with this program; if not, write to the Free Software
+#   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# INSTALL:
+#
+#      cp gimp-edje-export.py ~/.gimp/plug-ins/
+#      chmod +x ~/.gimp/plug-ins/gimp-edje-export.py
+#
+#    Notes:
+#     - ~/.gimp may change depending on gimp version, ie: ~/.gimp-2.4.
+#     - Make sure this file is marked as executable!
+#
+# USAGE:
+#    Load an image and go to "Python-Fu > Edje Save" that will
+#    appear on the image's window.
+#
+
+from gimpfu import *
+import os.path
+import re, gettext
+
+
+def save_layer(layer, filename):
+    temp_image = pdb.gimp_image_new (layer.width, layer.height, layer.image.base_type)
+    temp_drawable = pdb.gimp_layer_new_from_drawable (layer, temp_image)
+    temp_image.add_layer (temp_drawable, -1)
+    pdb.gimp_file_save(temp_image, temp_drawable, filename, filename)
+    gimp.delete(temp_image)
+    return
+
+def write_image_section(layers, edje_file, filenames):
+    edje_file.write("images {\n")
+    for layer in layers:
+        edje_file.write('   image: "%s" COMP;\n' % filenames[layer.name])
+    edje_file.write("\n}\n")
+
+def write_layer_data(layer, edje_file, filename):
+    expr = re.compile('\W')
+    name = expr.sub("_", layer.name)
+    data = {'name':name, 'width':layer.width, 'height':layer.height,
+            'x0':layer.offsets[0], 'y0':layer.offsets[1],
+            'x1':layer.offsets[0] + layer.width, 'y1':layer.offsets[1] + layer.height,
+            'path':filename, 'visible':int(layer.visible)
+            }
+    text = """\
+         part {
+            name: "%(name)s";
+            type: IMAGE;
+            mouse_events: 0;
+            description {
+               state: "default" 0.0;
+               min: %(width)d %(height)d;
+               max: %(width)d %(height)d;
+               rel1 {
+                  relative: 0.0 0.0;
+                  offset: %(x0)d %(y0)d;
+               }
+               rel2 {
+                  relative: 0.0 0.0;
+                  offset: %(x1)d %(y1)d;
+               }
+               image {
+                  normal: "%(path)s";
+               }
+               visible: %(visible)d;
+            }
+         }\n""" % data
+    edje_file.write(text)
+
+def fix_layers_name(img, save_path):
+    filenames = {}
+    for layer in img.layers:
+        expr = re.compile('\W')
+        name = expr.sub("_", layer.name)
+        if not name:
+            name = "unnamed"
+        layer.name = name
+        if name in filenames.keys():
+            continue
+        filename = os.path.join(save_path, name + ".png")
+        filenames[name] = filename
+
+    return filenames
+
+def edje_save(img, drawable, save_path, save_layers, edje_filename, invisible):
+    layers = []
+    filenames = {}
+    for layer in img.layers:
+        if layer.visible or invisible:
+            expr = re.compile('\W')
+            name = expr.sub("_", layer.name)
+            layer.name = name
+            if name in filenames.keys():
+                continue
+            filename = os.path.join(save_path, name + ".png")
+            filenames[name] = filename
+            layers.append(layer)
+
+    edje_file = open(os.path.join(save_path, edje_filename), 'w')
+    write_image_section(layers, edje_file, filenames)
+
+    edje_file.write('collections {\n   group {\n      name: "%s";\n' % img.name)
+    edje_file.write('      min: %d %d;\n      max: %d %d;\n      parts {\n' % (img.width, img.height,img.width, img.height))
+    layers.reverse()
+    for l in layers:
+        if save_layers:
+            save_layer(l, filenames[l.name])
+        write_layer_data(l, edje_file,filenames[l.name])
+    edje_file.write('      }\n   }\n}\n')
+    edje_file.close()
+
+register(
+    "python_fu_edje_save",
+    "Export the Image as Edje file",
+    "Export the Image as Edje file",
+    "Renato Chencarek",
+    "Renato Chencarek",
+    "2007",
+    "<Image>/Python-Fu/_Edje Save",
+    "RGBA, GRAYA",
+    [
+        (PF_STRING, "save_path",  "Path",  "/tmp/"),
+        (PF_TOGGLE, "save_layers",  "Save Layers ?", True),
+        (PF_STRING, "edje_filename",  "Filename for edje",  "edje.edc"),
+        (PF_TOGGLE, "export_invisible_layers",  "Export invisible layers", False)
+    ],
+    [],
+    edje_save)
+
+main()
diff --git a/utils/inkscape2edc b/utils/inkscape2edc
new file mode 100755 (executable)
index 0000000..25a1a8c
--- /dev/null
@@ -0,0 +1,309 @@
+#!/usr/bin/env python
+
+import os
+import os.path
+import subprocess
+import logging as log
+import re
+
+
+class Inkscape2Edc(object):
+    cmd = "inkscape --without-gui"
+    def __init__(self, infile, outfile, group,
+                 relative1_x=None, relative2_x=None,
+                 relative1_y=None, relative2_y=None,
+                 images_dir="",
+                 show_max=True, show_min=True, show_mouse_events=True):
+        self.infile = infile
+        self.outfile = outfile
+        self.group = group
+        self.relative1_x = relative1_x
+        self.relative2_x = relative2_x
+        self.relative1_y = relative1_y
+        self.relative2_y = relative2_y
+        self.images_dir = images_dir
+        self.show_max = show_max
+        self.show_min = show_min
+        self.show_mouse_events = show_mouse_events
+
+        self.images = {}
+        self.sizes = {}
+        self.known_ids = tuple()
+        self.w = 0
+        self.h = 0
+
+        self.out = open(self.outfile, "wb")
+        self.basedir = os.path.dirname(self.outfile)
+
+    def _exec_cmd(self, *args):
+        s = " ".join(args)
+        cmd = "%s --file=%r %s" % (self.cmd, self.infile, s)
+        try:
+            p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
+                                 stderr=subprocess.PIPE, shell=True)
+        except Exception, e:
+            log.error("cmd=%r exception: %s", cmd, e)
+            return ""
+
+        out, err = p.communicate()
+        if err:
+            log.error("cmd=%r error: %s", cmd, err)
+
+        return out
+
+    def load_sizes(self):
+        sizes = self._exec_cmd("--query-all").split('\n')
+
+        self.sizes = {}
+        order = []
+        for line in sizes:
+            if not line:
+                continue
+            try:
+                oid, x, y, w, h = line.split(',')
+            except ValueError:
+                log.warn("could not parse size line: %r", line)
+                continue
+            x = float(x)
+            y = float(y)
+            w = float(w)
+            h = float(h)
+            self.sizes[oid] = (x, y, w, h)
+            order.append(oid)
+
+        self.known_ids = tuple(order)
+
+        self.w = float(self._exec_cmd("--query-width"))
+        self.h = float(self._exec_cmd("--query-height"))
+
+    def output_file_header(self):
+        self.out.write("""\
+collections {
+   group {
+      name: "%(group)s";
+""" % self.__dict__)
+
+        if self.show_min:
+            self.out.write("      min: %(w)d %(h)d;\n" % self.__dict__)
+
+        if self.show_max:
+            self.out.write("      max: %(w)d %(h)d;\n" % self.__dict__)
+
+    def output_file_section_parts_begin(self):
+        self.out.write("      parts {\n")
+
+    def output_file_section_parts_end(self):
+        self.out.write("      }\n")
+
+    def output_file_section_images_begin(self):
+        self.out.write("      images {\n")
+
+    def output_file_section_images_end(self):
+        self.out.write("      }\n")
+
+    def output_file_foot(self):
+        self.out.write("""\
+   }
+}
+""")
+
+    def output_image(self, oid):
+        img = os.path.join(self.images_dir, oid)
+        img += ".png"
+
+        self._exec_cmd("--export-id='%s'" % oid,
+                       "--export-id-only",
+                       "--export-png='%s'" % os.path.join(self.basedir, img))
+
+        self.out.write('         image: "%s" COMP;\n' % img)
+        self.images[oid] = img
+
+    def output_part_desc_rel(self, x, y, w, h):
+        def choose_rel(relative, value, value_max):
+            if relative is not None:
+                return relative
+            elif value <= abs(value_max - value):
+                return 0.0
+            else:
+                return 1.0
+
+        x2 = x + w - 1
+        y2 = y + h - 1
+
+        rx1 = choose_rel(self.relative1_x, x, w)
+        rx2 = choose_rel(self.relative2_x, x2, w)
+        ry1 = choose_rel(self.relative1_y, y, h)
+        ry2 = choose_rel(self.relative2_y, y2, h)
+
+        ox1 = x - self.w * rx1
+        ox2 = x2 - self.w * rx2
+
+        oy1 = y - self.h * ry1
+        oy2 = y2 - self.h * ry2
+
+        self.out.write("""\
+               rel1 {
+                  relative: %03.1f %03.1f;
+                  offset: %d %d;
+               }
+               rel2 {
+                  relative: %03.1f %03.1f;
+                  offset: %d %d;
+               }
+""" % (rx1, ry1, ox1, oy1, rx2, ry2, ox2, oy2))
+
+
+    def output_part(self, oid):
+        try:
+            x, y, w, h = self.sizes[oid]
+        except KeyError:
+            log.error("no such object id: %s", oid)
+            return
+
+        info = {
+            "name": oid,
+            "x": x,
+            "y": y,
+            "w": w,
+            "h": h,
+            }
+
+        self.out.write("""
+         part {
+            name: "%(name)s";
+            type: IMAGE;
+""" % info)
+
+        if self.show_mouse_events:
+            self.out.write("            mouse_events: 0;\n")
+
+        self.out.write("""\
+            description {
+               state: "default" 0.0;
+""")
+
+        if self.show_min:
+            self.out.write("               min: %(w)d %(h)d;\n" % info)
+
+        if self.show_max:
+            self.out.write("               max: %(w)d %(h)d;\n" % info)
+
+        self.output_part_desc_rel(x, y, w, h)
+        self.out.write("""\
+               image.normal: "%s";
+            }
+         }
+""" % (self.images[oid],))
+
+
+def foreach_id(inkscape2edc, ids=None, re_exclude=None):
+    if ids:
+        for oid in inkscape2edc.known_ids:
+            if oid in ids:
+                yield oid
+    else:
+        for oid in inkscape2edc.known_ids:
+            if re_exclude is not None and re_exclude.match(oid):
+                continue
+            yield oid
+
+
+if __name__ == "__main__":
+    import optparse
+
+    usage = "usage: %prog [options] <input.svg>"
+    parser = optparse.OptionParser(usage=usage)
+
+    parser.add_option("-i", "--id", action="append", default=[],
+                      help=("Object ID to use, it will be the part name. "
+                            "Multiple usage to use more object ids."))
+    parser.add_option("-e", "--exclude", action="store", default=None,
+                      help=("Exclude regular expression."
+                            "Matching IDs will be ignored."))
+    parser.add_option("-o", "--output", action="store", default=None,
+                      help="Output file to use")
+    parser.add_option("-g", "--group", action="store", default=None,
+                      help="Group name")
+    parser.add_option("-d", "--images-dir", action="store", default="",
+                      help="Directory where to output images.")
+    parser.add_option("--no-min", action="store_true",
+                      help="Do not output min values")
+    parser.add_option("--no-max", action="store_true",
+                      help="Do not output max values")
+    parser.add_option("--no-mouse_events", action="store_true",
+                      help="Do not output mouse_events lines")
+    parser.add_option("--relative1-y", action="store",
+                      choices=("top", "bottom", "auto"),
+                      default="auto",
+                      help=("Choose what to use as base for rel1 y values, "
+                            "top=0.0, bottom=1.0, auto=nearest"))
+    parser.add_option("--relative2-y", action="store",
+                      choices=("top", "bottom", "auto"),
+                      default="auto",
+                      help=("Choose what to use as base for rel2 y values, "
+                            "top=0.0, bottom=1.0, auto=nearest"))
+    parser.add_option("--relative1-x", action="store",
+                      choices=("left", "right", "auto"),
+                      default="auto",
+                      help=("Choose what to use as base for rel1 x values, "
+                            "left=0.0, right=1.0, auto=nearest"))
+    parser.add_option("--relative2-x", action="store",
+                      choices=("left", "right", "auto"),
+                      default="auto",
+                      help=("Choose what to use as base for rel2 x values, "
+                            "left=0.0, right=1.0, auto=nearest"))
+
+
+    options, args = parser.parse_args()
+
+    try:
+        infile = args[0]
+    except IndexError:
+        parser.print_help()
+        raise SystemExit("missing input file name")
+
+    fname = os.path.splitext(infile)[0]
+    if not options.output:
+        options.output = fname + ".edc"
+
+    if not options.group:
+        options.group = fname
+
+    rx_map = {"left": 0.0, "right": 1.0}
+    options.relative1_x = rx_map.get(options.relative1_x, None)
+    options.relative2_x = rx_map.get(options.relative2_x, None)
+
+    ry_map = {"top": 0.0, "bottom": 1.0}
+    options.relative1_y = ry_map.get(options.relative1_y, None)
+    options.relative2_y = ry_map.get(options.relative2_y, None)
+
+    o = Inkscape2Edc(infile, options.output, options.group,
+                     relative1_x=options.relative1_x,
+                     relative2_x=options.relative2_x,
+                     relative1_y=options.relative1_y,
+                     relative2_y=options.relative2_y,
+                     images_dir=options.images_dir,
+                     show_max=not options.no_max, show_min=not options.no_min,
+                     show_mouse_events=not options.no_mouse_events)
+
+    re_exclude = None
+    if options.exclude:
+        re_exclude = re.compile(options.exclude)
+
+    if options.images_dir:
+        os.makedirs(options.images_dir)
+
+    o.load_sizes()
+    o.output_file_header()
+
+    o.output_file_section_images_begin()
+    for oid in foreach_id(o, options.id, re_exclude):
+        o.output_image(oid)
+    o.output_file_section_images_end()
+
+    o.output_file_section_parts_begin()
+    for oid in foreach_id(o, options.id, re_exclude):
+        o.output_part(oid)
+    o.output_file_section_parts_end()
+
+    o.output_file_foot()