aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLaurent Ghigonis <laurent@p1sec.com>2013-03-18 23:50:28 +0100
committerLaurent Ghigonis <laurent@p1sec.com>2013-03-18 23:50:28 +0100
commitb82e1730f6361ab6814a0cf825ff33cd0122d26a (patch)
tree4d4c2d575c2fc16e323253da9210b0aeaa63f8ac
downloadelife-b82e1730f6361ab6814a0cf825ff33cd0122d26a.tar.gz
initial import for elife
elife - Game of life as e17 background Support for reacting to local machine activity can be compiled optionnaly (disabled by default). See README
-rw-r--r--AUTHORS1
-rw-r--r--COPYING1
-rw-r--r--ChangeLog1
-rw-r--r--Makefile.am6
-rw-r--r--NEWS6
-rw-r--r--README83
-rwxr-xr-xautogen.sh17
-rw-r--r--configure.ac64
-rw-r--r--data/Makefile.am18
-rw-r--r--data/elife.edc48
-rw-r--r--m4/efl_binary.m471
-rw-r--r--src/Makefile.am37
-rw-r--r--src/elife.c106
-rw-r--r--src/elife_edje_external.c192
-rw-r--r--src/elife_evas_smart.c558
-rw-r--r--src/elife_evas_smart.h8
16 files changed, 1217 insertions, 0 deletions
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..4e42cdc
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1 @@
+Laurent Ghigonis <laurent@p1sec.com>
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/COPYING
@@ -0,0 +1 @@
+
diff --git a/ChangeLog b/ChangeLog
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1 @@
+
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..215bf9f
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,6 @@
+AUTOMAKE_OPTIONS = 1.4 foreign
+MAINTAINERCLEANFILES = Makefile.in
+
+SUBDIRS = src data
+
+ACLOCAL_AMFLAGS = -I m4
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..5c5261f
--- /dev/null
+++ b/NEWS
@@ -0,0 +1,6 @@
+bal$ git log --reverse --tags --simplify-by-decoration --pretty="format:%ai %d"
+2012-10-14 16:35:56 +0200
+2012-11-04 18:59:46 +0100 (v1.0)
+2012-11-04 19:14:50 +0100 (v1.1)
+2012-11-05 04:09:01 +0100 (origin/master, origin/manual_draw, manual_draw)
+2012-11-05 04:12:52 +0100 (HEAD, v1.2, master)
diff --git a/README b/README
new file mode 100644
index 0000000..cf5e968
--- /dev/null
+++ b/README
@@ -0,0 +1,83 @@
+elife - Game of life as e17 background
+v1.2
+
+Support for reacting to local machine activity can be compiled optionnaly
+(disabled by default).
+See section "Glouglou support".
+
+Packaging and general structure from EEnvader.fractal by Boris Faure <billiob@gmail.com>
+Many thanks to you Boris !
+
+Dependencies
+============
+
+Enlightenment 0.16.999 (aka e17)
+
+Install
+=======
+
+./autogen.sh
+make
+sudo make install
+
+"elife" will then appear in the "System" category of e17 wallpapers configuration panel.
+A binary called "elife" is also created and installed to run elife in standalone.
+
+Glouglou support
+================
+
+To enable glouglou support, pass --enable-glouglou to automake scripts :
+./autogen.sh --enable-glouglou
+OR
+./configure --enable-glouglou
+
+You will need libglouglou and glougloud
+
+Elife slows down my e17 !
+=========================
+
+elife is running in the same process as e17 therefore it can slow down the
+whole window manager, depending on your machine CPU.
+
+To improve this, you can:
+
+* Use OpenGL rendering in e17 by using the Composite module, and set the engine
+to OpenGL in Composite > Rendering pannel
+
+* Reduce the size of the elife grid by modifying the source code, in
+src/elife_evas_smart.c at the definitions of NCELL_X and NCELL_Y
+
+TODO
+====
+
+* make install without sudo rights
+* make a gadget
+
+Code organisation
+=================
+
+The core code is in src/elife_evas_smart.c
+All the other files are here to build standalone binary and edje file.
+
+src/elife_evas_smart.c
+ At each life cycle, grid_evolution() gets called
+
+Ideas
+=====
+
+freenode #e
+20:08 < loran> for the moment each cell is an evas_object. having the whole grid as one evas object and filling polygons manually (i'll take a look at seed
+ algorithm) might be faster, not sure
+20:10 < loran> but if i can have opengl rendering for the background with composite module for example, then i will improve other parts of elife, like having cell
+ created on external events like new processes, packets blocked by firewall, ...
+20:10 < loran> :p
+20:15 < drohan> it sounds interesting, but for future reference, you need a way to gain trust from the users, a background that uses cpu is not trusted, if you
+ change it as a widget or something else or try to comment all the code so the users can see what you are doing with it
+20:16 < loran> haha good point :p
+20:17 < drohan> and even then you will have a little problem with trust, change everything so you don't have to install it system wide, just local .e dir
+20:17 < loran> i think you can run make install without system rights
+20:17 < loran> without sudo
+
+Optimisation ideas:
+* one evas_object_rectangle, manualy write memory inside it (DONE)
+
diff --git a/autogen.sh b/autogen.sh
new file mode 100755
index 0000000..ae01364
--- /dev/null
+++ b/autogen.sh
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+rm -rf autom4te.cache
+rm -f aclocal.m4 ltmain.sh
+
+touch README
+
+echo "Running autopoint..." ; autopoint -f || :
+echo "Running aclocal..." ; aclocal -I m4 $ACLOCAL_FLAGS || 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
index 0000000..60d1703
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,64 @@
+dnl Process this file with autoconf to produce a configure script.
+
+# get rid of that stupid cache mechanism
+rm -f config.cache
+
+AC_INIT(elife, 0.1, laurent@p1sec.com)
+AC_PREREQ(2.52)
+AC_CONFIG_SRCDIR(configure.ac)
+AC_CANONICAL_BUILD
+AC_CANONICAL_HOST
+AC_ISC_POSIX
+
+AM_INIT_AUTOMAKE(1.6)
+AM_CONFIG_HEADER(config.h)
+m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
+
+AC_PROG_CC_C99
+AC_HEADER_STDC
+AC_C_CONST
+AM_PROG_CC_C_O
+
+define([AC_LIBTOOL_LANG_CXX_CONFIG], [:])dnl
+define([AC_LIBTOOL_LANG_F77_CONFIG], [:])dnl
+AC_PROG_LIBTOOL
+
+m4_ifdef([AM_GNU_GETTEXT_VERSION], [
+AM_GNU_GETTEXT_VERSION([0.17])
+])
+
+PKG_PROG_PKG_CONFIG
+PKG_CHECK_MODULES([ELIFE], [edje ecore-evas ecore evas eina])
+datadir_edj=$($PKG_CONFIG --variable=prefix enlightenment)/share/enlightenment/data/backgrounds
+
+EFL_WITH_BIN([edje], [edje-cc], [edje_cc])
+vmaj=$($PKG_CONFIG --variable=vmaj edje)
+MODULE_ARCH="$host_os-$host_cpu-$vmaj.0.0"
+AC_SUBST(MODULE_ARCH)
+AC_DEFINE_UNQUOTED(MODULE_ARCH, "$MODULE_ARCH", "Module architecture")
+
+datadir=$(pkg-config --variable=modules edje)/${PACKAGE}
+AC_ARG_ENABLE(homedir-install,
+ AS_HELP_STRING([--enable-homedir-install], [Install module in homedir]),
+ [
+ datadir="${HOME}/.edje/modules/${PACKAGE}";
+ datadir_edj="${HOME}/.e/e/backgrounds"
+ ]
+)
+AC_SUBST(datadir_edj)
+
+AC_ARG_ENABLE(glouglou,
+[ --enable-glouglou Enable glouglou support],
+[case "${enableval}" in
+ yes) glouglou=true ;;
+ no) glouglou=false ;;
+ *) AC_MSG_ERROR(bad value ${enableval} for --enable-glouglou) ;;
+esac],[glouglou=false])
+AM_CONDITIONAL(HAVE_GLOUGLOU, test x$glouglou = xtrue)
+
+AC_OUTPUT([
+Makefile
+data/Makefile
+src/Makefile
+], [
+])
diff --git a/data/Makefile.am b/data/Makefile.am
new file mode 100644
index 0000000..8664660
--- /dev/null
+++ b/data/Makefile.am
@@ -0,0 +1,18 @@
+AUTOMAKE_OPTIONS = 1.4 foreign
+MAINTAINERCLEANFILES = Makefile.in
+
+EDJE_FLAGS = -v
+
+filesdir = @datadir_edj@
+files_DATA = elife.edj
+
+EXTRA_DIST = elife.edc
+
+elife.edj: elife.edc
+ $(edje_cc) $(EDJE_FLAGS) $< $@
+
+clean-local:
+ rm -rf elife.edj *~
+
+uninstall:
+ rm -rf $(DESTDIR)@datadir_edj@/elife.edj
diff --git a/data/elife.edc b/data/elife.edc
new file mode 100644
index 0000000..69df75c
--- /dev/null
+++ b/data/elife.edc
@@ -0,0 +1,48 @@
+externals {
+ external: "elife";
+}
+
+collections {
+ group {
+ name: "e/desktop/background";
+
+ script {
+ public clock_cb(unused) {
+ emit("elife:refresh", "☃");
+ timer(0.5, "clock_cb", 1);
+ }
+ }
+
+ parts {
+ part {
+ name: "bg";
+ type: RECT;
+ description {
+ state: "default" 0.0;
+ color: 0 0 0 255;
+ }
+ }
+ part {
+ name: "elife";
+ type: EXTERNAL;
+ source: "elife";
+
+ description {
+ state: "default" 0.0;
+ }
+ }
+ }
+
+ // Get everything started at load
+ programs {
+ program {
+ name: "init";
+ signal: "load";
+ source: "";
+ script {
+ clock_cb(0);
+ }
+ }
+ }
+ }
+}
diff --git a/m4/efl_binary.m4 b/m4/efl_binary.m4
new file mode 100644
index 0000000..c774688
--- /dev/null
+++ b/m4/efl_binary.m4
@@ -0,0 +1,71 @@
+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 transformed into _)
+dnl Define have_binary (- is transformed into _)
+dnl Define conditional BUILD_BINARY (BINARY is the uppercase of binary, - being transformed 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])
+
+])
+
+
+dnl Macro that check if a binary is built or not
+
+dnl Usage: EFL_WITH_BIN(package, binary, default_value)
+dnl Call AC_SUBST(_binary) (_binary is the lowercase of binary, - being transformed into _ by default, or the value set by the user)
+
+AC_DEFUN([EFL_WITH_BIN],
+[
+
+m4_pushdef([DOWN], m4_translit([[$2]], [-A-Z], [_a-z]))dnl
+
+dnl configure option
+
+AC_ARG_WITH([$2],
+ [AC_HELP_STRING([--with-$2=PATH], [specify a specific path to ]DOWN[ @<:@default=$3@:>@])],
+ [_efl_with_binary=${withval}],
+ [_efl_with_binary=$(pkg-config --variable=prefix $1)/bin/$3])
+
+DOWN=${_efl_with_binary}
+AC_MSG_NOTICE(DOWN[ set to ${_efl_with_binary}])
+
+with_binary_[]m4_defn([DOWN])=${_efl_with_binary}
+
+AC_SUBST(DOWN)
+
+])
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..f8135a0
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,37 @@
+MAINTAINERCLEANFILES = Makefile.in
+INCLUDES = -I. \
+ -I$(top_srcdir) \
+ -I$(includedir) \
+ @ELIFE_CFLAGS@
+
+
+pkgdir = $(datadir)/$(MODULE_ARCH)
+pkg_LTLIBRARIES = module.la
+module_la_SOURCES = \
+ elife_evas_smart.c \
+ elife_edje_external.c
+
+module_la_LIBADD = @ELIFE_LIBS@
+module_la_DEPENDENCIES = $(top_builddir)/config.h
+
+bin_PROGRAMS = elife
+elife_SOURCES = \
+ elife_evas_smart.c \
+ elife.c
+elife_CPPFLAGS = \
+ @ELIFE_CFLAGS@
+
+if HAVE_GLOUGLOU
+module_la_LDFLAGS = -module -avoid-version -lglouglou -levent
+module_la_CFLAGS = -DHAVE_GLOUGLOU
+elife_LDADD = \
+ @ELIFE_LIBS@ -lglouglou -levent
+elife_CFLAGS = -DHAVE_GLOUGLOU
+else
+module_la_LDFLAGS = -module -avoid-version
+elife_LDADD = \
+ @ELIFE_LIBS@
+endif
+
+clean-local:
+ rm -rf *~
diff --git a/src/elife.c b/src/elife.c
new file mode 100644
index 0000000..8b97cb8
--- /dev/null
+++ b/src/elife.c
@@ -0,0 +1,106 @@
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <Evas.h>
+#include <Ecore.h>
+#include <Ecore_Evas.h>
+
+#include "elife_evas_smart.h"
+
+#define BG 0xff002b36
+#define FG 0xff839496
+
+#define MIN(a,b) (((a)<(b))?(a):(b))
+
+static struct {
+ Ecore_Evas *ee;
+ Evas *evas;
+ Evas_Coord w, h;
+ Evas_Object *bg;
+ Evas_Object *elife;
+} elife_g;
+#define _G elife_g
+
+static void
+resize_cb(Ecore_Evas *ee)
+{
+ int w, h;
+
+ ecore_evas_geometry_get(ee, NULL, NULL, &w, &h);
+ evas_object_resize(_G.bg, w, h);
+ evas_object_resize(_G.elife, w, h);
+}
+
+static Eina_Bool
+timer_cb(void *data)
+{
+ Evas_Object *o = (Evas_Object *)data;
+
+ evas_object_smart_callback_call(o, "refresh", NULL);
+
+ return EINA_TRUE;
+}
+
+int
+main(void)
+{
+ unsigned int seedval;
+ int fd;
+
+ if (!ecore_evas_init())
+ return -1;
+
+ _G.w = 600;
+ _G.h = 350;
+
+
+ /*open file */
+ if ((fd = open("/dev/urandom", O_RDONLY)) < 0) {
+ perror(NULL);
+ exit(1);
+ }
+ if (read(fd, &seedval, sizeof(seedval)) != sizeof(seedval)) {
+ perror(NULL);
+ close(fd);
+ exit(1);
+ }
+ close(fd);
+ srand(seedval);
+
+ _G.ee = ecore_evas_software_x11_new(
+ NULL, /* const char * disp_name */
+ 0, /* Ecore_X_Window parent */
+ 0, 0, _G.w, _G.h);
+
+ ecore_evas_title_set(_G.ee, "elife");
+ ecore_evas_borderless_set(_G.ee, 0);
+ ecore_evas_show(_G.ee);
+ _G.evas = ecore_evas_get(_G.ee);
+
+ _G.bg = evas_object_rectangle_add(_G.evas);
+ evas_object_color_set(_G.bg,
+ (BG >> 16) & 0xff,
+ (BG >> 8) & 0xff,
+ BG & 0xff,
+ BG >> 24);
+ evas_object_move(_G.bg, 0, 0);
+ evas_object_resize(_G.bg, _G.w, _G.h);
+ evas_object_show(_G.bg);
+
+ _G.elife = elife_smart_new(_G.evas);
+ evas_object_resize(_G.elife, _G.w, _G.h);
+ evas_object_show(_G.elife);
+
+ ecore_timer_add(0.1, timer_cb, _G.elife);
+
+ ecore_evas_callback_resize_set(_G.ee, &resize_cb);
+
+ ecore_main_loop_begin();
+
+ ecore_evas_shutdown();
+ ecore_shutdown();
+
+ return 0;
+}
diff --git a/src/elife_edje_external.c b/src/elife_edje_external.c
new file mode 100644
index 0000000..14035d2
--- /dev/null
+++ b/src/elife_edje_external.c
@@ -0,0 +1,192 @@
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <Evas.h>
+#include <Ecore.h>
+#include <Ecore_Evas.h>
+#include <Edje.h>
+
+#include "elife_evas_smart.h"
+
+/* Prototypes -{{{-*/
+
+static Evas_Object *
+elife_ext_add(void *data, Evas *evas, Evas_Object *parent,
+ const Eina_List *params, const char *part_name);
+static void
+elife_ext_state_set(void *data, Evas_Object *obj,
+ const void *from_params,
+ const void *to_params, float pos);
+static void
+elife_ext_signal_emit(void *data, Evas_Object *obj,
+ const char *emission, const char *source);
+static Eina_Bool
+elife_ext_param_set(void *data, Evas_Object *obj,
+ const Edje_External_Param *param);
+static Eina_Bool
+elife_ext_param_get(void *data, const Evas_Object *obj,
+ Edje_External_Param *param);
+static Evas_Object *
+elife_ext_content_get(void *data, const Evas_Object *obj,
+ const char *content);
+static void*
+elife_ext_params_parse(void *data, Evas_Object *obj,
+ const Eina_List *params);
+static void
+elife_ext_params_free(void *params);
+static const char*
+elife_ext_label_get(void *data);
+static const char*
+elife_ext_description_get(void *data);
+static Evas_Object *
+elife_ext_icon_add(void *data, Evas *e);
+static Evas_Object *
+elife_ext_preview_add(void *data, Evas *e);
+static const char*
+elife_ext_translate(void *data, const char *orig);
+
+/* }}} */
+/* Globals -{{{-*/
+
+static struct {
+ Edje_External_Type ext_type;
+} elife_g = {
+ .ext_type = {
+ .abi_version = EDJE_EXTERNAL_TYPE_ABI_VERSION,
+ .module = "elife",
+ .module_name = "elife",
+ .add = elife_ext_add,
+ .state_set = elife_ext_state_set,
+ .signal_emit = elife_ext_signal_emit,
+ .param_set = elife_ext_param_set,
+ .param_get = elife_ext_param_get,
+ .content_get = elife_ext_content_get,
+ .params_parse = elife_ext_params_parse,
+ .params_free = elife_ext_params_free,
+ .label_get = elife_ext_label_get,
+ .description_get = elife_ext_description_get,
+ .icon_add = elife_ext_icon_add,
+ .preview_add = elife_ext_preview_add,
+ .translate = elife_ext_translate,
+ },
+};
+#define _G elife_g
+
+/* }}} */
+/* Edje External -{{{-*/
+
+static Evas_Object *
+elife_ext_add(void *data, Evas *evas, Evas_Object *parent,
+ const Eina_List *params, const char *part_name)
+{
+ return elife_smart_new(evas);
+}
+
+static void
+elife_ext_state_set(void *data, Evas_Object *obj,
+ const void *from_params,
+ const void *to_params, float pos)
+{
+}
+
+static void
+elife_ext_signal_emit(void *data, Evas_Object *obj,
+ const char *emission, const char *source)
+{
+ evas_object_smart_callback_call(obj, emission, NULL);
+}
+
+static Eina_Bool
+elife_ext_param_set(void *data, Evas_Object *obj,
+ const Edje_External_Param *param)
+{
+ return EINA_TRUE;
+}
+
+static Eina_Bool
+elife_ext_param_get(void *data, const Evas_Object *obj,
+ Edje_External_Param *param)
+{
+ return EINA_TRUE;
+}
+
+static Evas_Object *
+elife_ext_content_get(void *data, const Evas_Object *obj,
+ const char *content)
+{
+ return NULL;
+}
+
+static void*
+elife_ext_params_parse(void *data, Evas_Object *obj,
+ const Eina_List *params)
+{
+ return NULL;
+}
+
+static void
+elife_ext_params_free(void *params)
+{
+}
+
+static const char*
+elife_ext_label_get(void *data)
+{
+ return NULL;
+}
+
+static const char*
+elife_ext_description_get(void *data)
+{
+ return NULL;
+}
+
+static Evas_Object *
+elife_ext_icon_add(void *data, Evas *e)
+{
+ return NULL;
+}
+
+static Evas_Object *
+elife_ext_preview_add(void *data, Evas *e)
+{
+ return NULL;
+}
+
+static const char*
+elife_ext_translate(void *data, const char *orig)
+{
+ return NULL;
+}
+/* }}} */
+/* Init/Shutdown -{{{-*/
+
+Eina_Bool
+elife_init(void)
+{
+ unsigned int seedval = time(NULL);
+ int fd;
+
+ if ((fd = open("/dev/random", O_RDONLY)) >= 0) {
+ read(fd, &seedval, sizeof(seedval));
+ close(fd);
+ }
+ srand(seedval);
+
+ edje_external_type_register("elife", &_G.ext_type);
+
+ return EINA_TRUE;
+}
+
+void
+elife_shutdown(void)
+{
+ edje_external_type_unregister("elife");
+}
+
+EINA_MODULE_INIT(elife_init);
+EINA_MODULE_SHUTDOWN(elife_shutdown);
+
+/* }}} */
diff --git a/src/elife_evas_smart.c b/src/elife_evas_smart.c
new file mode 100644
index 0000000..acbd9a2
--- /dev/null
+++ b/src/elife_evas_smart.c
@@ -0,0 +1,558 @@
+/*
+ * elife - Game of life / Living graphic
+ */
+
+/*
+ * Copyright (c) 2012 Laurent Ghigonis <laurent@p1sec.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include <err.h>
+
+#include "elife_evas_smart.h"
+
+#ifdef HAVE_GLOUGLOU
+#include <libglouglou.h>
+#endif
+
+#define NCELL_X 100
+#define NCELL_Y 100
+#define INJECT_PROBA 40
+#define INITCELL_PROBA 7
+#define CONWAY_GROW_DIE 600
+#define DEBUG 0
+
+#define MIN(a,b) (((a)<(b))?(a):(b))
+#define CELL_GET(grid, x, y) &(grid->cells[(y*grid->w) + x])
+
+typedef struct lifepattern_s {
+ const int w;
+ const int h;
+ const char *pat;
+} lifepattern_s;
+
+enum lifepattern_t {
+ ELIFE_PAT_BEEHIVE = 0,
+ ELIFE_PAT_BOAT = 1,
+ ELIFE_PAT_SHIP = 2,
+ ELIFE_PAT_LOAF = 3,
+ ELIFE_PAT_QUEENBEE = 4,
+ ELIFE_PAT_GLIDER = 5,
+ ELIFE_PAT_LWSS = 6,
+};
+#define PATTERN_COUNT 7
+
+lifepattern_s lifepatterns[] = {
+ [ELIFE_PAT_BEEHIVE] = {3, 4, "010101101010"},
+ [ELIFE_PAT_BOAT] = {3, 3, "010101011"},
+ [ELIFE_PAT_SHIP] = {3, 3, "110101011"},
+ [ELIFE_PAT_LOAF] = {4, 4, "0110100101010010"},
+ [ELIFE_PAT_QUEENBEE] = {4, 7, "1100001000010001000100101100"},
+ [ELIFE_PAT_GLIDER] = {3, 3, "010011101"},
+ [ELIFE_PAT_LWSS] = {5, 4, "10010000011000101111"},
+};
+
+enum lifemode {
+ ELIFE_MODE_CONWAY,
+ ELIFE_MODE_CONWAY_GROW,
+ ELIFE_MODE_LORAN_CIVILISATION,
+};
+
+struct cell {
+ int age, newage;
+ u_int32_t forced_color;
+ int x, y;
+ int r, g, b;
+};
+
+struct grid {
+ Evas_Object *container;
+ struct cell *cells;
+ Evas_Object *image;
+ int *mem;
+ int w, h;
+ int pix_w, pix_h;
+ int cell_pix_w, cell_pix_h;
+ int age;
+ enum lifemode mode;
+#ifdef HAVE_GLOUGLOU
+ struct gg_client *ggcli;
+ struct event_base *ev_base;
+#endif
+};
+
+static struct grid *grid_new(Evas_Object *container,
+ int w, int h, enum lifemode mode);
+static void grid_del(struct grid *grid);
+static int grid_evolution(struct grid *grid);
+static void grid_inject_pattern(struct grid *grid, u_int32_t color);
+static int grid_redraw(struct grid *grid, int w, int h);
+static int cell_neighbours_count(struct cell *cell, struct grid *grid);
+static void cell_redraw(struct cell *c, struct grid *g);
+static void grid_mouse_down(void *data, Evas *evas, Evas_Object *child,
+ void *event_info);
+
+Evas_Object *elife_smart_new(Evas *e);
+static void elife_on_refresh(void *data, Evas_Object *o,
+ void *event_info);
+static Evas_Object *elife_object_new(Evas *evas);
+static Evas_Smart *_elife_object_smart_get(void);
+static void _elife_object_del(Evas_Object *o);
+static void _elife_object_move(Evas_Object *o,
+ Evas_Coord x, Evas_Coord y);
+static void _elife_object_resize(Evas_Object *o,
+ Evas_Coord w, Evas_Coord h);
+/* Not implemented
+static void _elife_object_show(Evas_Object *o);
+static void _elife_object_hide(Evas_Object *o);
+static void _elife_object_color_set(Evas_Object *o, int r, int g, int b, int a);
+static void _elife_object_clip_set(Evas_Object *o, Evas_Object *clip);
+static void _elife_object_clip_unset(Evas_Object *o);
+*/
+void *xmalloc(size_t size);
+
+static struct {
+ Evas_Smart_Class klass;
+} elife_evas_smart_g = {
+ .klass = {
+ .name = "elife_object",
+ .version = EVAS_SMART_CLASS_VERSION,
+ .add = NULL,
+ .del = _elife_object_del,
+ .move = _elife_object_move,
+ .resize = _elife_object_resize,
+ .show = NULL,
+ .hide = NULL,
+ .color_set = NULL,
+ .clip_set = NULL,
+ .clip_unset = NULL,
+ .calculate = NULL,
+ .member_add = NULL,
+ .member_del = NULL,
+ .parent = NULL,
+ .callbacks = NULL,
+ .interfaces = NULL,
+ .data = NULL,
+ },
+#define _G elife_evas_smart_g
+};
+
+#ifdef HAVE_GLOUGLOU
+int
+gg_packet(struct gg_client *cli, struct gg_packet *pkt)
+{
+ struct grid *grid;
+ u_int32_t color;
+
+ grid = cli->usrdata;
+ switch(pkt->type) {
+ case PACKET_FORK: color=0xff0000; break;
+ case PACKET_EXEC: color=0x00ff00; break;
+ case PACKET_EXIT: color=0x0000ff; break;
+ default: return 0;
+ }
+ grid_inject_pattern(grid, color);
+
+ return 0;
+}
+#endif
+
+static struct grid *
+grid_new(Evas_Object *container, int w, int h, enum lifemode mode)
+{
+ struct grid *g;
+ struct cell *cell;
+ Evas_Object *o;
+ int i, j;
+
+ g = xmalloc(sizeof(struct grid));
+ g->container = container;
+ o = evas_object_image_filled_add(evas_object_evas_get(container));
+ if (!o)
+ err(1, "Cannot create image for grid");
+ evas_object_image_alpha_set(o, EINA_FALSE);
+ evas_object_image_smooth_scale_set(o, EINA_FALSE);
+ evas_object_data_set(o, "grid", g);
+ evas_object_event_callback_add(o, EVAS_CALLBACK_MOUSE_DOWN,
+ grid_mouse_down, g);
+ evas_object_smart_member_add(o, container);
+ evas_object_show(o);
+ g->image = o;
+ g->mem = NULL;
+ g->w = w;
+ g->h = h;
+ g->age = 0;
+ g->mode = mode;
+ g->cells = xmalloc(sizeof(struct cell) * w * h);
+ for (j=0; j<h; j++) {
+ for (i=0; i<w; i++) {
+ cell = CELL_GET(g, i, j);
+ cell->x = i;
+ cell->y = j;
+ cell->r = 0;
+ cell->g = 0;
+ cell->b = 0;
+ cell->forced_color = 0x000000;
+ cell->age = !(rand() % INITCELL_PROBA);
+ }
+ }
+
+#ifdef HAVE_GLOUGLOU
+ g->ev_base = event_base_new();
+ g->ggcli = gg_client_connect(g->ev_base, "127.0.0.1", GLOUGLOU_ANALY_DEFAULT_PORT,
+ NULL, gg_packet, g);
+#endif
+
+ return g;
+}
+
+static void
+grid_del(struct grid *grid)
+{
+#ifdef HAVE_GLOUGLOU
+ gg_client_disconnect(grid->ggcli);
+#endif
+ free(grid->cells);
+ free(grid->mem);
+ free(grid);
+}
+
+static int
+grid_evolution(struct grid *grid)
+{
+ struct cell *cell;
+ int i, j;
+ int neighbours;
+
+ for (j=0; j<grid->h; j++) {
+ for (i=0; i<grid->w; i++) {
+ cell = CELL_GET(grid, i, j);
+ neighbours = cell_neighbours_count(cell, grid);
+ switch (grid->mode) {
+ case ELIFE_MODE_CONWAY:
+ if (cell->age == 0 && neighbours == 3)
+ cell->newage = 1;
+ else if (cell->age > 0 && (neighbours == 2 || neighbours == 3))
+ cell->newage = cell->age;
+ else
+ cell->newage = 0;
+ break;
+ case ELIFE_MODE_CONWAY_GROW:
+ if (cell->age == 0 && neighbours == 3)
+ cell->newage = 1;
+ else if (cell->age > 0 && (neighbours == 2 || neighbours == 3))
+ if (cell->age > CONWAY_GROW_DIE)
+ cell->newage = 0;
+ else
+ cell->newage = cell->age + 1;
+ else
+ cell->newage = 0;
+ break;
+ case ELIFE_MODE_LORAN_CIVILISATION:
+ if (neighbours == 4 || neighbours < 2)
+ cell->newage = 0;
+ else if (neighbours > 2 && neighbours != 5)
+ cell->newage = cell->age + 1;
+ else if (neighbours == 2 && cell->age > 1)
+ cell->newage = 0;
+ else
+ cell->newage = cell->age;
+ if (cell->age > 100)
+ cell->newage = 0;
+ break;
+ }
+ if (cell->newage == 0 && cell->forced_color)
+ cell->forced_color = 0;
+ if (DEBUG)
+ printf("evolution: %d %d n %d age %d newage %d\n", i, j,
+ neighbours, cell->age, cell->newage);
+ }
+ }
+
+#ifdef HAVE_GLOUGLOU
+ event_base_loop(grid->ev_base, EVLOOP_NONBLOCK);
+#else
+ if (rand() % INJECT_PROBA == 0)
+ grid_inject_pattern(grid, 0);
+#endif
+
+ for (j=0; j<grid->h; j++) {
+ for (i=0; i<grid->w; i++) {
+ cell = CELL_GET(grid, i, j);
+ cell->age = cell->newage;
+ cell_redraw(cell, grid);
+ }
+ }
+ evas_object_image_pixels_dirty_set(grid->image, EINA_TRUE);
+
+ grid->age++;
+}
+
+static void
+grid_inject_pattern(struct grid *grid, u_int32_t color)
+{
+ struct cell *cell;
+ enum lifepattern_t npat;
+ lifepattern_s *pat;
+ int x, y, cx, cy;
+ int i, j;
+ int age;
+
+ npat = rand() % PATTERN_COUNT;
+ if (DEBUG)
+ printf("grid_inject_pattern: %d\n", npat);
+ pat = &lifepatterns[npat];
+ x = rand() % (grid->w - pat->w);
+ y = rand() % (grid->h - pat->h);
+ for (j=0; j<pat->h; j++) {
+ for (i=0; i<pat->w; i++) {
+ cx = x + i;
+ cy = y + j;
+ if (cx >= grid->w || cy >= grid->h)
+ continue;
+ cell = CELL_GET(grid, cx, cy);
+ age = (pat->pat[pat->w*j + i] - '0') * 27;
+ if (age != 0)
+ cell->newage = age;
+ cell->forced_color = color;
+ cell->age = cell->newage;
+ // cell_redraw(cell, grid);
+ }
+ }
+}
+
+static int
+grid_redraw(struct grid *grid, int w, int h)
+{
+ struct cell *cell;
+ int i,j;
+ Evas_Object *o;
+
+ grid->cell_pix_w = w / grid->w;
+ grid->cell_pix_h = h / grid->h;
+ grid->pix_w = (w / grid->w) * grid->w;
+ grid->pix_h = (h / grid->h) * grid->h;
+ if (DEBUG)
+ printf("redraw: container %d %d cell %d %d\n", w, h, grid->cell_pix_w, grid->cell_pix_h);
+
+ evas_object_image_fill_set(grid->image, 0, 0, grid->pix_w, grid->pix_h);
+ evas_object_image_size_set (grid->image, grid->pix_w, grid->pix_h);
+ evas_object_resize(grid->image, w, h);
+ /* XXX could be optimized to avoid flickering on resize */
+ if (grid->mem)
+ free(grid->mem);
+ grid->mem = calloc(w * h, sizeof(int));
+ if (!grid->mem)
+ err(1, "could not calloc grid->mem");
+ evas_object_image_data_set(grid->image, (void *) grid->mem);
+ for (j=0; j<grid->h; j++) {
+ for (i=0; i<grid->w; i++) {
+ cell = CELL_GET(grid, i, j);
+ cell_redraw(cell, grid);
+ }
+ }
+}
+
+static int
+cell_neighbours_count(struct cell *cell, struct grid *grid)
+{
+ struct cell *ncell;
+ int m, n, cx, cy;
+ int count;
+
+ count = 0;
+ for (n=-1; n<=1; n++) {
+ for (m=-1; m<=1; m++) {
+ if (m == 0 && n == 0)
+ continue;
+ cx = cell->x + m;
+ cy = cell->y + n;
+ if (cx < 0 || cx >= grid->w || cy < 0 || cy >= grid->h)
+ continue;
+ ncell = CELL_GET(grid, cx, cy);
+ if (ncell->age > 0)
+ count++;
+ }
+ }
+
+ return count;
+}
+
+static void
+cell_redraw(struct cell *c, struct grid *grid)
+{
+ u_int8_t r, g, b, a;
+ int x, y, w, h;
+ int i, j;
+ int color;
+
+ if (c->forced_color && c->age > 0) {
+ r = (c->forced_color & 0xff0000) >> 16;
+ g = (c->forced_color & 0xff00) >> 8;
+ b = (c->forced_color & 0xff);
+ } else if (c->age < 100) {
+ r = (c->age > 0) ? 128 : 0;
+ g = (c->age > 0) ? (33 + c->age * 7) : 0;
+ b = 0;
+ } else if (c->age < CONWAY_GROW_DIE - 50) {
+ r = 128 - c->age;
+ g = 255 - c->age;
+ b = (c->age - 100) * 2;
+ } else {
+ r = 255;
+ g = (c->age % 2) * 255;
+ b = 255;
+ }
+ a = 255;
+ if (r == c->r && g == c->g && b == c->b)
+ return;
+ c->r = r;
+ c->g = g;
+ c->b = b;
+
+ x = c->x * grid->cell_pix_w;
+ y = c->y * grid->cell_pix_h;
+ w = grid->cell_pix_w;
+ h = grid->cell_pix_h;
+ for (j=y; j<y+h; j++) {
+ for (i=x; i<x+w; i++) {
+ color = 0xff000000 + (r << 16) + (g << 8) + (b);
+ grid->mem[j*grid->pix_w + i] = color;
+ }
+ }
+}
+
+static void
+grid_mouse_down(void *data,
+ Evas *evas,
+ Evas_Object *child,
+ void *event_info)
+{
+ Evas_Coord x, y, w, h;
+ Evas_Event_Mouse_Up *evt = event_info;
+ struct grid *grid;
+
+ grid = data;
+ grid_inject_pattern(grid, 0);
+}
+
+Evas_Object *
+elife_smart_new(Evas *e)
+{
+ return elife_object_new(e);
+}
+
+static void
+elife_on_refresh(void *data, Evas_Object *o, void *event_info)
+{
+ Evas_Coord x, y, w, h;
+ Evas_Object *child;
+ struct grid *grid;
+
+ grid = evas_object_data_get(o, "grid");
+
+ grid_evolution(grid);
+}
+
+static Evas_Object *
+elife_object_new(Evas *evas)
+{
+ Evas_Object *elife_object;
+ struct grid *grid;
+
+ elife_object = evas_object_smart_add(evas,
+ _elife_object_smart_get());
+ grid = grid_new(elife_object, NCELL_X, NCELL_Y, ELIFE_MODE_CONWAY_GROW);
+ evas_object_data_set(elife_object, "grid", grid);
+ evas_object_smart_callback_add(elife_object,
+ "refresh",
+ elife_on_refresh,
+ NULL);
+
+ return elife_object;
+}
+
+static Evas_Smart *
+_elife_object_smart_get(void)
+{
+ static Evas_Smart *smart = NULL;
+
+ if (smart)
+ return smart;
+
+ smart = evas_smart_class_new(&_G.klass);
+ return smart;
+}
+
+static void
+_elife_object_del(Evas_Object *o)
+{
+ Evas_Object *child;
+ struct grid *grid;
+ Eina_List *list;
+
+ list = evas_object_smart_members_get(o);
+ EINA_LIST_FREE(list, child) {
+ evas_object_smart_member_del(child);
+ evas_object_del(child);
+ }
+ grid = evas_object_data_del(o, "grid");
+ grid_del(grid);
+}
+
+static void
+_elife_object_move(Evas_Object *o, Evas_Coord x, Evas_Coord y)
+{
+ Evas_Coord orig_x, orig_y, dx, dy;
+ Eina_List *lst;
+ Evas_Object *child;
+ void *data;
+
+ if (DEBUG)
+ printf("oject_move: %d %d\n", x, y);
+ evas_object_geometry_get(o, &orig_x, &orig_y, NULL, NULL);
+ dx = x - orig_x;
+ dy = y - orig_y;
+
+ lst = evas_object_smart_members_get(o);
+ EINA_LIST_FREE(lst, data) {
+ child = data;
+ evas_object_geometry_get(child, &orig_x, &orig_y, NULL, NULL);
+ evas_object_move(child, orig_x + dx, orig_y + dy);
+ }
+}
+
+static void
+_elife_object_resize(Evas_Object *o, Evas_Coord w, Evas_Coord h)
+{
+ struct grid *grid;
+
+ if (DEBUG)
+ printf("oject_resize: %d %d\n", w, h);
+ grid = evas_object_data_get(o, "grid");
+ grid_redraw(grid, w, h);
+}
+
+void *
+xmalloc(size_t size)
+{
+ void *x;
+
+ x = malloc(size);
+ if (!x)
+ err(1, "Error: failed to allocate %d", size);
+ return x;
+}
+
diff --git a/src/elife_evas_smart.h b/src/elife_evas_smart.h
new file mode 100644
index 0000000..b5a5b85
--- /dev/null
+++ b/src/elife_evas_smart.h
@@ -0,0 +1,8 @@
+#ifndef ELIFE_SMART_H
+#define ELIFE_SMART_H
+#include <Evas.h>
+
+Evas_Object *elife_smart_new(Evas *e);
+
+#endif
+