summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeandro Pereira <leandro@profusion.mobi>2013-02-14 20:43:18 +0000
committerTom Hacohen <tom@stosb.com>2013-06-17 10:03:58 +0100
commit8894714ba3d279a4555c35aba83dc8da3b3f2ca7 (patch)
tree5dd51fdfe031222794c67375c4ea9c5d8609c9a1
Add elev8 module for E17!HEADmaster
Now you can write modules for E17 in JavaScript! As a bonus points, it makes E17 even more unstable! Hooray! This is just a proof of concept. It should work, but there are lots of rough edges. See README for details on how to build and use it. Now go make awesome gadgets -- I'd recommend making the Connman example from EasyUI work as an E17 gadget. It should be a low hanging fruit (*wink* *wink* *nudge* *nudge*). SVN revision: 83922
-rw-r--r--AUTHORS1
-rw-r--r--COPYING32
-rw-r--r--COPYING-PLAIN33
-rw-r--r--ChangeLog0
-rw-r--r--INSTALL237
-rw-r--r--Makefile.am33
-rw-r--r--NEWS0
-rw-r--r--README30
-rwxr-xr-xautogen.sh17
-rw-r--r--configure.ac74
-rw-r--r--e-module-elev8.edc91
-rw-r--r--e_modules-elev8.spec.in48
-rw-r--r--images/module_icon.pngbin0 -> 19270 bytes
-rw-r--r--m4/ac_attribute.m447
-rw-r--r--module.desktop.in11
-rw-r--r--src/Makefile.am30
-rw-r--r--src/e_mod_main.c317
-rw-r--r--src/e_mod_main.h10
-rw-r--r--src/elev8.cc493
-rw-r--r--src/elev8.h24
-rw-r--r--src/environment.cc41
-rw-r--r--src/environment.h14
-rw-r--r--src/gadcon.cc357
-rw-r--r--src/gadcon.h14
-rw-r--r--src/storage.cc193
-rw-r--r--src/storage.h14
-rw-r--r--src/timer.cc136
-rw-r--r--src/timer.h13
-rw-r--r--src/utils.cc82
-rw-r--r--src/utils.h14
-rw-r--r--test-gadget.js45
31 files changed, 2451 insertions, 0 deletions
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..bc7a77e
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1 @@
Nobody Noone <null@null>
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..9690c3f
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,32 @@
1
2Permission is hereby granted, free of charge, to any person obtaining a copy
3of this software and associated documentation files (the "Software"), to
4deal in the Software without restriction, including without limitation the
5rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
6sell copies of the Software, and to permit persons to whom the Software is
7furnished to do so, subject to the following conditions:
8
9The above copyright notice and this permission notice shall be included in
10all copies of the Software and its Copyright notices. In addition publicly
11documented acknowledgment must be given that this software has been used if no
12source code of this software is made available publicly. Making the source
13available publicly means including the source for this software with the
14distribution, or a method to get this software via some reasonable mechanism
15(electronic transfer via a network or media) as well as making an offer to
16supply the source on request. This Copyright notice serves as an offer to
17supply the source on on request as well. Instead of this, supplying
18acknowledgments of use of this software in either Copyright notices, Manuals,
19Publicity and Marketing documents or any documentation provided with any
20product containing this software. This License does not apply to any software
21that links to the libraries provided by this software (statically or
22dynamically), but only to the software provided.
23
24Please see the COPYING-PLAIN for a plain-english explanation of this notice
25and its intent.
26
27THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
28IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
29FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
30THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
31IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
32CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/COPYING-PLAIN b/COPYING-PLAIN
new file mode 100644
index 0000000..922ef13
--- /dev/null
+++ b/COPYING-PLAIN
@@ -0,0 +1,33 @@
1Plain English Copyright Notice
2
3This file is not intended to be the actual License. The reason this file
4exists is that we here are programmers and engineers. We aren't lawyers. We
5provide licenses that we THINK say the right things, but we have our own
6intentions at heart. This is a plain-english explanation of what those
7intentions are, and if you follow them you will be within the "spirit" of
8the license.
9
10The intent is for us to enjoy writing software that is useful to us (the
11AUTHORS) and allow others to use it freely and also benefit from the work we
12put into making it. We don't want to restrict others using it. They should
13not *HAVE* to make the source code of the applications they write that
14simply link to these libraries (be that statically or dynamically), or for
15them to be limited as to what license they choose to use (be it open, closed
16or anything else). But we would like to know you are using these libraries.
17We simply would like to know that it has been useful to someone. This is why
18we ask for acknowledgement of some sort.
19
20You can do what you want with the source of this software - it doesn't
21matter. We still have it here for ourselves and it is open and free to use
22and download and play with. It can't be taken away. We don't really mind what
23you do with the source to your software. We would simply like to know that
24you are using it - especially if it makes it to a commerical product. If you
25simply e-mail all the AUTHORS (see COPYING and AUTHORS files) telling us, and
26then make sure you include a paragraph or page in the manual for the product
27with the copyright notice and state that you used this software, we will be
28very happy. If you want to contribute back modifications and fixes you may have
29made we will welcome those too with open arms (generally). If you want help
30with changes needed, ports needed or features to be added, arrangements can
31be easily made with some dialogue.
32
33Nobody Noone <null@null>
diff --git a/ChangeLog b/ChangeLog
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/ChangeLog
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 0000000..d3c5b40
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,237 @@
1Installation Instructions
2*************************
3
4Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005,
52006, 2007 Free Software Foundation, Inc.
6
7This file is free documentation; the Free Software Foundation gives
8unlimited permission to copy, distribute and modify it.
9
10Basic Installation
11==================
12
13Briefly, the shell commands `./configure; make; make install' should
14configure, build, and install this package. The following
15more-detailed instructions are generic; see the `README' file for
16instructions specific to this package.
17
18 The `configure' shell script attempts to guess correct values for
19various system-dependent variables used during compilation. It uses
20those values to create a `Makefile' in each directory of the package.
21It may also create one or more `.h' files containing system-dependent
22definitions. Finally, it creates a shell script `config.status' that
23you can run in the future to recreate the current configuration, and a
24file `config.log' containing compiler output (useful mainly for
25debugging `configure').
26
27 It can also use an optional file (typically called `config.cache'
28and enabled with `--cache-file=config.cache' or simply `-C') that saves
29the results of its tests to speed up reconfiguring. Caching is
30disabled by default to prevent problems with accidental use of stale
31cache files.
32
33 If you need to do unusual things to compile the package, please try
34to figure out how `configure' could check whether to do them, and mail
35diffs or instructions to the address given in the `README' so they can
36be considered for the next release. If you are using the cache, and at
37some point `config.cache' contains results you don't want to keep, you
38may remove or edit it.
39
40 The file `configure.ac' (or `configure.in') is used to create
41`configure' by a program called `autoconf'. You need `configure.ac' if
42you want to change it or regenerate `configure' using a newer version
43of `autoconf'.
44
45The simplest way to compile this package is:
46
47 1. `cd' to the directory containing the package's source code and type
48 `./configure' to configure the package for your system.
49
50 Running `configure' might take a while. While running, it prints
51 some messages telling which features it is checking for.
52
53 2. Type `make' to compile the package.
54
55 3. Optionally, type `make check' to run any self-tests that come with
56 the package.
57
58 4. Type `make install' to install the programs and any data files and
59 documentation.
60
61 5. You can remove the program binaries and object files from the
62 source code directory by typing `make clean'. To also remove the
63 files that `configure' created (so you can compile the package for
64 a different kind of computer), type `make distclean'. There is
65 also a `make maintainer-clean' target, but that is intended mainly
66 for the package's developers. If you use it, you may have to get
67 all sorts of other programs in order to regenerate files that came
68 with the distribution.
69
70 6. Often, you can also type `make uninstall' to remove the installed
71 files again.
72
73Compilers and Options
74=====================
75
76Some systems require unusual options for compilation or linking that the
77`configure' script does not know about. Run `./configure --help' for
78details on some of the pertinent environment variables.
79
80 You can give `configure' initial values for configuration parameters
81by setting variables in the command line or in the environment. Here
82is an example:
83
84 ./configure CC=c99 CFLAGS=-g LIBS=-lposix
85
86 *Note Defining Variables::, for more details.
87
88Compiling For Multiple Architectures
89====================================
90
91You can compile the package for more than one kind of computer at the
92same time, by placing the object files for each architecture in their
93own directory. To do this, you can use GNU `make'. `cd' to the
94directory where you want the object files and executables to go and run
95the `configure' script. `configure' automatically checks for the
96source code in the directory that `configure' is in and in `..'.
97
98 With a non-GNU `make', it is safer to compile the package for one
99architecture at a time in the source code directory. After you have
100installed the package for one architecture, use `make distclean' before
101reconfiguring for another architecture.
102
103Installation Names
104==================
105
106By default, `make install' installs the package's commands under
107`/usr/local/bin', include files under `/usr/local/include', etc. You
108can specify an installation prefix other than `/usr/local' by giving
109`configure' the option `--prefix=PREFIX'.
110
111 You can specify separate installation prefixes for
112architecture-specific files and architecture-independent files. If you
113pass the option `--exec-prefix=PREFIX' to `configure', the package uses
114PREFIX as the prefix for installing programs and libraries.
115Documentation and other data files still use the regular prefix.
116
117 In addition, if you use an unusual directory layout you can give
118options like `--bindir=DIR' to specify different values for particular
119kinds of files. Run `configure --help' for a list of the directories
120you can set and what kinds of files go in them.
121
122 If the package supports it, you can cause programs to be installed
123with an extra prefix or suffix on their names by giving `configure' the
124option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
125
126Optional Features
127=================
128
129Some packages pay attention to `--enable-FEATURE' options to
130`configure', where FEATURE indicates an optional part of the package.
131They may also pay attention to `--with-PACKAGE' options, where PACKAGE
132is something like `gnu-as' or `x' (for the X Window System). The
133`README' should mention any `--enable-' and `--with-' options that the
134package recognizes.
135
136 For packages that use the X Window System, `configure' can usually
137find the X include and library files automatically, but if it doesn't,
138you can use the `configure' options `--x-includes=DIR' and
139`--x-libraries=DIR' to specify their locations.
140
141Specifying the System Type
142==========================
143
144There may be some features `configure' cannot figure out automatically,
145but needs to determine by the type of machine the package will run on.
146Usually, assuming the package is built to be run on the _same_
147architectures, `configure' can figure that out, but if it prints a
148message saying it cannot guess the machine type, give it the
149`--build=TYPE' option. TYPE can either be a short name for the system
150type, such as `sun4', or a canonical name which has the form:
151
152 CPU-COMPANY-SYSTEM
153
154where SYSTEM can have one of these forms:
155
156 OS KERNEL-OS
157
158 See the file `config.sub' for the possible values of each field. If
159`config.sub' isn't included in this package, then this package doesn't
160need to know the machine type.
161
162 If you are _building_ compiler tools for cross-compiling, you should
163use the option `--target=TYPE' to select the type of system they will
164produce code for.
165
166 If you want to _use_ a cross compiler, that generates code for a
167platform different from the build platform, you should specify the
168"host" platform (i.e., that on which the generated programs will
169eventually be run) with `--host=TYPE'.
170
171Sharing Defaults
172================
173
174If you want to set default values for `configure' scripts to share, you
175can create a site shell script called `config.site' that gives default
176values for variables like `CC', `cache_file', and `prefix'.
177`configure' looks for `PREFIX/share/config.site' if it exists, then
178`PREFIX/etc/config.site' if it exists. Or, you can set the
179`CONFIG_SITE' environment variable to the location of the site script.
180A warning: not all `configure' scripts look for a site script.
181
182Defining Variables
183==================
184
185Variables not defined in a site shell script can be set in the
186environment passed to `configure'. However, some packages may run
187configure again during the build, and the customized values of these
188variables may be lost. In order to avoid this problem, you should set
189them in the `configure' command line, using `VAR=value'. For example:
190
191 ./configure CC=/usr/local2/bin/gcc
192
193causes the specified `gcc' to be used as the C compiler (unless it is
194overridden in the site shell script).
195
196Unfortunately, this technique does not work for `CONFIG_SHELL' due to
197an Autoconf bug. Until the bug is fixed you can use this workaround:
198
199 CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash
200
201`configure' Invocation
202======================
203
204`configure' recognizes the following options to control how it operates.
205
206`--help'
207`-h'
208 Print a summary of the options to `configure', and exit.
209
210`--version'
211`-V'
212 Print the version of Autoconf used to generate the `configure'
213 script, and exit.
214
215`--cache-file=FILE'
216 Enable the cache: use and save the results of the tests in FILE,
217 traditionally `config.cache'. FILE defaults to `/dev/null' to
218 disable caching.
219
220`--config-cache'
221`-C'
222 Alias for `--cache-file=config.cache'.
223
224`--quiet'
225`--silent'
226`-q'
227 Do not print messages saying which checks are being made. To
228 suppress all normal output, redirect it to `/dev/null' (any error
229 messages will still be shown).
230
231`--srcdir=DIR'
232 Look for the package's source code in directory DIR. Usually
233 `configure' can determine that directory automatically.
234
235`configure' also accepts some other, not widely useful, options. Run
236`configure --help' for more details.
237
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..f1699b3
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,33 @@
1ACLOCAL_AMFLAGS = -I m4
2MAINTAINERCLEANFILES = Makefile.in aclocal.m4 config.guess config.h.in \
3 config.sub configure depcomp install-sh ltmain.sh \
4 missing module.desktop config.rpath mkinstalldirs
5
6SUBDIRS = src
7
8# if HAVE_PO
9# SUBDIRS += po
10# endif
11
12EDJE_FLAGS = -v \
13 -id $(top_srcdir)/images
14
15filesdir = $(datadir)
16files_DATA = module.desktop e-module-elev8.edj
17
18EXTRA_DIST = module.desktop.in \
19 e_modules-elev8.spec.in \
20 e-module-elev8.edc \
21 images/module_icon.png
22
23e-module-elev8.edj: Makefile e-module-elev8.edc images/module_icon.png
24
25%.edj: %.edc
26 $(EDJE_CC) $(EDJE_FLAGS) $< $@
27
28clean-local:
29 rm -rf *.edj module.desktop e_modules-elev8.spec *~
30
31uninstall:
32 rm -rf $(DESTDIR)$(datadir)
33
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/NEWS
diff --git a/README b/README
new file mode 100644
index 0000000..c1928e2
--- /dev/null
+++ b/README
@@ -0,0 +1,30 @@
1Elev8 Module for E17
2--------------------
3
4This is a proof of concept module that will let you have E17 gadgets written
5in JavaScript, using the Elev8 API. It works to the extent that one can
6create gadgets using Elementary widgets and create menu entries, and use
7Elev8 modules, such as D-Bus and storage.
8
9
10BUILDING
11
12You'll need a recent version of Elev8 (specially its Elementary module).
13
14
15
16USING
17
18Set ELEV8_MODPATH to point to the path of your Elev8 module installation
19directory before launching Enlightenment.
20
21Copy test-gadget.js to /tmp.
22
23Load the Elev8 module in Settings->Modules. Accept that it is not a standard
24module and that it might be unstable.
25
26Loading the module will scan the /tmp directory (currently hardcoded!) for
27'*.js' files, and create a new gadget class for each gadget. When the module
28is loaded, one can just add them to the shelves or desktop directly, by
29choosing the file name as the module name (e.g. 'test-gadget.js').
30
diff --git a/autogen.sh b/autogen.sh
new file mode 100755
index 0000000..d824564
--- /dev/null
+++ b/autogen.sh
@@ -0,0 +1,17 @@
1#!/bin/sh
2
3rm -rf autom4te.cache
4rm -f aclocal.m4 ltmain.sh
5
6touch README
7
8#echo "Running autopoint..." ; autopoint -f || :
9echo "Running aclocal..." ; aclocal -I m4 $ACLOCAL_FLAGS || exit 1
10echo "Running autoheader..." ; autoheader || exit 1
11echo "Running autoconf..." ; autoconf || exit 1
12echo "Running libtoolize..." ; (libtoolize --copy --automake || glibtoolize --automake) || exit 1
13echo "Running automake..." ; automake --add-missing --copy --gnu || exit 1
14
15if [ -z "$NOCONFIGURE" ]; then
16 ./configure "$@"
17fi
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..62a07f4
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,74 @@
1dnl Process this file with autoconf to produce a configure script.
2
3# get rid of that stupid cache mechanism
4rm -f config.cache
5
6AC_INIT(elev8, 0.0.1, null@null)
7AC_PREREQ(2.52)
8AC_CONFIG_SRCDIR(configure.ac)
9AC_CANONICAL_BUILD
10AC_CANONICAL_HOST
11AC_ISC_POSIX
12
13AM_INIT_AUTOMAKE(1.8)
14AC_CONFIG_HEADERS(config.h)
15m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
16
17AC_PROG_CC
18AC_PROG_CXX
19AC_HEADER_STDC
20AC_C_CONST
21AC_C___ATTRIBUTE__
22
23define([AC_LIBTOOL_LANG_CXX_CONFIG], [:])dnl
24define([AC_LIBTOOL_LANG_F77_CONFIG], [:])dnl
25AC_PROG_LIBTOOL
26
27dnl m4_ifdef([AM_GNU_GETTEXT_VERSION], [
28dnl AM_GNU_GETTEXT_VERSION([0.14])
29dnl ])
30dnl
31dnl m4_ifdef([AM_GNU_GETTEXT], [
32dnl AM_GNU_GETTEXT([external])
33dnl po_makefile_in=po/Makefile.in
34dnl AM_CONDITIONAL([HAVE_PO], [true])
35dnl ],[
36dnl AM_CONDITIONAL([HAVE_PO], [false])
37dnl ])
38dnl AC_SUBST(LTLIBINTL)
39
40PKG_CHECK_MODULES(E, [enlightenment])
41release=$(pkg-config --variable=release enlightenment)
42MODULE_ARCH="$host_os-$host_cpu-$release"
43AC_SUBST(MODULE_ARCH)
44AC_DEFINE_UNQUOTED(MODULE_ARCH, "$MODULE_ARCH", "Module architecture")
45
46# Find edje_cc
47PKG_CHECK_MODULES(EDJE, [edje >= 0.5.0])
48AC_ARG_WITH(edje-cc,
49 AC_HELP_STRING([--with-edje-cc=PATH], [specify a specific path to edje_cc]),
50 [
51 v=$withval;
52 EDJE_CC=$v
53 ],[
54 EDJE_CC=$(pkg-config --variable=prefix edje)/bin/edje_cc
55 ]
56)
57AC_SUBST(EDJE_CC)
58AC_MSG_CHECKING([Which edje_cc to use])
59AC_MSG_RESULT(${EDJE_CC})
60
61datadir=$(pkg-config --variable=modules enlightenment)/${PACKAGE}
62AC_ARG_ENABLE(homedir-install,
63 AS_HELP_STRING([--enable-homedir-install], [Install module in homedir]),
64 [ datadir="${HOME}/.e/e/modules/${PACKAGE}" ]
65)
66
67AC_OUTPUT([
68Makefile
69src/Makefile
70module.desktop
71e_modules-elev8.spec
72$po_makefile_in
73], [
74])
diff --git a/e-module-elev8.edc b/e-module-elev8.edc
new file mode 100644
index 0000000..5f38717
--- /dev/null
+++ b/e-module-elev8.edc
@@ -0,0 +1,91 @@
1images
2{
3 image: "module_icon.png" COMP;
4}
5
6collections
7{
8 group
9 {
10 name: "icon";
11 max: 24 24;
12 parts
13 {
14 part
15 {
16 name: "image";
17 mouse_events: 0;
18 type: IMAGE;
19 description
20 {
21 state: "default" 0.0;
22 aspect: 1.0 1.0;
23 aspect_preference: BOTH;
24 image.normal: "module_icon.png";
25 }
26 }
27 }
28 }
29 group
30 {
31 name: "modules/elev8/main";
32 max: 128 128;
33 parts
34 {
35 part
36 {
37 name: "icon";
38 mouse_events: 0;
39 type: IMAGE;
40 description
41 {
42 state: "default" 0.0;
43 aspect: 1.0 1.0;
44 aspect_preference: BOTH;
45 rel1.offset: 2 2;
46 rel2.offset: -3 -3;
47 image.normal: "module_icon.png";
48 }
49 description
50 {
51 state: "bigger" 0.0;
52 inherit: "default" 0.0;
53 rel1.offset: -2 -2;
54 rel2.offset: 3 3;
55 }
56 }
57 part
58 {
59 name: "event";
60 mouse_events: 1;
61 type: RECT;
62 description
63 {
64 state: "default" 0.0;
65 color: 255 255 255 0;
66 }
67 }
68 }
69 programs
70 {
71 program
72 {
73 name: "mouse_in";
74 signal: "mouse,in";
75 source: "event";
76 action: STATE_SET "bigger" 0.0;
77 transition: LINEAR 0.1;
78 target: "icon";
79 }
80 program
81 {
82 name: "mouse_out";
83 signal: "mouse,out";
84 source: "event";
85 action: STATE_SET "default" 0.0;
86 transition: LINEAR 0.2;
87 target: "icon";
88 }
89 }
90 }
91}
diff --git a/e_modules-elev8.spec.in b/e_modules-elev8.spec.in
new file mode 100644
index 0000000..6a52cd1
--- /dev/null
+++ b/e_modules-elev8.spec.in
@@ -0,0 +1,48 @@
1%define module_name elev8
2%{!?_rel:%{expand:%%global _rel 0.enl%{?dist}}}
3
4Summary: %{module_name} module for the Enlightenment window manager
5Name: e_modules-%{module_name}
6Version: @VERSION@
7Release: %{_rel}
8License: BSD
9Group: User Interface/Desktops
10URL: http://www.enlightenment.org/
11Source: ftp://ftp.enlightenment.org/pub/enlightenment/%{module_name}-%{version}.tar.gz
12Packager: %{?_packager:%{_packager}}%{!?_packager:Michael Jennings <mej@eterm.org>}
13Vendor: %{?_vendorinfo:%{_vendorinfo}}%{!?_vendorinfo:The Enlightenment Project (http://www.enlightenment.org/)}
14Distribution: %{?_distribution:%{_distribution}}%{!?_distribution:%{_vendor}}
15BuildRequires: ecore-devel, evas-devel, edje-bin
16BuildRequires: edje-devel, eet-devel, enlightenment-devel >= 0.16.999
17Requires: enlightenment >= 0.16.999
18BuildRoot: %{_tmppath}/%{name}-%{version}-root
19
20%description
21%{module_name} module for the Enlightenment window manager.
22
23%prep
24%setup -q -n %{module_name}-%{version}
25
26%build
27%{configure}
28%{__make} %{?_smp_mflags} %{?mflags}
29
30%install
31%{__make} %{?mflags_install} DESTDIR=$RPM_BUILD_ROOT install
32%{find_lang} %{module_name} || true > %{module_name}.lang
33
34%clean
35test "x$RPM_BUILD_ROOT" != "x/" && rm -rf $RPM_BUILD_ROOT
36
37%post
38/sbin/ldconfig
39
40%postun
41/sbin/ldconfig
42
43%files -f %{module_name}.lang
44%defattr(-, root, root)
45%doc AUTHORS ChangeLog COPYING* INSTALL NEWS README
46%{_libdir}/enlightenment/modules/%{module_name}*
47
48%changelog
diff --git a/images/module_icon.png b/images/module_icon.png
new file mode 100644
index 0000000..42cd67b
--- /dev/null
+++ b/images/module_icon.png
Binary files differ
diff --git a/m4/ac_attribute.m4 b/m4/ac_attribute.m4
new file mode 100644
index 0000000..23479a9
--- /dev/null
+++ b/m4/ac_attribute.m4
@@ -0,0 +1,47 @@
1dnl Copyright (C) 2004-2008 Kim Woelders
2dnl Copyright (C) 2008 Vincent Torri <vtorri at univ-evry dot fr>
3dnl That code is public domain and can be freely used or copied.
4dnl Originally snatched from somewhere...
5
6dnl Macro for checking if the compiler supports __attribute__
7
8dnl Usage: AC_C___ATTRIBUTE__
9dnl call AC_DEFINE for HAVE___ATTRIBUTE__ and __UNUSED__
10dnl if the compiler supports __attribute__, HAVE___ATTRIBUTE__ is
11dnl defined to 1 and __UNUSED__ is defined to __attribute__((unused))
12dnl otherwise, HAVE___ATTRIBUTE__ is not defined and __UNUSED__ is
13dnl defined to nothing.
14
15AC_DEFUN([AC_C___ATTRIBUTE__],
16[
17
18AC_MSG_CHECKING([for __attribute__])
19
20AC_CACHE_VAL([ac_cv___attribute__],
21 [AC_TRY_COMPILE(
22 [
23#include <stdlib.h>
24
25int func(int x);
26int foo(int x __attribute__ ((unused)))
27{
28 exit(1);
29}
30 ],
31 [],
32 [ac_cv___attribute__="yes"],
33 [ac_cv___attribute__="no"]
34 )])
35
36AC_MSG_RESULT($ac_cv___attribute__)
37
38if test "x${ac_cv___attribute__}" = "xyes" ; then
39 AC_DEFINE([HAVE___ATTRIBUTE__], [1], [Define to 1 if your compiler has __attribute__])
40 AC_DEFINE([__UNUSED__], [__attribute__((unused))], [Macro declaring a function argument to be unused])
41 else
42 AC_DEFINE([__UNUSED__], [], [Macro declaring a function argument to be unused])
43fi
44
45])
46
47dnl End of ac_attribute.m4
diff --git a/module.desktop.in b/module.desktop.in
new file mode 100644
index 0000000..7cbffa1
--- /dev/null
+++ b/module.desktop.in
@@ -0,0 +1,11 @@
1[Desktop Entry]
2Type=Link
3Name=Elev8
4Name[ru]=Скелет
5Name[de]=Elev8ett
6Name[eo]=Elev8eto
7Name[el]=Elev8
8Icon=e-module-elev8
9Comment=Third floor. Mattresses. Pillows. Towels.
10#Several different types available here. NEED TO DOC THESE.
11X-Enlightenment-ModuleType=utils
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..a22af79
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,30 @@
1MAINTAINERCLEANFILES = Makefile.in
2
3AM_CPPFLAGS = -I. \
4 -I$(top_srcdir) \
5 -I$(includedir) \
6 @E_CFLAGS@
7
8pkgdir = $(datadir)/$(MODULE_ARCH)
9pkg_LTLIBRARIES = module.la
10module_la_SOURCES = e_mod_main.h \
11 e_mod_main.c \
12 elev8.cc \
13 elev8.h \
14 timer.cc \
15 timer.h \
16 storage.cc \
17 storage.h \
18 environment.cc \
19 environment.h \
20 utils.cc \
21 utils.h \
22 gadcon.cc \
23 gadcon.h
24
25module_la_LIBADD = @E_LIBS@ -ldl -lv8 -lstdc++
26module_la_LDFLAGS = -module -avoid-version
27module_la_DEPENDENCIES = $(top_builddir)/config.h
28
29clean-local:
30 rm -rf *~
diff --git a/src/e_mod_main.c b/src/e_mod_main.c
new file mode 100644
index 0000000..7c908c4
--- /dev/null
+++ b/src/e_mod_main.c
@@ -0,0 +1,317 @@
1#include "e.h"
2#include "e_mod_main.h"
3#include "elev8.h"
4
5typedef struct _Gadget Gadget;
6
7/*
8 * The problem with this structure is that it maps the script name to
9 * this structure. This means you can't have various instances of the
10 * same gadget running at the same time (so, for example, various
11 * instances of a Weather gadget would display the same location).
12 *
13 * We need a way to fix this, by providing an Elev8_Context for each
14 * instance.
15 *
16 * As a proof of concept, though, this works fairly well.
17 */
18struct _Gadget {
19 E_Gadcon_Client_Class *klass;
20 Elev8_Context *ctx;
21 int clients;
22};
23
24/* gadcon requirements */
25static E_Gadcon_Client *_gc_init(E_Gadcon *gc, const char *name, const char *id, const char *style);
26static void _gc_shutdown(E_Gadcon_Client *gcc);
27static void _gc_orient(E_Gadcon_Client *gcc, E_Gadcon_Orient orient);
28static const char *_gc_label(const E_Gadcon_Client_Class *client_class);
29static Evas_Object *_gc_icon(const E_Gadcon_Client_Class *client_class, Evas *evas);
30static const char *_gc_id_new(const E_Gadcon_Client_Class *client_class);
31
32static e17_elev8_log_domain = -1;
33
34static Eina_Hash *name_to_g = NULL;
35
36static Gadget *
37gadget_name_lookup(const char *name)
38{
39 if (!name) return NULL;
40 return eina_hash_find(name_to_g, name);
41}
42
43static void
44gadget_destroy(Gadget *g)
45{
46 if (!g) return;
47
48 g->clients--;
49 if (g->clients) return;
50
51 e_gadcon_provider_unregister(g->klass);
52 free((char *)g->klass->name);
53 free(g->klass);
54 elev8_context_del(g->ctx);
55 free(g);
56}
57
58static Eina_Bool
59gadget_setup(const char *file, const char *name)
60{
61 Gadget *g;
62
63 name = strdup(name);
64 if (!name) return EINA_FALSE;
65
66 g = calloc(1, sizeof(*g));
67 if (!g) goto out_nog;
68
69 g->ctx = elev8_context_add();
70 if (!g->ctx) goto out_noctx;
71
72 elev8_context_enter(g->ctx);
73 gadcon_client_bridge_register(name);
74 elev8_context_leave(g->ctx);
75
76 if (!elev8_context_script_exec(g->ctx, file)) goto out_noklass;
77
78 g->klass = calloc(1, sizeof(*g->klass));
79 if (!g->klass) goto out_noklass;
80 if (!eina_hash_add(name_to_g, name, g)) goto out;
81
82 memcpy(g->klass, (E_Gadcon_Client_Class[]) {{
83 .version = GADCON_CLIENT_CLASS_VERSION,
84 .name = name,
85 .func = {
86 .init = _gc_init,
87 .shutdown = _gc_shutdown,
88 .orient = _gc_orient,
89 .label = _gc_label,
90 .icon = _gc_icon,
91 .id_new = _gc_id_new,
92 .id_del = NULL,
93 .is_site = NULL
94 },
95 .default_style = E_GADCON_CLIENT_STYLE_PLAIN
96 }}, sizeof(E_Gadcon_Client_Class));
97
98 g->clients = 0;
99 e_gadcon_provider_register(g->klass);
100
101 return EINA_TRUE;
102
103out:
104 free(g->klass);
105out_noklass:
106 elev8_context_del(g->ctx);
107out_noctx:
108 free(g);
109out_nog:
110 free((char *)name);
111
112 return EINA_FALSE;
113}
114
115static void
116handle_mouse_down(void *data, Evas *e, Evas_Object *eo, void *event_info)
117{
118 Evas_Event_Mouse_Down *ev = (Evas_Event_Mouse_Down *)event_info;
119 E_Gadcon_Client *gcc = (E_Gadcon_Client *)data;
120 Gadget *g = gadget_name_lookup(gcc->name);
121 void *menu, *zone;
122 int x, y;
123
124 if (!g) return;
125
126 elev8_context_enter(g->ctx);
127
128 menu = gadcon_client_bridge_menu_build(gcc->name);
129 if (!menu) goto end;
130
131 menu = e_gadcon_client_util_menu_items_append(gcc, menu, 0);
132
133 e_gadcon_canvas_zone_geometry_get(gcc->gadcon, &x, &y, NULL, NULL);
134
135 zone = e_util_zone_current_get(e_manager_current_get());
136 e_menu_activate_mouse(menu, zone, x + ev->output.x, y + ev->output.y, 1, 1,
137 E_MENU_POP_DIRECTION_AUTO, ev->timestamp);
138
139 evas_event_feed_mouse_up(e, ev->button, EVAS_BUTTON_NONE,
140 ev->timestamp, NULL);
141
142end:
143 elev8_context_leave(g->ctx);
144}
145
146static void
147install_menu_handler(Evas_Object *base, void *gcc)
148{
149 evas_object_event_callback_add(base, EVAS_CALLBACK_MOUSE_DOWN,
150 handle_mouse_down, gcc);
151}
152
153static void
154base_object_move(void *data, Evas *e, Evas_Object *obj, void *event_info)
155{
156 E_Gadcon_Client *gcc = data;
157 Gadget *g = gadget_name_lookup(gcc->name);
158 int x, y;
159
160 if (!g) return;
161
162 elev8_context_enter(g->ctx);
163 evas_object_geometry_get(obj, &x, &y, NULL, NULL);
164 gadcon_client_bridge_gadget_move(gcc->name, x, y);
165 elev8_context_leave(g->ctx);
166}
167
168static void
169base_object_resize(void *data, Evas *e, Evas_Object *obj, void *event_info)
170{
171 E_Gadcon_Client *gcc = data;
172 Gadget *g = gadget_name_lookup(gcc->name);
173 int w, h;
174
175 if (!g) return;
176
177 elev8_context_enter(g->ctx);
178 evas_object_geometry_get(obj, NULL, NULL, &w, &h);
179 gadcon_client_bridge_gadget_resize(gcc->name, w, h);
180 elev8_context_leave(g->ctx);
181}
182
183static E_Gadcon_Client *
184_gc_init(E_Gadcon *gc, const char *name, const char *id, const char *style)
185{
186 Evas_Object *o;
187 E_Gadcon_Client *gcc;
188 Gadget *g = gadget_name_lookup(name);
189
190 if (!g) return NULL;
191
192 o = evas_object_rectangle_add(gc->evas);
193 if (!o) return NULL;
194
195 evas_object_color_set(o, 255, 255, 255, 0);
196 evas_object_show(o);
197
198 elev8_context_enter(g->ctx);
199 if (!gadcon_bridge_init(o, name, id, style))
200 {
201 elev8_context_leave(g->ctx);
202 evas_object_del(o);
203 return NULL;
204 }
205
206 gcc = e_gadcon_client_new(gc, name, id, style, o);
207 e_gadcon_client_min_size_set(gcc, 64, 64);
208 install_menu_handler(o, gcc);
209
210 evas_object_event_callback_add(o, EVAS_CALLBACK_MOVE, base_object_move, gcc);
211 evas_object_event_callback_add(o, EVAS_CALLBACK_RESIZE, base_object_resize, gcc);
212
213 g->clients++;
214
215 elev8_context_leave(g->ctx);
216
217 return gcc;
218}
219
220static void
221_gc_shutdown(E_Gadcon_Client *gcc)
222{
223 Gadget *g = gadget_name_lookup(gcc->name);
224 if (!g) return;
225
226 elev8_context_enter(g->ctx);
227 evas_object_del(gcc->o_base);
228 gadcon_client_bridge_shutdown(gcc->name);
229 elev8_context_leave(g->ctx);
230}
231
232static void
233_gc_orient(E_Gadcon_Client *gcc, E_Gadcon_Orient orient)
234{
235 Gadget *g = gadget_name_lookup(gcc->name);
236 if (!g) return;
237
238 elev8_context_enter(g->ctx);
239 gadcon_client_bridge_orient(gcc->name, orient);
240 elev8_context_leave(g->ctx);
241}
242
243static const char *
244_gc_label(const E_Gadcon_Client_Class *klass)
245{
246 return klass->name;
247}
248
249static Evas_Object *
250_gc_icon(const E_Gadcon_Client_Class *client_class __UNUSED__, Evas *evas)
251{
252 return NULL;
253}
254
255static const char *
256_gc_id_new(const E_Gadcon_Client_Class *klass)
257{
258 static char buf[4096];
259 static int instances = 0;
260
261 snprintf(buf, sizeof(buf) - 1, "%s:%d", klass->name, instances++);
262 return buf;
263}
264
265/* module setup */
266EAPI E_Module_Api e_modapi =
267{
268 E_MODULE_API_VERSION,
269 "Elev8 Module"
270};
271
272static void
273gadget_dir_list_setup(const char *name, const char *path, void *data)
274{
275 char full_path[PATH_MAX];
276
277 if (!eina_str_has_suffix(name, ".js")) return;
278 if (snprintf(full_path, sizeof(full_path) - 1, "%s/%s", path, name) < 0) return;
279
280 if (!gadget_setup(full_path, name))
281 {
282 printf("***** ERROR SETTING UP GADGET %s\n", full_path);
283 }
284}
285
286EAPI void *
287e_modapi_init(E_Module *m)
288{
289 e17_elev8_log_domain = eina_log_domain_register("e17_elev8", EINA_COLOR_RED);
290 elev8_init();
291
292 name_to_g = eina_hash_string_superfast_new((Eina_Free_Cb)gadget_destroy);
293
294 if (!eina_file_dir_list("/tmp", EINA_FALSE, gadget_dir_list_setup, NULL))
295 {
296 elev8_shutdown();
297 return NULL;
298 }
299
300 return m;
301}
302
303EAPI int
304e_modapi_shutdown(E_Module *m __UNUSED__)
305{
306 eina_hash_free(name_to_g);
307
308 elev8_shutdown();
309 eina_log_domain_unregister(e17_elev8_log_domain);
310 return 1;
311}
312
313EAPI int
314e_modapi_save(E_Module *m __UNUSED__)
315{
316 return 1;
317}
diff --git a/src/e_mod_main.h b/src/e_mod_main.h
new file mode 100644
index 0000000..4adf2f1
--- /dev/null
+++ b/src/e_mod_main.h
@@ -0,0 +1,10 @@
1#ifndef E_MOD_MAIN_H
2#define E_MOD_MAIN_H
3
4EAPI extern E_Module_Api e_modapi;
5
6EAPI void *e_modapi_init (E_Module *m);
7EAPI int e_modapi_shutdown (E_Module *m);
8EAPI int e_modapi_save (E_Module *m);
9
10#endif
diff --git a/src/elev8.cc b/src/elev8.cc
new file mode 100644
index 0000000..cc26dfa
--- /dev/null
+++ b/src/elev8.cc
@@ -0,0 +1,493 @@
1#include <dlfcn.h>
2#include <Ecore_Con.h>
3#include <Ecore.h>
4#include <Eina.h>
5#include <fcntl.h>
6#include <sys/mman.h>
7#include <sys/stat.h>
8#include <sys/types.h>
9#include <unistd.h>
10#include <v8.h>
11
12#include "elev8.h"
13#include "timer.h"
14#include "storage.h"
15#include "environment.h"
16#include "utils.h"
17#include "gadcon.h"
18
19#define MODLOAD_ENV "ELEV8_MODPATH"
20#define MODLOAD_ENV_DEFAULT_DIRS ".:"
21
22#define CRIT(...) do { fputs("CRIT: ", stderr); fprintf(stderr, __VA_ARGS__); fputc('\n', stderr); } while(0)
23
24using namespace v8;
25
26enum ContextUseRule{
27 CREATE_NEW_CONTEXT,
28 USE_CURRENT_CONTEXT
29};
30
31struct _Elev8_Context {
32 Persistent<Value> v8_self;
33 Persistent<ObjectTemplate> global;
34 Persistent<Context> context;
35 Persistent<Object> module_cache;
36};
37
38static int log_domain;
39static Ecore_Event_Handler *siguser_handler;
40
41static Handle<Value>
42_string_to_object(Handle<String> str)
43{
44 HandleScope scope;
45
46 Handle<Value> json = Context::GetCurrent()->Global()->Get(String::NewSymbol("JSON"));
47 if (json.IsEmpty())
48 return Null();
49
50 Handle<Value> stringify = json->ToObject()->Get(String::NewSymbol("parse"));
51 if (stringify.IsEmpty())
52 return Null();
53
54 Handle<Function> func = Handle<Function>::Cast(stringify);
55 Handle<Value> args[1] = { str };
56
57 return scope.Close(func->Call(Context::GetCurrent()->Global(), 1, args)->ToObject());
58}
59
60static int
61_shebang_length(const char *p, int len)
62{
63 if ((len >= 2) && (p[0] == '#') && (p[1] == '!'))
64 return (const char *)memchr(&p[2], '\n', len) - p;
65 return 0;
66}
67
68Handle<String>
69_load_script_from_file(const char *filename)
70{
71 HandleScope scope;
72 Handle<String> ret;
73 int fd, len = 0;
74 char *p;
75 int n;
76
77 fd = open(filename, O_RDONLY);
78 if (fd < 0) goto fail_open;
79
80 len = lseek(fd, 0, SEEK_END);
81 if (len <= 0) goto fail;
82
83 p = reinterpret_cast<char*>(mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd, 0));
84 if (p == reinterpret_cast<char *>(MAP_FAILED)) goto fail;
85
86 n = _shebang_length(p, len);
87 ret = String::New(&p[n], len - n);
88
89 munmap(p, len);
90
91fail:
92 close(fd);
93
94fail_open:
95 return scope.Close(ret);
96}
97
98static char *
99_find_module_file_name(char *module_name, const char *prefix, const char *type)
100{
101 char *modpath = getenv(MODLOAD_ENV);
102 char default_modpath[] = MODLOAD_ENV_DEFAULT_DIRS;
103
104 if (!modpath) modpath = default_modpath;
105
106 for (char *token, *rest, *ptr = modpath;
107 (token = strtok_r(ptr, ":", &rest));
108 ptr = rest)
109 {
110 char full_path[PATH_MAX];
111
112 if (snprintf(full_path, PATH_MAX - 1, "%s/%s%s.%s", token, prefix, module_name, type) < 0)
113 return NULL;
114
115 if (!access(full_path, R_OK))
116 return strdup(full_path);
117 }
118
119 return NULL;
120}
121
122inline static char *
123_find_native_module_file_name(char *module_name)
124{
125 return _find_module_file_name(module_name, "lib", "so");
126}
127
128inline static char *
129_find_js_module_file_name(char *module_name)
130{
131 char *tmp;
132 char *path = _find_module_file_name(module_name, "", "js");
133
134 if (path)
135 return path;
136
137 if (asprintf(&tmp, "%s/", module_name) < 0)
138 goto end;
139
140 path = _find_module_file_name((char *)"package", tmp, "json");
141 free(tmp);
142
143 if (path)
144 {
145 HandleScope scope;
146 Handle<String> package_json = _load_script_from_file(path);
147 Handle<Value> package_obj = _string_to_object(package_json);
148
149 if (!package_obj->IsObject())
150 goto end;
151
152 Handle<Value> main_module = package_obj->ToObject()->Get(String::NewSymbol("main"));
153 if (!main_module->IsString())
154 goto end;
155
156 if (asprintf(&tmp, "%s/%s", dirname(path),
157 *String::Utf8Value(main_module->ToString())) > 0)
158 {
159 free(path);
160 return !access(tmp, R_OK) ? tmp : NULL;
161 }
162 }
163
164end:
165 free(path);
166 return NULL;
167}
168
169static bool
170_module_native_load(Elev8_Context *, char *module_name, Handle<Object> name_space, ContextUseRule)
171{
172 char *file_name = _find_native_module_file_name(module_name);
173
174 if (!file_name) return false;
175
176 // FIXME: Use Eina_Module here.
177 void *handle = dlopen(file_name, RTLD_LAZY);
178 if (!handle)
179 {
180 CRIT("Could not dlopen(%s): %s", file_name, dlerror());
181 free(file_name);
182 return false;
183 }
184
185 void (*init_func)(Handle<Object> name_space);
186 init_func = (void (*)(Handle<Object>))dlsym(handle, "RegisterModule");
187 if (!init_func)
188 {
189 CRIT("Could not dlsym(%p, RegisterModule): %s", handle, dlerror());
190 free(file_name);
191 dlclose(handle);
192 return false;
193 }
194
195 init_func(name_space);
196 free(file_name);
197 return true;
198}
199
200static bool
201_module_js_load(Elev8_Context *ctx, char *module_name, Handle<Object> name_space, ContextUseRule context_use_rule)
202{
203 char *file_name = _find_js_module_file_name(module_name);
204 bool return_value = false;
205
206 if (!file_name) return false;
207
208 Handle<String> mod_source = _load_script_from_file(file_name);
209 if (mod_source.IsEmpty())
210 {
211 free(file_name);
212 return false;
213 }
214
215 HandleScope handle_scope;
216
217 Persistent<Context> mod_context;
218 if (context_use_rule == CREATE_NEW_CONTEXT)
219 {
220 ctx->global->Set(String::NewSymbol("exports"), name_space);
221 mod_context = Context::New(NULL, ctx->global);
222 mod_context->Enter();
223
224 //run_script(PACKAGE_LIB_DIR "/../init.js");
225 }
226
227 TryCatch try_catch;
228 Local<Script> mod_script = Script::Compile(mod_source->ToString(), String::New(file_name));
229 if (try_catch.HasCaught())
230 {
231// boom(try_catch);
232 goto end;
233 }
234
235 mod_script->Run();
236 if (try_catch.HasCaught())
237 {
238// boom(try_catch);
239 goto end;
240 }
241
242 return_value = true;
243end:
244 free(file_name);
245
246 if (context_use_rule == CREATE_NEW_CONTEXT)
247 mod_context->Exit();
248
249 return return_value;
250}
251
252static bool
253_load_module_with_type_hints(Elev8_Context *ctx, Handle<String> module_name, Local<Object> name_space, ContextUseRule context_use_rule)
254{
255 String::Utf8Value module_name_utf(module_name);
256
257 if (module_name->Length() <= 3) goto end;
258
259 if (eina_str_has_suffix(*module_name_utf, ".js"))
260 {
261 *(*module_name_utf + module_name->Length() - 3) = '\0';
262 return _module_js_load(ctx, *module_name_utf, name_space, context_use_rule);
263 }
264
265 if (eina_str_has_suffix(*module_name_utf, ".so"))
266 {
267 *(*module_name_utf + module_name->Length() - 3) = '\0';
268 return _module_native_load(ctx, *module_name_utf, name_space, context_use_rule);
269 }
270
271end:
272 return _module_native_load(ctx, *module_name_utf, name_space, context_use_rule)
273 || _module_js_load(ctx, *module_name_utf, name_space, context_use_rule);
274}
275
276static Handle<Value>
277_load_module(Elev8_Context *ctx, Handle<String> module_name, ContextUseRule context_use_rule)
278{
279 HandleScope scope;
280
281 if (ctx->module_cache->HasOwnProperty(module_name))
282 return scope.Close(ctx->module_cache->Get(module_name));
283
284 Local<Object> name_space = (context_use_rule == CREATE_NEW_CONTEXT) ?
285 Object::New() : ctx->context->Global();
286
287 if (_load_module_with_type_hints(ctx, module_name, name_space, context_use_rule))
288 {
289 ctx->module_cache->Set(module_name, Persistent<Object>::New(name_space));
290 return scope.Close(name_space);
291 }
292
293 Local<String> msg = String::Concat(String::New("Cannot load module: "), module_name);
294 return scope.Close(ThrowException(Exception::Error(msg)));
295}
296
297static inline Handle<Value>
298_internal_require(Elev8_Context *ctx, const Arguments& args, ContextUseRule cur)
299{
300 HandleScope scope;
301 if (args.Length() < 1)
302 return scope.Close(ThrowException(Exception::Error(String::New("Module name missing"))));
303 return scope.Close(_load_module(ctx, args[0]->ToString(), cur));
304}
305
306static void
307_message_handler(Handle<Message> message, Handle<Value>)
308{
309 CRIT(*String::Utf8Value(message->Get()));
310}
311
312static Eina_Bool
313_flush_garbage_collector(void *, int, void *)
314{
315 V8::LowMemoryNotification();
316 return ECORE_CALLBACK_CANCEL;
317}
318
319static Handle<Value>
320_require(const Arguments& args)
321{
322 Elev8_Context *ctx = (Elev8_Context *)External::Cast(*args.Data())->Value();
323 return _internal_require(ctx, args, CREATE_NEW_CONTEXT);
324}
325
326static Handle<Value>
327___require__(const Arguments& args)
328{
329 Elev8_Context *ctx = (Elev8_Context *)External::Cast(*args.Data())->Value();
330 return _internal_require(ctx, args, USE_CURRENT_CONTEXT);
331}
332
333static Handle<Value>
334_modules(const Arguments& args)
335{
336 Elev8_Context *ctx = (Elev8_Context *)External::Cast(*args.Data())->Value();
337 return ctx->module_cache;
338}
339
340static Handle<Value>
341_print(const Arguments& args)
342{
343 HandleScope scope;
344 int argument_count = args.Length();
345
346 if (!argument_count) goto end;
347
348 for (int i = 0; i < argument_count; i++)
349 {
350 fputs(*String::Utf8Value(args[i]), stdout);
351
352 if (i < argument_count - 1)
353 putchar(' ');
354 }
355
356end:
357 putchar('\n');
358 fflush(stdout);
359
360 return Undefined();
361}
362
363static void
364_register_basic_functions(Elev8_Context *ctx)
365{
366#define REGISTER_FUNC(name) \
367 Context::GetCurrent()->Global()->Set(String::NewSymbol(#name), FunctionTemplate::New(_ ## name, ctx->v8_self)->GetFunction());
368
369 REGISTER_FUNC(require);
370 REGISTER_FUNC(__require__);
371 REGISTER_FUNC(modules);
372 REGISTER_FUNC(print);
373
374#undef REGISTER_FUNC
375}
376
377static void
378_load_internal_modules(Elev8_Context *ctx)
379{
380 timer::RegisterModule(ctx->global);
381 storage::RegisterModule(ctx->global);
382 environment::RegisterModule(ctx->global);
383 utils::RegisterModule(ctx->global);
384 gadcon::RegisterModule(ctx->global);
385}
386
387void
388elev8_init()
389{
390 eina_init();
391 ecore_con_init();
392
393 log_domain = eina_log_domain_register("elev8", EINA_COLOR_ORANGE);
394 if (!log_domain)
395 {
396 fprintf(stderr, "Could not register elev8 log domain, using global\n");
397 log_domain = EINA_LOG_DOMAIN_GLOBAL;
398 }
399
400 V8::AddMessageListener(_message_handler);
401 V8::SetCaptureStackTraceForUncaughtExceptions(true, 10, StackTrace::kDetailed);
402
403 siguser_handler = ecore_event_handler_add(ECORE_EVENT_SIGNAL_USER, _flush_garbage_collector, NULL);
404}
405
406void
407elev8_shutdown()
408{
409 ecore_event_handler_del(siguser_handler);
410 ecore_con_shutdown();
411 eina_shutdown();
412}
413
414Elev8_Context *
415elev8_context_add()
416{
417 HandleScope scope;
418 Elev8_Context *ctx = (Elev8_Context *)calloc(1, sizeof(*ctx));
419
420 if (!ctx) return NULL;
421
422 ctx->global = Persistent<ObjectTemplate>::New(ObjectTemplate::New());
423
424 ctx->context = Context::New(NULL, ctx->global);
425 ctx->context->Enter();
426
427 ctx->module_cache = Persistent<Object>::New(Object::New());
428 ctx->v8_self = Persistent<Value>::New(External::New(ctx));
429
430 _register_basic_functions(ctx);
431 _load_internal_modules(ctx);
432
433 ctx->context->Exit();
434
435 return ctx;
436}
437
438void
439elev8_context_del(Elev8_Context *ctx)
440{
441 if (!ctx) return;
442
443 ctx->v8_self.Dispose();
444 ctx->context.Dispose();
445 ctx->module_cache.Dispose();
446 ctx->global.Dispose();
447 free(ctx);
448}
449
450void
451elev8_context_leave(Elev8_Context *ctx)
452{
453 ctx->context->Exit();
454}
455
456void
457elev8_context_enter(Elev8_Context *ctx)
458{
459 ctx->context->Enter();
460}
461
462Eina_Bool
463elev8_context_script_exec(Elev8_Context *ctx, const char *path)
464{
465 Context::Scope s(ctx->context);
466 HandleScope scope;
467 TryCatch try_catch;
468
469 Handle<String> source = _load_script_from_file(path);
470 if (source.IsEmpty())
471 {
472 CRIT("Could not open script \"%s\"", path);
473 return EINA_FALSE;
474 }
475
476 Local<Script> script = Script::New(source, String::New(path));
477 if (try_catch.HasCaught())
478 {
479 CRIT("Could not compile script \"%s\": %s\n",
480 path, *String::Utf8Value(try_catch.Exception()));
481 return EINA_FALSE;
482 }
483
484 script->Run();
485 if (try_catch.HasCaught())
486 {
487 CRIT("Could not run script \"%s\": %s\n",
488 path, *String::Utf8Value(try_catch.Exception()));
489 return EINA_FALSE;
490 }
491
492 return EINA_TRUE;
493}
diff --git a/src/elev8.h b/src/elev8.h
new file mode 100644
index 0000000..2525586
--- /dev/null
+++ b/src/elev8.h
@@ -0,0 +1,24 @@
1#ifndef __ELEV8_H__
2#define __ELEV8_H__
3
4#ifdef __cplusplus
5extern "C" {
6#endif
7
8typedef struct _Elev8_Context Elev8_Context;
9
10void elev8_init();
11void elev8_shutdown();
12
13Elev8_Context *elev8_context_add();
14void elev8_context_del(Elev8_Context *ctx);
15void elev8_context_enter(Elev8_Context *ctx);
16void elev8_context_leave(Elev8_Context *ctx);
17
18Eina_Bool elev8_context_script_exec(Elev8_Context *ctx, const char *path);
19
20#ifdef __cplusplus
21}
22#endif
23
24#endif /* __ELEV8_H__ */ \ No newline at end of file
diff --git a/src/environment.cc b/src/environment.cc
new file mode 100644
index 0000000..5b8b9ae
--- /dev/null
+++ b/src/environment.cc
@@ -0,0 +1,41 @@
1#include <v8.h>
2#include <stdlib.h>
3#include "environment.h"
4
5using namespace v8;
6
7namespace environment {
8
9static Handle<Value> EnvironGet(Local<String> name, const AccessorInfo &)
10{
11 char *env_var = getenv(*String::Utf8Value(name));
12
13 if (env_var)
14 return String::New(env_var);
15
16 return Undefined();
17}
18
19static Handle<Value> EnvironSet(Local<String> name, Local<Value> value, const AccessorInfo &)
20{
21 if (value->IsUndefined())
22 {
23 unsetenv(*String::Utf8Value(name));
24 return Undefined();
25 }
26
27 if (setenv(*String::Utf8Value(name), *String::Utf8Value(value), 1) < 0)
28 return Undefined();
29
30 return value;
31}
32
33void RegisterModule(Handle<ObjectTemplate> global)
34{
35 Handle<ObjectTemplate> environ = ObjectTemplate::New();
36 environ->SetNamedPropertyHandler(EnvironGet, EnvironSet);
37
38 global->Set("environment", environ);
39}
40
41}
diff --git a/src/environment.h b/src/environment.h
new file mode 100644
index 0000000..0a0f76a
--- /dev/null
+++ b/src/environment.h
@@ -0,0 +1,14 @@
1#ifndef __ENVIRONMENT_H__
2#define __ENVIRONMENT_H__
3
4#include <v8.h>
5
6using namespace v8;
7
8namespace environment {
9
10void RegisterModule(Handle<ObjectTemplate>);
11
12}
13#endif
14
diff --git a/src/gadcon.cc b/src/gadcon.cc
new file mode 100644
index 0000000..449c5bc
--- /dev/null
+++ b/src/gadcon.cc
@@ -0,0 +1,357 @@
1#include <Eina.h>
2#include <Evas.h>
3#include <v8.h>
4#include <stdlib.h>
5#include "gadcon.h"
6
7using namespace v8;
8
9extern "C" {
10/*
11 * E17 headers fails to compile with a C++ compiler, so provide some
12 * prototypes here and use void* types.
13 */
14
15void *e_menu_new(void);
16void *e_menu_item_new(void *);
17void *e_menu_item_nth(void *, int);
18void e_menu_item_label_set(void *, const char *);
19void e_menu_item_icon_file_set(void *, const char *);
20void e_menu_item_submenu_set(void *, void *);
21void e_menu_item_separator_set(void *, int);
22void e_menu_item_check_set(void *, int);
23void e_menu_item_toggle_set(void *, int);
24void e_menu_item_radio_set(void *, int);
25void e_menu_item_radio_group_set(void *, int);
26void e_gadcon_client_menu_set(void *, void *);
27void e_util_menu_item_theme_icon_set(void *, const char *);
28int e_object_unref(void *);
29void *e_object_delfn_add(void *, void (*)(void *, void *), void *);
30void *e_object_data_get(void *);
31void e_object_data_set(void *, void *);
32void e_menu_item_callback_set(void *, void (void *, void *, void *), void *);
33void *e_menu_root_get(void *);
34}
35
36namespace gadcon {
37
38struct Gadcon {
39 Persistent<Object> gadcon;
40
41 static void Register(const char *name) {
42 HandleScope scope;
43 Gadcon *g = (Gadcon *)calloc(1, sizeof(*g));
44
45 g->gadcon = Persistent<Object>::New(Object::New());
46 Context::GetEntered()->Global()->Set(String::NewSymbol("GadCon"), g->gadcon);
47
48 eina_hash_add(Gadcon::all_gadcons, name, g);
49 }
50
51 static Handle<Object> Lookup(const char *name) {
52 Gadcon *g = (Gadcon *)eina_hash_find(Gadcon::all_gadcons, name);
53 return g ? g->gadcon : Handle<Object>();
54 }
55
56 static void Initialize() {
57 if (Gadcon::all_gadcons) return;
58 Gadcon::all_gadcons = eina_hash_string_small_new(Gadcon::Destroy);
59 }
60
61private:
62 static Eina_Hash *all_gadcons;
63
64 static void Destroy(void *data) {
65 Gadcon *g = (Gadcon *)data;
66 g->gadcon.Dispose();
67 free(g);
68 }
69};
70
71Eina_Hash *Gadcon::all_gadcons = NULL;
72
73extern "C" Eina_Bool
74gadcon_bridge_init(Evas_Object *base, const char *name, const char *id, const char *style)
75{
76 HandleScope scope;
77 Handle<Object> gadcon = Gadcon::Lookup(name);
78
79 if (gadcon.IsEmpty())
80 {
81 fprintf(stderr, "no gadget by this name: \"%s\"\n", name);
82 return EINA_FALSE;
83 }
84 if (!gadcon->Has(String::NewSymbol("init")))
85 {
86 fprintf(stderr, "module src has no init fn\n");
87 return EINA_FALSE;
88 }
89 Handle<Value> init_function = gadcon->Get(String::NewSymbol("init"));
90 if (!init_function->IsFunction())
91 {
92 fprintf(stderr, "that's no moon\n");
93 return EINA_FALSE;
94 }
95
96 if (!Context::GetCurrent()->Global()->Has(String::NewSymbol("elm")))
97 {
98 fprintf(stderr, "elm module not loaded!\n");
99 return EINA_FALSE;
100 }
101
102 Handle<Value> elm_module = Context::GetCurrent()->Global()->Get(String::NewSymbol("elm"));
103 if (elm_module.IsEmpty())
104 {
105 fprintf(stderr, "could not find elm module for some reason!\n");
106 return EINA_FALSE;
107 }
108 Handle<Value> new_gadget_function = elm_module->ToObject()->Get(String::NewSymbol("NewGadgetFromEvasObject"));
109 if (new_gadget_function.IsEmpty())
110 {
111 fprintf(stderr, "elm module not supported!\n");
112 return EINA_FALSE;
113 }
114
115 Local<Function> le_gambiarret(Function::Cast(*new_gadget_function));
116 Handle<Value> le_gambiarret_args[1] = { External::New(base) };
117 Handle<Value> gadget = le_gambiarret->Call(Context::GetCurrent()->Global(), 1, le_gambiarret_args);
118
119 Local<Function> callback(Function::Cast(*init_function));
120 Handle<Value> args[4] = {
121 gadget,
122 String::New(name),
123 String::New(id),
124 String::New(style)
125 };
126
127 callback->Call(Context::GetCurrent()->Global(), 4, args);
128
129 gadcon->Set(String::Concat(String::New(name), String::NewSymbol("::gadget")), gadget);
130
131 return EINA_TRUE;
132}
133
134extern "C" void
135gadcon_client_bridge_gadget_move(const char *name, int x, int y)
136{
137 HandleScope scope;
138 Handle<Object> gadcon = Gadcon::Lookup(name);
139
140 if (gadcon.IsEmpty()) return;
141 Local<Value> gadget = gadcon->Get(String::Concat(String::New(name), String::NewSymbol("::gadget")));
142
143 if (gadget.IsEmpty()) return;
144 if (!gadget->IsObject()) return;
145
146 gadget->ToObject()->Set(String::NewSymbol("x"), Integer::New(x));
147 gadget->ToObject()->Set(String::NewSymbol("y"), Integer::New(y));
148}
149
150extern "C" void
151gadcon_client_bridge_gadget_resize(const char *name, int w, int h)
152{
153 HandleScope scope;
154 Handle<Object> gadcon = Gadcon::Lookup(name);
155
156 if (gadcon.IsEmpty()) return;
157
158 Local<Value> gadget = gadcon->Get(String::Concat(String::New(name), String::NewSymbol("::gadget")));
159
160 if (gadget.IsEmpty()) return;
161 if (!gadget->IsObject()) return;
162
163 gadget->ToObject()->Set(String::NewSymbol("width"), Integer::New(w));
164 gadget->ToObject()->Set(String::NewSymbol("height"), Integer::New(h));
165}
166
167extern "C" void
168gadcon_client_bridge_shutdown(const char *name)
169{
170 HandleScope scope;
171 Handle<Object> gadcon = Gadcon::Lookup(name);
172
173 if (gadcon.IsEmpty()) return;
174 if (!gadcon->Has(String::NewSymbol("shutdown"))) return;
175
176 Handle<Value> shutdown_function = gadcon->Get(String::NewSymbol("shutdown"));
177 if (!shutdown_function->IsFunction()) return;
178
179 Local<Function> callback(Function::Cast(*shutdown_function));
180 Handle<Value> args[0] = { };
181
182 callback->Call(Context::GetCurrent()->Global(), 0, args);
183}
184
185extern "C" void
186gadcon_client_bridge_orient(const char *name, int orient)
187{
188 HandleScope scope;
189 Handle<Object> gadcon = Gadcon::Lookup(name);
190
191 if (gadcon.IsEmpty()) return;
192 if (!gadcon->Has(String::NewSymbol("orient"))) return;
193
194 Handle<Value> orient_function = gadcon->Get(String::NewSymbol("orient"));
195 if (!orient_function->IsFunction()) return;
196
197 Local<Function> callback(Function::Cast(*orient_function));
198 Handle<Value> args[1] = { Integer::New(orient) };
199
200 callback->Call(Context::GetCurrent()->Global(), 1, args);
201}
202
203struct MenuItemCallback {
204 Persistent<Object> item;
205
206 MenuItemCallback(Handle<Object> item_)
207 : item(Persistent<Object>::New(item_)) {}
208
209 ~MenuItemCallback() {
210 item.Dispose();
211 }
212
213 static void Invoke(void *data, void *menu, void *menu_item) {
214 HandleScope scope;
215 MenuItemCallback *self = (MenuItemCallback *)data;
216
217 Handle<Value> callback_function = self->item->Get(String::NewSymbol("callback"));
218 if (!callback_function->IsFunction()) return;
219
220 Local<Function> callback(Function::Cast(*callback_function));
221 Handle<Value> args[0] = { };
222
223 callback->Call(self->item, 0, args);
224 }
225};
226
227static void
228destroy_menu_items(void *menu)
229{
230 for (unsigned i = 0; ; i++)
231 {
232 void *mi = e_menu_item_nth(menu, i);
233 if (!mi) return;
234 delete static_cast<MenuItemCallback *>(e_object_data_get(mi));
235 }
236}
237
238static void
239destroy_menu(void *data, void *menu)
240{
241 Eina_List *submenus = (Eina_List *)data;
242 void *submenu;
243
244 EINA_LIST_FREE(submenus, submenu)
245 {
246 destroy_menu_items(submenu);
247 e_object_unref(submenu);
248 }
249
250 destroy_menu_items(menu);
251}
252
253static void
254build_menu_recursively(Local<Array> items, void *menu, Eina_List **submenus)
255{
256 HandleScope scope;
257
258 if (!menu) return;
259
260 for (unsigned i = 0; i < items->Length(); i++)
261 {
262 Local<Object> item = items->Get(i)->ToObject();
263 void *mi = e_menu_item_new(menu);
264
265 if (!item->Has(String::NewSymbol("label")))
266 {
267 e_menu_item_separator_set(mi, 1);
268 continue;
269 }
270
271 e_menu_item_label_set(mi,
272 *String::Utf8Value(item->Get(String::NewSymbol("label"))));
273
274 if (item->Has(String::NewSymbol("icon_theme")))
275 e_util_menu_item_theme_icon_set(mi,
276 *String::Utf8Value(item->Get(String::NewSymbol("icon_theme"))));
277
278 if (item->Has(String::NewSymbol("icon_file")))
279 e_menu_item_icon_file_set(mi,
280 *String::Utf8Value(item->Get(String::NewSymbol("icon_file"))));
281
282 if (item->Has(String::NewSymbol("items")))
283 {
284 Local<Array> subitems = Array::Cast(*item->Get(String::NewSymbol("items")));
285 void *submenu = e_menu_new();
286
287 *submenus = eina_list_append(*submenus, submenu);
288
289 build_menu_recursively(subitems, submenu, submenus);
290 e_menu_item_submenu_set(mi, submenu);
291 }
292
293 if (item->Has(String::NewSymbol("callback")))
294 {
295 e_object_data_set(mi, new MenuItemCallback(item));
296 e_menu_item_callback_set(mi, MenuItemCallback::Invoke, e_object_data_get(mi));
297 }
298
299 if (item->Has(String::NewSymbol("check")))
300 e_menu_item_check_set(mi, item->Get(String::NewSymbol("check"))->Int32Value());
301
302 if (item->Has(String::NewSymbol("radio")))
303 e_menu_item_radio_set(mi, item->Get(String::NewSymbol("radio"))->Int32Value());
304
305 if (item->Has(String::NewSymbol("radio_group")))
306 e_menu_item_radio_group_set(mi, item->Get(String::NewSymbol("radio_group"))->Int32Value());
307
308 if (item->Has(String::NewSymbol("toggle")))
309 e_menu_item_toggle_set(mi, item->Get(String::NewSymbol("toggle"))->Int32Value());
310 }
311}
312
313extern "C" void *
314gadcon_client_bridge_menu_build(const char *name)
315{
316 HandleScope scope;
317 Handle<Object> gadcon = Gadcon::Lookup(name);
318
319 if (gadcon.IsEmpty()) return NULL;
320 if (!gadcon->Has(String::NewSymbol("menu"))) return NULL;
321
322 Handle<Value> menu_function = gadcon->Get(String::NewSymbol("menu"));
323 if (!menu_function->IsFunction()) return NULL;
324
325 Local<Function> callback(Function::Cast(*menu_function));
326 Handle<Value> args[0] = { };
327 Local<Value> items_as_value = callback->Call(Context::GetCurrent()->Global(), 0, args);
328 if (items_as_value.IsEmpty()) return NULL;
329 if (!items_as_value->IsArray()) return NULL;
330
331 Local<Array> items = Array::Cast(*items_as_value);
332
333 void *menu = e_menu_new();
334 if (!menu) return NULL;
335
336 Eina_List *submenus = NULL;
337 build_menu_recursively(items, menu, &submenus);
338
339 e_object_data_set(menu, submenus);
340 e_object_delfn_add(menu, destroy_menu, submenus);
341
342 return menu;
343}
344
345extern "C" void
346gadcon_client_bridge_register(const char *name)
347{
348 Gadcon::Register(name);
349}
350
351void
352RegisterModule(Handle<ObjectTemplate>)
353{
354 Gadcon::Initialize();
355}
356
357}
diff --git a/src/gadcon.h b/src/gadcon.h
new file mode 100644
index 0000000..a1d2dbd
--- /dev/null
+++ b/src/gadcon.h
@@ -0,0 +1,14 @@
1#ifndef __GADCON_H__
2#define __GADCON_H__
3
4#include <v8.h>
5
6using namespace v8;
7
8namespace gadcon {
9
10void RegisterModule(Handle<ObjectTemplate>);
11
12}
13#endif
14
diff --git a/src/storage.cc b/src/storage.cc
new file mode 100644
index 0000000..0805129
--- /dev/null
+++ b/src/storage.cc
@@ -0,0 +1,193 @@
1#include <v8.h>
2#include <Eet.h>
3#include <Ecore.h>
4#include "storage.h"
5
6using namespace v8;
7
8namespace storage {
9
10int log;
11
12#define STORAGE_DBG(...) EINA_LOG_DOM_DBG(log, __VA_ARGS__)
13#define STORAGE_INF(...) EINA_LOG_DOM_INFO(log, __VA_ARGS__)
14#define STORAGE_WRN(...) EINA_LOG_DOM_WARN(log, __VA_ARGS__)
15#define STORAGE_ERR(...) EINA_LOG_DOM_ERR(log, __VA_ARGS__)
16#define STORAGE_CRT(...) EINA_LOG_DOM_CRIT(log, __VA_ARGS__)
17
18static Eet_File *ef = NULL;
19static Persistent<String> databaseFile;
20static const char* const defaultDatabaseFile = "/tmp/elev8.eet";
21
22static void ensureEetIsOpen()
23{
24 if (ef) return;
25
26 STORAGE_INF("Opening database: %s\n", *String::Utf8Value(databaseFile));
27 ef = eet_open(*String::Utf8Value(databaseFile), EET_FILE_MODE_READ_WRITE);
28 if (ef) return;
29
30 if (!strncmp(*String::Utf8Value(databaseFile), defaultDatabaseFile, sizeof(defaultDatabaseFile) - 1))
31 {
32 STORAGE_CRT("Could not open default database file at %s", defaultDatabaseFile);
33 return;
34 }
35
36 HandleScope scope;
37
38 STORAGE_ERR("Could not open database at %s, trying default path", *String::Utf8Value(databaseFile));
39 databaseFile.Dispose();
40 databaseFile = Persistent<String>::New(String::New(defaultDatabaseFile));
41 ensureEetIsOpen();
42}
43
44static void closeEetOnExit()
45{
46 if (ef)
47 {
48 STORAGE_INF("Closing database: %s\n", *String::Utf8Value(databaseFile));
49 eet_close(ef);
50 }
51}
52
53static Handle<Value> clear(const Arguments&)
54{
55 HandleScope scope;
56 char **items;
57 int size;
58
59 ensureEetIsOpen();
60
61 items = eet_list(ef, "*", &size);
62 for (int i = 0; i < size; i++) eet_delete(ef, items[i]);
63 free(items);
64 return Undefined();
65}
66
67static Handle<Value> remove(const Arguments& args)
68{
69 HandleScope scope;
70
71 ensureEetIsOpen();
72
73 eet_delete(ef, *String::Utf8Value(args[0]));
74 return Undefined();
75}
76
77static Handle<Value> setItem(Local<Value> property, Local<Value> value)
78{
79 HandleScope scope;
80
81 ensureEetIsOpen();
82
83 eet_write(ef, *String::Utf8Value(property), *String::Utf8Value(value),
84 value->ToString()->Utf8Length(), 1);
85 return Undefined();
86}
87
88static Handle<Value> setItem(const Arguments& args)
89{
90 return setItem(args[0], args[1]);
91}
92
93static Handle<Value> getItem(Local<Value> property)
94{
95 HandleScope scope;
96 Handle<String> result;
97 char *ret;
98 int size;
99
100 ensureEetIsOpen();
101
102 ret = (char *)eet_read(ef, *String::Utf8Value(property), &size);
103 if (!ret) return Null();
104
105 result = String::New(ret, size);
106 free(ret);
107
108 return scope.Close(result);
109
110}
111
112static Handle<Value> getItem(const Arguments& args)
113{
114 return getItem(args[0]);
115}
116
117static Handle<Value> key(const Arguments& args)
118{
119 HandleScope scope;
120 int index = args[0]->Uint32Value();
121
122 ensureEetIsOpen();
123
124 if (index > eet_num_entries(ef)) return Null();
125
126 char **items;
127 int size;
128 items = eet_list(ef, "*", &size);
129 Handle<String> result = String::New(items[index]);
130 free(items);
131 return scope.Close(result);
132}
133
134static Handle<Value> length(Local<String>, const AccessorInfo&)
135{
136 HandleScope scope;
137 return scope.Close(Integer::New(eet_num_entries(ef)));
138}
139
140static Handle<Value> databaseGet(Local<String>, const AccessorInfo&)
141{
142 HandleScope scope;
143 return scope.Close(databaseFile);
144}
145
146static void databaseSet(Local<String>, Local<Value> value, const AccessorInfo&)
147{
148 if (!value->IsString()) return;
149
150 HandleScope scope;
151
152 databaseFile.Dispose();
153 eet_close(ef);
154 ef = NULL;
155
156 databaseFile = Persistent<String>::New(value->ToString());
157}
158
159void RegisterModule(Handle<ObjectTemplate> global)
160{
161 log = eina_log_domain_register("elev8-store", EINA_COLOR_ORANGE);
162 if (!log)
163 {
164 STORAGE_ERR("could not register elev8-store log domain.");
165 log = EINA_LOG_DOMAIN_GLOBAL;
166 }
167
168 STORAGE_INF("elev8-store Logging initialized. %d", log);
169
170 eet_init();
171 ecore_init();
172
173 atexit(closeEetOnExit);
174
175 databaseFile = Persistent<String>::New(String::New(defaultDatabaseFile));
176
177 Handle<FunctionTemplate> tmpl = FunctionTemplate::New();
178 tmpl->SetClassName(String::New("Storage"));
179
180 Handle<ObjectTemplate> inst_t = tmpl->InstanceTemplate();
181
182 inst_t->Set("setItem", FunctionTemplate::New(setItem));
183 inst_t->Set("getItem", FunctionTemplate::New(getItem));
184 inst_t->Set("clear", FunctionTemplate::New(clear));
185 inst_t->Set("removeItem", FunctionTemplate::New(remove));
186 inst_t->Set("key", FunctionTemplate::New(key));
187 inst_t->SetAccessor(String::NewSymbol("length"), length, NULL);
188 inst_t->SetAccessor(String::NewSymbol("database"), databaseGet, databaseSet);
189
190 global->Set("LocalStorage", tmpl);
191}
192
193}
diff --git a/src/storage.h b/src/storage.h
new file mode 100644
index 0000000..bb4289e
--- /dev/null
+++ b/src/storage.h
@@ -0,0 +1,14 @@
1#ifndef __STORAGE_H__
2#define __STORAGE_H__
3
4#include <v8.h>
5
6using namespace v8;
7
8namespace storage {
9
10void RegisterModule(Handle<ObjectTemplate>);
11
12}
13#endif
14
diff --git a/src/timer.cc b/src/timer.cc
new file mode 100644
index 0000000..ea9be7d
--- /dev/null
+++ b/src/timer.cc
@@ -0,0 +1,136 @@
1#include <v8.h>
2#include <Ecore.h>
3#include "timer.h"
4
5using namespace v8;
6
7namespace timer {
8
9static int log_domain;
10
11#define DBG(...) EINA_LOG_DOM_DBG(log_domain, __VA_ARGS__)
12#define INF(...) EINA_LOG_DOM_INFO(log_domain, __VA_ARGS__)
13#define WRN(...) EINA_LOG_DOM_WARN(log_domain, __VA_ARGS__)
14#define ERR(...) EINA_LOG_DOM_ERR(log_domain, __VA_ARGS__)
15#define CRT(...) EINA_LOG_DOM_CRITICAL(log_domain, __VA_ARGS__)
16
17static void clearInterval(Handle<Value> val);
18
19class Timer {
20public:
21 Eina_Bool repeat;
22 Eina_Bool on_interval;
23
24 Timer(double interval_, Handle<Value> callback_, bool repeat_, const Local<Object>& thisObj_) {
25 obj = Persistent<Object>::New(Object::New());
26 obj->SetHiddenValue(String::NewSymbol("elev8::timer"), External::New(this));
27
28 timer = ecore_timer_add(interval_, Timer::OnInterval, this);
29 thisObj = Persistent<Object>::New(thisObj_);
30 callback = Persistent<Value>::New(callback_);
31 repeat = repeat_;
32 on_interval = false;
33 }
34
35 Handle<Object> ToObject() {
36 return obj;
37 }
38
39 ~Timer() {
40 obj->DeleteHiddenValue(String::NewSymbol("elev8::timer"));
41 ecore_timer_del(timer);
42 obj.Dispose();
43 thisObj.Dispose();
44 callback.Dispose();
45 }
46
47private:
48 Persistent<Object> obj;
49 Ecore_Timer *timer;
50 Persistent<Object> thisObj;
51 Persistent<Value> callback;
52
53 static Persistent<FunctionTemplate> tmpl;
54
55 static Eina_Bool OnInterval(void *data)
56 {
57 HandleScope scope;
58 Timer *t = static_cast<Timer *>(data);
59 Handle<Function> func(Function::Cast(*t->callback));
60 t->on_interval = true;
61 func->Call(t->thisObj, 0, NULL);
62 t->on_interval = false;
63
64 if (t->repeat)
65 return ECORE_CALLBACK_RENEW;
66
67 clearInterval(t->ToObject());
68 return ECORE_CALLBACK_CANCEL;
69 }
70};
71
72static void clearInterval(Handle<Value> val)
73{
74 HandleScope scope;
75
76 if (!val->IsObject())
77 return;
78
79 Local<Value> timer = val->ToObject()->GetHiddenValue(String::NewSymbol("elev8::timer"));
80
81 if (timer.IsEmpty())
82 return;
83
84 Timer *t = static_cast<Timer *>(External::Cast(*timer)->Value());
85 t->repeat = false;
86
87 if (!t->on_interval)
88 delete t;
89}
90
91static Handle<Value> New(const Arguments& args, bool repeat)
92{
93 HandleScope scope;
94
95 if (!args[0]->IsFunction())
96 return Undefined();
97
98 double interval = args[1]->IsNumber() ? args[1]->NumberValue() / 1000. : 0;
99 return ((new Timer(interval, args[0], repeat, args.This()))->ToObject());
100}
101
102static Handle<Value> clearInterval(const Arguments& args)
103{
104 clearInterval(args[0]);
105 return Undefined();
106}
107
108static Handle<Value> setInterval(const Arguments& args)
109{
110 return New(args, true);
111}
112
113static Handle<Value> setTimeout(const Arguments& args)
114{
115 return New(args, false);
116}
117
118void RegisterModule(Handle<ObjectTemplate> global)
119{
120 log_domain = eina_log_domain_register("elev8-timer", EINA_COLOR_ORANGE);
121 if (!log_domain)
122 {
123 ERR( "could not register elev8-timer log domain.");
124 log_domain = EINA_LOG_DOMAIN_GLOBAL;
125 }
126
127 INF("elev8-timer Logging initialized. %d", log_domain);
128
129 ecore_init();
130 global->Set("setTimeout", FunctionTemplate::New(setTimeout));
131 global->Set("setInterval", FunctionTemplate::New(setInterval));
132 global->Set("clearTimeout", FunctionTemplate::New(clearInterval));
133 global->Set("clearInterval", FunctionTemplate::New(clearInterval));
134}
135
136}
diff --git a/src/timer.h b/src/timer.h
new file mode 100644
index 0000000..dbc37e5
--- /dev/null
+++ b/src/timer.h
@@ -0,0 +1,13 @@
1#ifndef __TIMER_H__
2#define __TIMER_H__
3
4#include <v8.h>
5
6using namespace v8;
7
8namespace timer {
9
10void RegisterModule(Handle<ObjectTemplate>);
11
12}
13#endif
diff --git a/src/utils.cc b/src/utils.cc
new file mode 100644
index 0000000..2985f7f
--- /dev/null
+++ b/src/utils.cc
@@ -0,0 +1,82 @@
1#include <v8.h>
2#include <Ecore.h>
3#include "utils.h"
4
5using namespace v8;
6
7namespace utils {
8
9int log;
10
11#define UTILS_DBG(...) EINA_LOG_DOM_DBG(log, __VA_ARGS__)
12#define UTILS_INF(...) EINA_LOG_DOM_INFO(log, __VA_ARGS__)
13#define UTILS_WRN(...) EINA_LOG_DOM_WARN(log, __VA_ARGS__)
14#define UTILS_ERR(...) EINA_LOG_DOM_ERR(log, __VA_ARGS__)
15#define UTILS_CRT(...) EINA_LOG_DOM_CRITICAL(log, __VA_ARGS__)
16
17static Handle<Value>
18deep_clone(Local<Value> value) {
19 HandleScope scope;
20 if (!value->IsObject())
21 return Undefined();
22
23 Local<Object> obj = value->ToObject();
24 Local<Object> clone =obj->Clone();
25 Local<Array> props = clone->GetOwnPropertyNames();
26
27 for (unsigned int i = 0; i < props->Length(); i++)
28 {
29 Local<Value> key = props->Get(i);
30 if (clone->Get(key)->IsObject())
31 clone->Set(key, deep_clone(obj->Get(key)));
32 }
33
34 return scope.Close(clone);
35}
36
37static Handle<Value>
38clone(const Arguments &args)
39{
40 Local<Value> object = args[0];
41 Local<Value> deep = args[1];
42
43 if (object->IsUndefined())
44 return Undefined();
45
46 if (!deep->BooleanValue())
47 return object->ToObject()->Clone();
48
49 return deep_clone(object);
50}
51
52static Handle<Value>
53isObjectEmpty(const Arguments& args)
54{
55 HandleScope scope;
56 Local<Object> object = args[0]->ToObject();
57
58 if (object->IsUndefined())
59 return Undefined();
60
61 return Boolean::New(object->GetOwnPropertyNames()->Length() == 0);
62}
63
64void RegisterModule(Handle<ObjectTemplate> global)
65{
66 log = eina_log_domain_register("elev8-utils", EINA_COLOR_ORANGE);
67 if (!log)
68 {
69 UTILS_ERR("could not register elev8-utils log domain.");
70 log = EINA_LOG_DOMAIN_GLOBAL;
71 }
72
73 UTILS_INF("elev8-utils Logging initialized. %d", log);
74
75 Handle<ObjectTemplate> tmpl = ObjectTemplate::New();
76 tmpl->Set("clone", FunctionTemplate::New(clone));
77 tmpl->Set("isEmpty", FunctionTemplate::New(isObjectEmpty));
78
79 global->Set("utils", tmpl);
80}
81
82}
diff --git a/src/utils.h b/src/utils.h
new file mode 100644
index 0000000..270d071
--- /dev/null
+++ b/src/utils.h
@@ -0,0 +1,14 @@
1#ifndef __UTILS_JS_H__
2#define __UTILS_JS_H__
3
4#include <v8.h>
5
6using namespace v8;
7
8namespace utils {
9
10void RegisterModule(Handle<ObjectTemplate>);
11
12}
13#endif
14
diff --git a/test-gadget.js b/test-gadget.js
new file mode 100644
index 0000000..e1d2284
--- /dev/null
+++ b/test-gadget.js
@@ -0,0 +1,45 @@
1elm = require('elm');
2
3GadCon.init = function(gadget, name, id, style) {
4 gadget.elements = {
5 le_label: elm.Label({
6 label: name
7 }),
8 le_button: elm.Button({
9 label: 'btn'
10 }),
11 }
12};
13
14GadCon.menu_obj = [
15 { label: 'Foo' },
16 {
17 label: 'Bar',
18 check: 1,
19 callback: function() {
20 print('clicked ' + this.label + '; ' + this.check);
21 this.check = !this.check;
22 }
23 },
24 {},
25 {
26 label: 'Baz',
27 items: [
28 {
29 label: 'Bla',
30 check: 1
31 },
32 {
33 label: 'Deep',
34 items: [
35 { label: 'Hierarchy!' }
36 ]
37 }
38 ]
39 },
40 { label: 'Has submenu', items: [ { label: 'Bla' } ] }
41];
42
43GadCon.menu = function(name, id) {
44 return GadCon.menu_obj;
45}