summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Zaoui <daniel.zaoui@yahoo.com>2018-12-24 22:51:52 +0200
committerStefan Schmidt <s.schmidt@samsung.com>2020-02-04 14:49:46 +0100
commite93b33e781211bd7ac8020036dbb3d4f79de0c9d (patch)
tree556661a752e09cc8ffbe9ef9719b4c90ca63510f
parent25888fb5b06d0986c35010d545cf71ca93daed7e (diff)
downloadefl-e93b33e781211bd7ac8020036dbb3d4f79de0c9d.tar.gz
exactness: import code from external repo into efl.git
Exactness has been developed in a separate git repo for many years. This finally moves it over into efl. Having it in tree allows us for easier testing with our current main target elementary_test and integration into our CI system (patches for this are work in progress already). We are only importing the lib and binary for test execution, not the full set of test data. This is would be over 500MB and thus it will stay in a different repo and only made available during the actual testing. [The original patch was made by Daniel Zaoui. Over the course of review and testing it got extended with build fixes for API changes and mingw compilation support from Stefan Schmidt and Michael Blumenkrantz]
-rw-r--r--meson.build1
-rw-r--r--src/bin/exactness/.gitignore5
-rw-r--r--src/bin/exactness/exactness.c675
-rw-r--r--src/bin/exactness/injector.c483
-rw-r--r--src/bin/exactness/inspect.c1653
-rw-r--r--src/bin/exactness/meson.build42
-rw-r--r--src/bin/exactness/player.c1393
-rw-r--r--src/bin/exactness/player_entry.edc932
-rw-r--r--src/bin/exactness/recorder.c531
-rw-r--r--src/lib/exactness/Exactness.h268
-rw-r--r--src/lib/exactness/exactness_private.h10
-rw-r--r--src/lib/exactness/legacy_file.c876
-rw-r--r--src/lib/exactness/meson.build31
-rw-r--r--src/lib/exactness/unit.c424
14 files changed, 7324 insertions, 0 deletions
diff --git a/meson.build b/meson.build
index 5ee96f0f09..fb77c43570 100644
--- a/meson.build
+++ b/meson.build
@@ -335,6 +335,7 @@ subprojects = [
['elua' ,['elua'] , false, true, true, false, true, false, ['eina', 'luajit'], []],
['ecore_wayland' ,['wl-deprecated'] , false, true, false, false, false, false, ['eina'], []],
['ecore_drm' ,['drm-deprecated'] , false, true, false, false, false, false, ['eina'], []],
+['exactness' ,[] , false, true, true, false, false, false, ['eina, evas, eet'], []],
]
# We generate Efl_Config.h and config.h later, they will be available here
diff --git a/src/bin/exactness/.gitignore b/src/bin/exactness/.gitignore
new file mode 100644
index 0000000000..2760101039
--- /dev/null
+++ b/src/bin/exactness/.gitignore
@@ -0,0 +1,5 @@
+/exactness
+/exactness_inject
+/exactness_inspect
+/exactness_play
+/exactness_record
diff --git a/src/bin/exactness/exactness.c b/src/bin/exactness/exactness.c
new file mode 100644
index 0000000000..06c6097cf5
--- /dev/null
+++ b/src/bin/exactness/exactness.c
@@ -0,0 +1,675 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <Ecore.h>
+#include <Ecore_Getopt.h>
+#include <Ecore_Evas.h>
+#include <Ecore_File.h>
+
+#include "exactness_private.h"
+
+#ifdef _WIN32
+# include <evil_private.h> /* mkdir */
+#endif
+
+#define SCHEDULER_CMD_SIZE 1024
+
+#define ORIG_SUBDIR "orig"
+#define CURRENT_SUBDIR "current"
+
+#define EXACTNESS_PATH_MAX 1024
+
+#define BUF_SIZE 1024
+
+typedef struct
+{
+ EINA_INLIST;
+ char *name;
+ const char *command;
+} List_Entry;
+
+typedef enum
+{
+ RUN_SIMULATION,
+ RUN_PLAY,
+ RUN_INIT
+} Run_Mode;
+
+static unsigned short _running_jobs = 0, _max_jobs = 1;
+static Eina_List *_base_dirs = NULL;
+static char *_dest_dir;
+static char *_wrap_command = NULL, *_fonts_dir = NULL;
+static int _verbose = 0;
+static Eina_Bool _scan_objs = EINA_FALSE, _disable_screenshots = EINA_FALSE, _stabilize_shots = EINA_FALSE;
+
+static Run_Mode _mode;
+static List_Entry *_next_test_to_run = NULL;
+static unsigned int _tests_executed = 0;
+
+static Eina_List *_errors;
+static Eina_List *_compare_errors;
+
+static Eina_Bool _job_consume();
+
+static void
+_printf(int verbose, const char *fmt, ...)
+{
+ va_list ap;
+ if (!_verbose || verbose > _verbose) return;
+
+ va_start(ap, fmt);
+ vprintf(fmt, ap);
+ va_end(ap);
+}
+
+static Exactness_Image *
+_image_load(const char *filename)
+{
+ int w, h;
+ Evas_Load_Error err;
+ Ecore_Evas *ee = ecore_evas_new(NULL, 0, 0, 100, 100, NULL);
+ Eo *e = ecore_evas_get(ee);
+
+ Eo *img = evas_object_image_add(e);
+ evas_object_image_file_set(img, filename, NULL);
+ err = evas_object_image_load_error_get(img);
+ if (err != EVAS_LOAD_ERROR_NONE)
+ {
+ fprintf(stderr, "could not load image '%s'. error string is \"%s\"\n",
+ filename, evas_load_error_str(err));
+ return NULL;
+ }
+
+ Exactness_Image *ex_img = malloc(sizeof(*ex_img));
+ int len;
+ evas_object_image_size_get(img, &w, &h);
+ ex_img->w = w;
+ ex_img->h = h;
+ len = w * h * 4;
+ ex_img->pixels = malloc(len);
+ memcpy(ex_img->pixels, evas_object_image_data_get(img, EINA_FALSE), len);
+
+ ecore_evas_free(ee);
+ return ex_img;
+}
+
+static void
+_image_save(Exactness_Image *ex_img, const char *output)
+{
+ Ecore_Evas *ee;
+ Eo *e, *img;
+ ee = ecore_evas_new(NULL, 0, 0, 100, 100, NULL);
+ e = ecore_evas_get(ee);
+ img = evas_object_image_add(e);
+ evas_object_image_size_set(img, ex_img->w, ex_img->h);
+ evas_object_image_data_set(img, ex_img->pixels);
+ evas_object_image_save(img, output, NULL, NULL);
+ ecore_evas_free(ee);
+}
+
+static Eina_Bool
+_file_compare(const char *orig_dir, const char *ent_name)
+{
+ Eina_Bool result = EINA_FALSE;
+ Exactness_Image *img1, *img2, *imgO = NULL;
+ char *filename1 = alloca(strlen(orig_dir) + strlen(ent_name) + 20);
+ char *filename2 = alloca(strlen(_dest_dir) + strlen(ent_name) + 20);
+ sprintf(filename1, "%s/%s", orig_dir, ent_name);
+ sprintf(filename2, "%s/%s/%s", _dest_dir, CURRENT_SUBDIR, ent_name);
+
+ img1 = _image_load(filename1);
+ img2 = _image_load(filename2);
+
+ if (exactness_image_compare(img1, img2, &imgO))
+ {
+ char *buf = alloca(strlen(_dest_dir) + strlen(ent_name));
+ sprintf(buf, "%s/%s/comp_%s", _dest_dir, CURRENT_SUBDIR, ent_name);
+ _image_save(imgO, buf);
+ _compare_errors = eina_list_append(_compare_errors, strdup(ent_name));
+ result = EINA_TRUE;
+ }
+ exactness_image_free(img1);
+ exactness_image_free(img2);
+ exactness_image_free(imgO);
+ return result;
+}
+
+static void
+_exu_imgs_unpack(const char *exu_path, const char *dir, const char *ent_name)
+{
+ Exactness_Unit *unit = exactness_unit_file_read(exu_path);
+ Exactness_Image *img;
+ Eina_List *itr;
+ Ecore_Evas *ee = ecore_evas_new(NULL, 0, 0, 100, 100, NULL);
+ Eo *e = ecore_evas_get(ee);
+ int n = 1;
+ if (!unit) return;
+ EINA_LIST_FOREACH(unit->imgs, itr, img)
+ {
+ Eo *o = evas_object_image_add(e);
+ char *filename = alloca(strlen(dir) + strlen(ent_name) + 20);
+ snprintf(filename, EXACTNESS_PATH_MAX, "%s/%s%c%.3d.png",
+ dir, ent_name, SHOT_DELIMITER, n++);
+ evas_object_image_size_set(o, img->w, img->h);
+ evas_object_image_data_set(o, img->pixels);
+ if (!evas_object_image_save(o, filename, NULL, NULL))
+ {
+ printf("Cannot save widget to <%s>\n", filename);
+ }
+ efl_del(o);
+ }
+ efl_del(e);
+ ecore_evas_free(ee);
+}
+
+static void
+_run_test_compare(const List_Entry *ent)
+{
+ char *path = alloca(EXACTNESS_PATH_MAX);
+ char *origdir = alloca(strlen(_dest_dir) + 20);
+ const char *base_dir;
+ Eina_List *itr;
+ int n = 1, nb_fails = 0;
+ printf("STATUS %s: COMPARE\n", ent->name);
+ EINA_LIST_FOREACH(_base_dirs, itr, base_dir)
+ {
+ sprintf(path, "%s/%s.exu", base_dir, ent->name);
+ if (ecore_file_exists(path))
+ {
+ char *currentdir;
+ sprintf(origdir, "%s/%s/%s", _dest_dir, CURRENT_SUBDIR, ORIG_SUBDIR);
+ mkdir(origdir, 0744);
+ _exu_imgs_unpack(path, origdir, ent->name);
+ sprintf(path, "%s/%s/%s.exu", _dest_dir, CURRENT_SUBDIR, ent->name);
+ currentdir = alloca(strlen(_dest_dir) + 20);
+ sprintf(currentdir, "%s/%s", _dest_dir, CURRENT_SUBDIR);
+ _exu_imgs_unpack(path, currentdir, ent->name);
+ goto found;
+ }
+ else
+ {
+ sprintf(path, "%s/%s.rec", base_dir, ent->name);
+ if (ecore_file_exists(path))
+ {
+ sprintf(origdir, "%s/%s", _dest_dir, ORIG_SUBDIR);
+ goto found;
+ }
+ }
+ }
+found:
+ do
+ {
+ sprintf(path, "%s/%s%c%.3d.png", origdir, ent->name, SHOT_DELIMITER, n);
+ if (ecore_file_exists(path))
+ {
+ sprintf(path, "%s%c%.3d.png", ent->name, SHOT_DELIMITER, n);
+ if (_file_compare(origdir, path)) nb_fails++;
+ }
+ else break;
+ n++;
+ } while (EINA_TRUE);
+ if (!nb_fails)
+ printf("STATUS %s: END - SUCCESS\n", ent->name);
+ else
+ printf("STATUS %s: END - FAIL (%d/%d)\n", ent->name, nb_fails, n - 1);
+}
+
+#define CONFIG "ELM_SCALE=1 ELM_FINGER_SIZE=10 "
+static Eina_Bool
+_run_command_prepare(const List_Entry *ent, char *buf)
+{
+ char scn_path[EXACTNESS_PATH_MAX];
+ Eina_Strbuf *sbuf;
+ const char *base_dir;
+ Eina_List *itr;
+ Eina_Bool is_exu;
+ EINA_LIST_FOREACH(_base_dirs, itr, base_dir)
+ {
+ is_exu = EINA_TRUE;
+ sprintf(scn_path, "%s/%s.exu", base_dir, ent->name);
+ if (ecore_file_exists(scn_path)) goto ok;
+ else
+ {
+ is_exu = EINA_FALSE;
+ sprintf(scn_path, "%s/%s.rec", base_dir, ent->name);
+ if (ecore_file_exists(scn_path)) goto ok;
+ }
+ }
+ fprintf(stderr, "Test %s not found in the provided base directories\n", ent->name);
+ return EINA_FALSE;
+ok:
+ sbuf = eina_strbuf_new();
+ printf("STATUS %s: START\n", ent->name);
+ eina_strbuf_append_printf(sbuf,
+ "%s exactness_play %s %s%s %s%.*s %s%s%s-t '%s' ",
+ _wrap_command ? _wrap_command : "",
+ _mode == RUN_SIMULATION ? "-s" : "",
+ _fonts_dir ? "-f " : "", _fonts_dir ? _fonts_dir : "",
+ _verbose ? "-" : "", _verbose, "vvvvvvvvvv",
+ _scan_objs ? "--scan-objects " : "",
+ _disable_screenshots ? "--disable-screenshots " : "",
+ _stabilize_shots ? "--stabilize-shots " : "",
+ scn_path
+ );
+ if (is_exu)
+ {
+ if (_mode == RUN_PLAY)
+ eina_strbuf_append_printf(sbuf, "-o '%s/%s/%s.exu' ", _dest_dir, CURRENT_SUBDIR, ent->name);
+ if (_mode == RUN_INIT)
+ eina_strbuf_append_printf(sbuf, "-o '%s' ", scn_path);
+ }
+ else
+ {
+ if (_mode == RUN_PLAY)
+ eina_strbuf_append_printf(sbuf, "-o '%s/%s' ", _dest_dir, CURRENT_SUBDIR);
+ if (_mode == RUN_INIT)
+ eina_strbuf_append_printf(sbuf, "-o '%s/%s' ", _dest_dir, ORIG_SUBDIR);
+ }
+ if (ent->command)
+ {
+ eina_strbuf_append(sbuf, "-- ");
+ eina_strbuf_append(sbuf, CONFIG);
+ eina_strbuf_append(sbuf, ent->command);
+ }
+ strncpy(buf, eina_strbuf_string_get(sbuf), SCHEDULER_CMD_SIZE-1);
+ eina_strbuf_free(sbuf);
+ _printf(1, "Command: %s\n", buf);
+ return EINA_TRUE;
+}
+
+static void
+_job_compare(void *data)
+{
+ _run_test_compare(data);
+
+ _running_jobs--;
+ _job_consume();
+ /* If all jobs are done. */
+ if (!_running_jobs) ecore_main_loop_quit();
+}
+
+static Eina_Bool
+_job_deleted_cb(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
+{
+ Ecore_Exe_Event_Del *msg = (Ecore_Exe_Event_Del *) event;
+ List_Entry *ent = ecore_exe_data_get(msg->exe);
+
+ if ((msg->exit_code != 0) || (msg->exit_signal != 0))
+ {
+ _errors = eina_list_append(_errors, ent);
+ }
+
+ if (_mode == RUN_PLAY)
+ {
+ ecore_job_add(_job_compare, ent);
+ }
+ else
+ {
+ _running_jobs--;
+ _job_consume();
+ if (!_running_jobs) ecore_main_loop_quit();
+ }
+
+ return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_job_consume()
+{
+ static Ecore_Event_Handler *job_del_callback_handler = NULL;
+ char buf[SCHEDULER_CMD_SIZE];
+ List_Entry *ent = _next_test_to_run;
+
+ if (_running_jobs == _max_jobs) return EINA_FALSE;
+ if (!ent) return EINA_FALSE;
+
+ if (_run_command_prepare(ent, buf))
+ {
+ _running_jobs++;
+ _tests_executed++;
+
+ if (!job_del_callback_handler)
+ {
+ job_del_callback_handler = ecore_event_handler_add(ECORE_EXE_EVENT_DEL,
+ _job_deleted_cb, NULL);
+ }
+
+ if (!ecore_exe_pipe_run(buf, ECORE_EXE_TERM_WITH_PARENT, ent))
+ {
+ fprintf(stderr, "Failed executing test '%s'\n", ent->name);
+ }
+ }
+ _next_test_to_run = EINA_INLIST_CONTAINER_GET(
+ EINA_INLIST_GET(ent)->next, List_Entry);
+
+
+ return EINA_TRUE;
+}
+
+static void
+_scheduler_run()
+{
+ while (_job_consume());
+}
+
+static List_Entry *
+_list_file_load(const char *filename)
+{
+ List_Entry *ret = NULL;
+ char buf[BUF_SIZE] = "";
+ FILE *file;
+ file = fopen(filename, "r");
+ if (!file)
+ {
+ perror("Failed opening list file");
+ return NULL;
+ }
+
+ while (fgets(buf, BUF_SIZE, file))
+ {
+ /* Skip comment/empty lines. */
+ if ((*buf == '#') || (*buf == '\n') || (!*buf))
+ continue;
+
+ char *tmp;
+ List_Entry *cur = calloc(1, sizeof(*cur));
+ cur->name = strdup(buf);
+
+ /* Set the command to the second half and put a \0 in between. */
+ tmp = strchr(cur->name, ' ');
+ if (tmp)
+ {
+ *tmp = '\0';
+ cur->command = tmp + 1;
+ }
+ else
+ {
+ /* FIXME: error. */
+ cur->command = "";
+ }
+
+ /* Replace the newline char with a \0. */
+ tmp = strchr(cur->command, '\n');
+ if (tmp)
+ {
+ *tmp = '\0';
+ }
+
+ ret = EINA_INLIST_CONTAINER_GET(
+ eina_inlist_append(EINA_INLIST_GET(ret), EINA_INLIST_GET(cur)),
+ List_Entry);
+ }
+
+ return ret;
+}
+
+static void
+_list_file_free(List_Entry *list)
+{
+ while (list)
+ {
+ List_Entry *ent = list;
+ list = EINA_INLIST_CONTAINER_GET(EINA_INLIST_GET(list)->next,
+ List_Entry);
+
+ free(ent->name);
+ free(ent);
+ /* we don't free ent->command because it's allocated together. */
+ }
+}
+
+static int
+_errors_sort_cb(List_Entry *a, List_Entry *b)
+{
+ return strcmp(a->name, b->name);
+}
+
+static const Ecore_Getopt optdesc = {
+ "exactness",
+ "%prog [options] <-r|-p|-i|-s> <list file>",
+ PACKAGE_VERSION,
+ "(C) 2013 Enlightenment",
+ "BSD",
+ "A pixel perfect test suite for EFL based applications.",
+ 0,
+ {
+ ECORE_GETOPT_APPEND('b', "base-dir", "The location of the exu/rec files.", ECORE_GETOPT_TYPE_STR),
+ ECORE_GETOPT_STORE_STR('o', "output", "The location of the images."),
+ ECORE_GETOPT_STORE_STR('w', "wrap", "Use a custom command to launch the tests (e.g valgrind)."),
+ ECORE_GETOPT_STORE_USHORT('j', "jobs", "The number of jobs to run in parallel."),
+ ECORE_GETOPT_STORE_TRUE('p', "play", "Run in play mode."),
+ ECORE_GETOPT_STORE_TRUE('i', "init", "Run in init mode."),
+ ECORE_GETOPT_STORE_TRUE('s', "simulation", "Run in simulation mode."),
+ ECORE_GETOPT_STORE_TRUE(0, "scan-objects", "Extract information of all the objects at every shot."),
+ ECORE_GETOPT_STORE_TRUE(0, "disable-screenshots", "Disable screenshots."),
+ ECORE_GETOPT_STORE_STR('f', "fonts-dir", "Specify a directory of the fonts that should be used."),
+ ECORE_GETOPT_STORE_TRUE(0, "stabilize-shots", "Wait for the frames to be stable before taking the shots."),
+ ECORE_GETOPT_COUNT('v', "verbose", "Turn verbose messages on."),
+
+ ECORE_GETOPT_LICENSE('L', "license"),
+ ECORE_GETOPT_COPYRIGHT('C', "copyright"),
+ ECORE_GETOPT_VERSION('V', "version"),
+ ECORE_GETOPT_HELP('h', "help"),
+ ECORE_GETOPT_SENTINEL
+ }
+};
+
+int
+main(int argc, char *argv[])
+{
+ int ret = 0;
+ List_Entry *test_list;
+ int args = 0;
+ const char *list_file;
+ Eina_List *itr;
+ const char *base_dir;
+ char tmp[EXACTNESS_PATH_MAX];
+ Eina_Bool mode_play = EINA_FALSE, mode_init = EINA_FALSE, mode_simulation = EINA_FALSE;
+ Eina_Bool want_quit = EINA_FALSE, scan_objs = EINA_FALSE;
+ Ecore_Getopt_Value values[] = {
+ ECORE_GETOPT_VALUE_LIST(_base_dirs),
+ ECORE_GETOPT_VALUE_STR(_dest_dir),
+ ECORE_GETOPT_VALUE_STR(_wrap_command),
+ ECORE_GETOPT_VALUE_USHORT(_max_jobs),
+ ECORE_GETOPT_VALUE_BOOL(mode_play),
+ ECORE_GETOPT_VALUE_BOOL(mode_init),
+ ECORE_GETOPT_VALUE_BOOL(mode_simulation),
+ ECORE_GETOPT_VALUE_BOOL(scan_objs),
+ ECORE_GETOPT_VALUE_BOOL(_disable_screenshots),
+ ECORE_GETOPT_VALUE_STR(_fonts_dir),
+ ECORE_GETOPT_VALUE_BOOL(_stabilize_shots),
+ ECORE_GETOPT_VALUE_INT(_verbose),
+
+ ECORE_GETOPT_VALUE_BOOL(want_quit),
+ ECORE_GETOPT_VALUE_BOOL(want_quit),
+ ECORE_GETOPT_VALUE_BOOL(want_quit),
+ ECORE_GETOPT_VALUE_BOOL(want_quit),
+ ECORE_GETOPT_VALUE_NONE
+ };
+
+ ecore_init();
+ ecore_evas_init();
+ evas_init();
+ mode_play = mode_init = mode_simulation = EINA_FALSE;
+ want_quit = EINA_FALSE;
+ _dest_dir = "./";
+ _scan_objs = scan_objs;
+
+ args = ecore_getopt_parse(&optdesc, values, argc, argv);
+ if (args < 0)
+ {
+ fprintf(stderr, "Failed parsing arguments.\n");
+ ret = 1;
+ goto end;
+ }
+ else if (want_quit)
+ {
+ ret = 1;
+ goto end;
+ }
+ else if (args == argc)
+ {
+ fprintf(stderr, "Expected test list as the last argument..\n");
+ ecore_getopt_help(stderr, &optdesc);
+ ret = 1;
+ goto end;
+ }
+ else if (mode_play + mode_init + mode_simulation != 1)
+ {
+ fprintf(stderr, "At least and only one of the running modes can be set.\n");
+ ecore_getopt_help(stderr, &optdesc);
+ ret = 1;
+ goto end;
+ }
+
+ if (!_base_dirs) _base_dirs = eina_list_append(NULL, "./recordings");
+
+ list_file = argv[args];
+
+ /* Load the list file and start iterating over the records. */
+ test_list = _list_file_load(list_file);
+ _next_test_to_run = test_list;
+
+ if (!test_list)
+ {
+ fprintf(stderr, "No matching tests found in '%s'\n", list_file);
+ ret = 1;
+ goto end;
+ }
+
+ /* Pre-run summary */
+ fprintf(stderr, "Running with settings:\n");
+ fprintf(stderr, "\tConcurrent jobs: %d\n", _max_jobs);
+ fprintf(stderr, "\tTest list: %s\n", list_file);
+ fprintf(stderr, "\tBase dirs:\n");
+ EINA_LIST_FOREACH(_base_dirs, itr, base_dir)
+ fprintf(stderr, "\t\t%s\n", base_dir);
+ fprintf(stderr, "\tDest dir: %s\n", _dest_dir);
+
+ if (mode_play)
+ {
+ _mode = RUN_PLAY;
+ if (snprintf(tmp, EXACTNESS_PATH_MAX, "%s/%s", _dest_dir, CURRENT_SUBDIR)
+ >= EXACTNESS_PATH_MAX)
+ {
+ fprintf(stderr, "Path too long: %s", tmp);
+ ret = 1;
+ goto end;
+ }
+ mkdir(tmp, 0744);
+ }
+ else if (mode_init)
+ {
+ _mode = RUN_INIT;
+ if (snprintf(tmp, EXACTNESS_PATH_MAX, "%s/%s", _dest_dir, ORIG_SUBDIR)
+ >= EXACTNESS_PATH_MAX)
+ {
+ fprintf(stderr, "Path too long: %s", tmp);
+ ret = 1;
+ goto end;
+ }
+ mkdir(tmp, 0744);
+ }
+ else if (mode_simulation)
+ {
+ _mode = RUN_SIMULATION;
+ }
+ _scheduler_run();
+
+
+ ecore_main_loop_begin();
+
+ /* Results */
+ printf("*******************************************************\n");
+ if (mode_play && EINA_FALSE)
+ {
+ List_Entry *list_itr;
+
+ EINA_INLIST_FOREACH(test_list, list_itr)
+ {
+ _run_test_compare(list_itr);
+ }
+ }
+
+ printf("Finished executing %u out of %u tests.\n",
+ _tests_executed,
+ eina_inlist_count(EINA_INLIST_GET(test_list)));
+
+ /* Sort the errors and the compare_errors. */
+ _errors = eina_list_sort(_errors, 0, (Eina_Compare_Cb) _errors_sort_cb);
+ _compare_errors = eina_list_sort(_compare_errors, 0, (Eina_Compare_Cb) strcmp);
+
+ if (_errors || _compare_errors)
+ {
+ FILE *report_file;
+ char report_filename[EXACTNESS_PATH_MAX] = "";
+ /* Generate the filename. */
+ snprintf(report_filename, EXACTNESS_PATH_MAX,
+ "%s/%s/errors.html",
+ _dest_dir, mode_init ? ORIG_SUBDIR : CURRENT_SUBDIR);
+ report_file = fopen(report_filename, "w+");
+ if (report_file)
+ {
+ printf("%s %p\n", report_filename, report_file);
+ fprintf(report_file,
+ "<?xml version=\"1.0\" encoding=\"UTF-8\"?><!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">"
+ "<html xmlns=\"http://www.w3.org/1999/xhtml\"><head><title>Exactness report</title></head><body>");
+
+ if (_errors)
+ {
+ fprintf(report_file,
+ "<h1>Tests that failed execution:</h1><ul>");
+ List_Entry *ent;
+ printf("List of tests that failed execution:\n");
+ EINA_LIST_FOREACH(_errors, itr, ent)
+ {
+ printf("\t* %s\n", ent->name);
+
+ fprintf(report_file, "<li>%s</li>", ent->name);
+ }
+ fprintf(report_file, "</ul>");
+ }
+
+ if (_compare_errors)
+ {
+ fprintf(report_file,
+ "<h1>Images that failed comparison: (Original, Current, Diff)</h1><ul>");
+ char *test_name;
+ printf("List of images that failed comparison:\n");
+ EINA_LIST_FREE(_compare_errors, test_name)
+ {
+ Eina_Bool is_from_exu;
+ char origpath[EXACTNESS_PATH_MAX];
+ snprintf(origpath, EXACTNESS_PATH_MAX, "%s/%s/orig/%s",
+ _dest_dir, CURRENT_SUBDIR, test_name);
+ is_from_exu = ecore_file_exists(origpath);
+ printf("\t* %s\n", test_name);
+
+ fprintf(report_file, "<li><h2>%s</h2> <img src='%sorig/%s' alt='Original' /> <img src='%s' alt='Current' /> <img src='comp_%s' alt='Diff' /></li>",
+ test_name, is_from_exu ? "" : "../",
+ test_name, test_name, test_name);
+ free(test_name);
+ }
+ fprintf(report_file, "</ul>");
+ }
+ fprintf(report_file,
+ "</body></html>");
+
+ printf("Report html: %s\n", report_filename);
+ ret = 1;
+ }
+ else
+ {
+ perror("Failed opening report file");
+ }
+ }
+
+ _list_file_free(test_list);
+end:
+ evas_shutdown();
+ ecore_evas_shutdown();
+ ecore_shutdown();
+
+ return ret;
+}
diff --git a/src/bin/exactness/injector.c b/src/bin/exactness/injector.c
new file mode 100644
index 0000000000..95e71a6927
--- /dev/null
+++ b/src/bin/exactness/injector.c
@@ -0,0 +1,483 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <unistd.h>
+
+#ifndef EFL_EO_API_SUPPORT
+#define EFL_EO_API_SUPPORT
+#endif
+#include <Eina.h>
+#include <Eet.h>
+#include <Ecore.h>
+#include <Ecore_Getopt.h>
+#include <Elementary.h>
+
+#include <Exactness.h>
+
+#include "exactness_private.h"
+
+typedef struct
+{
+ Eina_Debug_Session *session;
+ int srcid;
+ void *buffer;
+ unsigned int size;
+} _Main_Loop_Info;
+
+#define WRAPPER_TO_XFER_MAIN_LOOP(foo) \
+static void \
+_intern_main_loop ## foo(void *data) \
+{ \
+ _Main_Loop_Info *info = data; \
+ _main_loop ## foo(info->session, info->srcid, info->buffer, info->size); \
+ free(info->buffer); \
+ free(info); \
+} \
+static Eina_Bool \
+foo(Eina_Debug_Session *session, int srcid, void *buffer, int size) \
+{ \
+ _Main_Loop_Info *info = calloc(1, sizeof(*info)); \
+ info->session = session; \
+ info->srcid = srcid; \
+ info->size = size; \
+ if (info->size) \
+ { \
+ info->buffer = malloc(info->size); \
+ memcpy(info->buffer, buffer, info->size); \
+ } \
+ ecore_main_loop_thread_safe_call_async(_intern_main_loop ## foo, info); \
+ return EINA_TRUE; \
+}
+
+#ifndef WORDS_BIGENDIAN
+#define SWAP_64(x) x
+#define SWAP_32(x) x
+#define SWAP_16(x) x
+#define SWAP_DBL(x) x
+#else
+#define SWAP_64(x) eina_swap64(x)
+#define SWAP_32(x) eina_swap32(x)
+#define SWAP_16(x) eina_swap16(x)
+#define SWAP_DBL(x) SWAP_64(x)
+#endif
+
+#define EXTRACT_INT(_buf) \
+({ \
+ int __i; \
+ memcpy(&__i, _buf, sizeof(int)); \
+ _buf += sizeof(int); \
+ SWAP_32(__i); \
+})
+
+#define STORE_INT(_buf, __i) \
+{ \
+ int __i2 = SWAP_32(__i); \
+ memcpy(_buf, &__i2, sizeof(int)); \
+ _buf += sizeof(int); \
+}
+
+#define STORE_DOUBLE(_buf, __d) \
+{ \
+ double __d2 = SWAP_DBL(__d); \
+ memcpy(_buf, &__d2, sizeof(double)); \
+ _buf += sizeof(double); \
+}
+
+#define STORE_STRING(_buf, __s) \
+{ \
+ int __len = (__s ? strlen(__s) : 0) + 1; \
+ if (__s) memcpy(_buf, __s, __len); \
+ else *_buf = '\0'; \
+ _buf += __len; \
+}
+
+static Eina_Stringshare *_src_filename = NULL;
+static Exactness_Unit *_src_unit = NULL;
+static int _verbose = 0;
+
+static Eina_Debug_Session *_session = NULL;
+static int _cid = -1, _pid = -1;
+static Eina_List *_cur_event_list = NULL;
+
+static int _all_apps_get_op = EINA_DEBUG_OPCODE_INVALID;
+static int _mouse_in_op = EINA_DEBUG_OPCODE_INVALID;
+static int _mouse_out_op = EINA_DEBUG_OPCODE_INVALID;
+static int _mouse_wheel_op = EINA_DEBUG_OPCODE_INVALID;
+static int _multi_down_op = EINA_DEBUG_OPCODE_INVALID;
+static int _multi_up_op = EINA_DEBUG_OPCODE_INVALID;
+static int _multi_move_op = EINA_DEBUG_OPCODE_INVALID;
+static int _key_down_op = EINA_DEBUG_OPCODE_INVALID;
+static int _key_up_op = EINA_DEBUG_OPCODE_INVALID;
+static int _take_shot_op = EINA_DEBUG_OPCODE_INVALID;
+static int _efl_event_op = EINA_DEBUG_OPCODE_INVALID;
+static int _click_on_op = EINA_DEBUG_OPCODE_INVALID;
+static int _stabilize_op = EINA_DEBUG_OPCODE_INVALID;
+static int _finish_op = EINA_DEBUG_OPCODE_INVALID;
+
+static Eina_Bool _all_apps_get_cb(Eina_Debug_Session *, int , void *, int);
+
+EINA_DEBUG_OPCODES_ARRAY_DEFINE(_debug_ops,
+ {"Daemon/Client/register_observer", &_all_apps_get_op, NULL},
+ {"Daemon/Client/added", NULL, &_all_apps_get_cb},
+ {"Exactness/Actions/Mouse In", &_mouse_in_op, NULL},
+ {"Exactness/Actions/Mouse Out", &_mouse_out_op, NULL},
+ {"Exactness/Actions/Mouse Wheel", &_mouse_wheel_op, NULL},
+ {"Exactness/Actions/Multi Down", &_multi_down_op, NULL},
+ {"Exactness/Actions/Multi Up", &_multi_up_op, NULL},
+ {"Exactness/Actions/Multi Move", &_multi_move_op, NULL},
+ {"Exactness/Actions/Key Down", &_key_down_op, NULL},
+ {"Exactness/Actions/Key Up", &_key_up_op, NULL},
+ {"Exactness/Actions/Take Shot", &_take_shot_op, NULL},
+ {"Exactness/Actions/EFL Event", &_efl_event_op, NULL},
+ {"Exactness/Actions/Click On", &_click_on_op, NULL},
+ {"Exactness/Actions/Stabilize", &_stabilize_op, NULL},
+ {"Exactness/Actions/Finish", &_finish_op, NULL},
+ {NULL, NULL, NULL}
+ );
+
+static void
+_printf(int verbose, const char *fmt, ...)
+{
+ va_list ap;
+ if (!_verbose || verbose > _verbose) return;
+
+ va_start(ap, fmt);
+ vprintf(fmt, ap);
+ va_end(ap);
+}
+
+static void
+_feed_event(Exactness_Action_Type type, unsigned int n_evas, void *data)
+{
+ switch (type)
+ {
+ case EXACTNESS_ACTION_MOUSE_IN:
+ {
+ _printf(1, "Mouse in\n");
+ _printf(2, "%s evas_event_feed_mouse_in n_evas=<%d>\n", __func__, n_evas);
+ eina_debug_session_send(_session, _cid, _mouse_in_op, &n_evas, sizeof(int));
+ break;
+ }
+ case EXACTNESS_ACTION_MOUSE_OUT:
+ {
+ _printf(1, "Mouse out\n");
+ _printf(2, "%s evas_event_feed_mouse_out n_evas=<%d>\n", __func__, n_evas);
+ eina_debug_session_send(_session, _cid, _mouse_out_op, &n_evas, sizeof(int));
+ break;
+ }
+ case EXACTNESS_ACTION_MOUSE_WHEEL:
+ {
+ Exactness_Action_Mouse_Wheel *t = data;
+ int len = 3*sizeof(int);
+ char *buf = malloc(len), *tmp = buf;
+ _printf(1, "Mouse wheel\n");
+ _printf(2, "%s evas_event_feed_mouse_wheel n_evas=<%d>\n", __func__, n_evas);
+ STORE_INT(tmp, n_evas);
+ STORE_INT(tmp, t->direction);
+ STORE_INT(tmp, t->z);
+ eina_debug_session_send(_session, _cid, _mouse_wheel_op, buf, len);
+ break;
+ }
+ case EXACTNESS_ACTION_MULTI_DOWN:
+ case EXACTNESS_ACTION_MULTI_UP:
+ {
+ Exactness_Action_Multi_Event *t = data;
+ int len = 5*sizeof(int)+7*sizeof(double)+sizeof(int);
+ char *buf = malloc(len), *tmp = buf;
+ _printf(2, "%s %s n_evas=<%d>\n", __func__,
+ type == EXACTNESS_ACTION_MULTI_DOWN ? "evas_event_feed_multi_down" :
+ "evas_event_feed_multi_up", n_evas);
+ STORE_INT(tmp, n_evas);
+ STORE_INT(tmp, t->d);
+ STORE_INT(tmp, t->b);
+ STORE_INT(tmp, t->x);
+ STORE_INT(tmp, t->y);
+ STORE_DOUBLE(tmp, t->rad);
+ STORE_DOUBLE(tmp, t->radx);
+ STORE_DOUBLE(tmp, t->rady);
+ STORE_DOUBLE(tmp, t->pres);
+ STORE_DOUBLE(tmp, t->ang);
+ STORE_DOUBLE(tmp, t->fx);
+ STORE_DOUBLE(tmp, t->fy);
+ STORE_INT(tmp, t->flags);
+ eina_debug_session_send(_session, _cid,
+ type == EXACTNESS_ACTION_MULTI_DOWN ? _multi_down_op : _multi_up_op,
+ buf, len);
+ break;
+ }
+ case EXACTNESS_ACTION_MULTI_MOVE:
+ {
+ Exactness_Action_Multi_Move *t = data;
+ int len = 4*sizeof(int)+7*sizeof(double);
+ char *buf = malloc(len), *tmp = buf;
+ _printf(2, "%s evas_event_feed_multi_move n_evas=<%d>\n", __func__, n_evas);
+ STORE_INT(tmp, n_evas);
+ STORE_INT(tmp, t->d);
+ STORE_INT(tmp, t->x);
+ STORE_INT(tmp, t->y);
+ STORE_DOUBLE(tmp, t->rad);
+ STORE_DOUBLE(tmp, t->radx);
+ STORE_DOUBLE(tmp, t->rady);
+ STORE_DOUBLE(tmp, t->pres);
+ STORE_DOUBLE(tmp, t->ang);
+ STORE_DOUBLE(tmp, t->fx);
+ STORE_DOUBLE(tmp, t->fy);
+ eina_debug_session_send(_session, _cid, _multi_move_op, buf, len);
+ break;
+ }
+ case EXACTNESS_ACTION_KEY_DOWN:
+ case EXACTNESS_ACTION_KEY_UP:
+ {
+ Exactness_Action_Key_Down_Up *t = data;
+ int len = 2*sizeof(int) + 4;
+ len += t->keyname ? strlen(t->keyname) : 0;
+ len += t->key ? strlen(t->key) : 0;
+ len += t->string ? strlen(t->string) : 0;
+ len += t->compose ? strlen(t->compose) : 0;
+ char *buf = malloc(len), *tmp = buf;
+ _printf(2, "%s %s n_evas=<%d>\n", __func__,
+ type == EXACTNESS_ACTION_KEY_DOWN ? "evas_event_feed_key_down " :
+ "evas_event_feed_key_up", n_evas);
+ STORE_INT(tmp, n_evas);
+ STORE_STRING(tmp, t->keyname);
+ STORE_STRING(tmp, t->key);
+ STORE_STRING(tmp, t->string);
+ STORE_STRING(tmp, t->compose);
+ STORE_INT(tmp, t->keycode);
+ eina_debug_session_send(_session, _cid,
+ type == EXACTNESS_ACTION_KEY_DOWN ? _key_down_op : _key_up_op,
+ buf, len);
+ break;
+ }
+ case EXACTNESS_ACTION_TAKE_SHOT:
+ {
+ _printf(2, "%s take shot n_evas=<%d>\n", __func__, n_evas);
+ eina_debug_session_send(_session, _cid, _take_shot_op, &n_evas, sizeof(int));
+ break;
+ }
+ case EXACTNESS_ACTION_EFL_EVENT:
+ {
+ Exactness_Action_Efl_Event *t = data;
+ int len = 0;
+ len += t->wdg_name ? strlen(t->wdg_name) : 0;
+ len += t->event_name ? strlen(t->event_name) : 0;
+ char *buf = malloc(len), *tmp = buf;
+ _printf(2, "%s %s\n", __func__, "EFL event");
+ STORE_STRING(tmp, t->wdg_name);
+ STORE_STRING(tmp, t->event_name);
+ eina_debug_session_send(_session, _cid, _efl_event_op, buf, len);
+ break;
+ }
+ case EXACTNESS_ACTION_CLICK_ON:
+ {
+ Exactness_Action_Click_On *t = data;
+ int len = 0;
+ len += t->wdg_name ? strlen(t->wdg_name) : 0;
+ char *buf = malloc(len), *tmp = buf;
+ _printf(2, "%s %s\n", __func__, "Click On");
+ STORE_STRING(tmp, t->wdg_name);
+ eina_debug_session_send(_session, _cid, _click_on_op, buf, len);
+ break;
+ }
+ case EXACTNESS_ACTION_STABILIZE:
+ {
+ _printf(2, "%s stabilize\n", __func__);
+ eina_debug_session_send(_session, _cid, _stabilize_op, NULL, 0);
+ break;
+ }
+ default: /* All non-input events are not handeled */
+ break;
+ }
+}
+
+static Eina_Bool
+_feed_event_timer_cb(void *data EINA_UNUSED)
+{
+ Exactness_Action *act = eina_list_data_get(_cur_event_list);
+ _feed_event(act->type, act->n_evas, act->data);
+
+ _cur_event_list = eina_list_next(_cur_event_list);
+
+ if (!_cur_event_list)
+ { /* Finished reading all events */
+ eina_debug_session_send(_session, _cid, _finish_op, NULL, 0);
+ ecore_main_loop_quit();
+ }
+ else
+ {
+ Exactness_Action *cur_act = eina_list_data_get(_cur_event_list);
+ ecore_timer_add(cur_act->delay_ms / 1000.0, _feed_event_timer_cb, NULL);
+ }
+ return ECORE_CALLBACK_CANCEL;
+}
+
+static Eina_Bool
+_src_open()
+{
+ double diff_time = 0; /* Time to wait before feeding the first event */
+
+ _printf(2, "<%s> Source file is <%s>\n", __func__, _src_filename);
+ if (!strcmp(_src_filename + strlen(_src_filename) - 4,".exu"))
+ {
+ _src_unit = exactness_unit_file_read(_src_filename);
+ }
+ else if (!strcmp(_src_filename + strlen(_src_filename) - 4,".rec"))
+ {
+ _src_unit = legacy_rec_file_read(_src_filename);
+ }
+ if (!_src_unit) return EINA_FALSE;
+ _cur_event_list = _src_unit->actions;
+ Exactness_Action *act = eina_list_data_get(_cur_event_list);
+
+ if (act->delay_ms)
+ {
+ _printf(2, " Waiting <%f>\n", diff_time);
+ ecore_timer_add(act->delay_ms / 1000.0, _feed_event_timer_cb, NULL);
+ }
+ else
+ {
+ _feed_event_timer_cb(NULL);
+ }
+ return EINA_TRUE;
+}
+
+static void
+_main_loop_all_apps_get_cb(Eina_Debug_Session *session EINA_UNUSED, int srcid EINA_UNUSED, void *buffer, int size EINA_UNUSED)
+{
+ char *buf = buffer;
+ int chosen_cid = -1;
+ if (_cid != -1) return;
+ while (size > 0)
+ {
+ int cid, pid, len;
+ cid = EXTRACT_INT(buf);
+ pid = EXTRACT_INT(buf);
+ if (_pid != -1)
+ {
+ if (_pid == pid)
+ {
+ _cid = cid;
+ _src_open();
+ return;
+ }
+ }
+ else
+ {
+ if (!strcmp(buf, "exactness_play"))
+ {
+ if (chosen_cid != -1)
+ {
+ fprintf(stderr, "Need to specify a PID - too much choice\n");
+ return;
+ }
+ chosen_cid = cid;
+ }
+ }
+ len = strlen(buf) + 1;
+ buf += len;
+ size -= (2 * sizeof(int) + len);
+ }
+ if (chosen_cid != -1)
+ {
+ _cid = chosen_cid;
+ _src_open();
+ }
+}
+
+WRAPPER_TO_XFER_MAIN_LOOP(_all_apps_get_cb)
+
+static void
+_ops_ready_cb(void *data EINA_UNUSED, Eina_Bool status)
+{
+ static Eina_Bool on = EINA_FALSE;
+ if (status)
+ {
+ if (!on)
+ {
+ eina_debug_session_send(_session, 0, _all_apps_get_op, NULL, 0);
+ }
+ on = EINA_TRUE;
+ }
+}
+
+static const Ecore_Getopt optdesc = {
+ "exactness_inject",
+ "%prog [options] <-v|-p|-t|-h> command",
+ PACKAGE_VERSION,
+ "(C) 2018 Enlightenment",
+ "BSD",
+ "A scenario events injector for EFL based applications.",
+ 1,
+ {
+ ECORE_GETOPT_STORE_STR('t', "test", "Test to run on the given application"),
+ ECORE_GETOPT_STORE_INT('p', "pid", "PID of the application to connect to"),
+ ECORE_GETOPT_STORE_INT('r', "remote-port", "Port to connect remotely to the daemon. Local connection if not specified"),
+ ECORE_GETOPT_COUNT('v', "verbose", "Turn verbose messages on."),
+
+ ECORE_GETOPT_LICENSE('L', "license"),
+ ECORE_GETOPT_COPYRIGHT('C', "copyright"),
+ ECORE_GETOPT_VERSION('V', "version"),
+ ECORE_GETOPT_HELP('h', "help"),
+ ECORE_GETOPT_SENTINEL
+ }
+};
+
+int main(int argc, char **argv)
+{
+ int opt_args = 0, real__ = 1, port = -1;
+ char *src = NULL;
+ Eina_Value *ret__;
+ Eina_Bool want_quit = EINA_FALSE;
+
+ Ecore_Getopt_Value values[] = {
+ ECORE_GETOPT_VALUE_STR(src),
+ ECORE_GETOPT_VALUE_INT(_pid),
+ ECORE_GETOPT_VALUE_INT(port),
+ ECORE_GETOPT_VALUE_INT(_verbose),
+
+ ECORE_GETOPT_VALUE_BOOL(want_quit),
+ ECORE_GETOPT_VALUE_BOOL(want_quit),
+ ECORE_GETOPT_VALUE_BOOL(want_quit),
+ ECORE_GETOPT_VALUE_BOOL(want_quit),
+ ECORE_GETOPT_VALUE_NONE
+ };
+
+ eina_init();
+ eet_init();
+ ecore_init();
+
+ opt_args = ecore_getopt_parse(&optdesc, values, argc, argv);
+ if (opt_args < 0)
+ {
+ fprintf(stderr, "Failed parsing arguments.\n");
+ goto end;
+ }
+ if (want_quit) goto end;
+
+ if (!src)
+ {
+ fprintf(stderr, "no test file specified\n");
+ goto end;
+ }
+ _src_filename = eina_stringshare_add(src);
+
+ if (port == -1)
+ _session = eina_debug_local_connect(EINA_TRUE);
+ else
+ _session = eina_debug_remote_connect(port);
+ eina_debug_opcodes_register(_session, _debug_ops(), _ops_ready_cb, NULL);
+
+ elm_init(argc, argv);
+ ret__ = efl_loop_begin(efl_main_loop_get());
+ real__ = efl_loop_exit_code_process(ret__);
+ elm_shutdown();
+end:
+ eet_shutdown();
+ eina_shutdown();
+ return real__;
+}
+
diff --git a/src/bin/exactness/inspect.c b/src/bin/exactness/inspect.c
new file mode 100644
index 0000000000..54f6627f22
--- /dev/null
+++ b/src/bin/exactness/inspect.c
@@ -0,0 +1,1653 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifndef EFL_BETA_API_SUPPORT
+#define EFL_BETA_API_SUPPORT
+#endif
+#ifndef EFL_EO_API_SUPPORT
+#define EFL_EO_API_SUPPORT
+#endif
+#include <Ecore.h>
+#include <Ecore_Getopt.h>
+#include <Ecore_Evas.h>
+#include <Elementary.h>
+#include <Exactness.h>
+#include <Efl_Ui.h>
+
+#include "exactness_private.h"
+
+#define LDIFF(x) "<b><color=#F0F>"#x"</color></b>"
+#define RDIFF(x) "<b><color=#0FF>"#x"</color></b>"
+
+typedef enum
+{
+ EX_FONTS_DIR,
+ EX_SCENARIO,
+ EX_IMAGE,
+ EX_OBJ_INFO
+} _Data_Type;
+
+typedef struct
+{
+ void *p1;
+ void *p2;
+ _Data_Type dt;
+} _Compare_Item_Data;
+
+typedef struct
+{
+ void *ex_parent;
+ Eo *gl_item;
+} _Item_Info;
+
+static Eo *_main_box = NULL;
+static Eina_List *_gls = NULL;
+static Eina_List *_units = NULL;
+static Eo *_comp_selected_item = NULL;
+
+static Elm_Genlist_Item_Class *_grp_itc = NULL, *_scn_itc = NULL, *_img_itc = NULL;
+static Elm_Genlist_Item_Class *_objs_itc = NULL, *_obj_itc = NULL;
+
+static Eina_Hash *_item_infos_hash = NULL;
+
+static Eina_Bool _show_only_diffs = EINA_FALSE;
+static Eina_List *_comp_vvs = NULL;
+
+static Eina_List *_modified_units = NULL;
+
+static const char *
+_action_name_get(Exactness_Action *act)
+{
+ if (!act) return NULL;
+ switch(act->type)
+ {
+ case EXACTNESS_ACTION_MOUSE_IN: return "Mouse In";
+ case EXACTNESS_ACTION_MOUSE_OUT: return "Mouse Out";
+ case EXACTNESS_ACTION_MOUSE_WHEEL: return "Mouse Wheel";
+ case EXACTNESS_ACTION_MULTI_DOWN: return "Multi Down";
+ case EXACTNESS_ACTION_MULTI_UP: return "Multi Up";
+ case EXACTNESS_ACTION_MULTI_MOVE: return "Multi Move";
+ case EXACTNESS_ACTION_KEY_DOWN: return "Key Down";
+ case EXACTNESS_ACTION_KEY_UP: return "Key Up";
+ case EXACTNESS_ACTION_TAKE_SHOT: return "Take shot";
+ case EXACTNESS_ACTION_EFL_EVENT: return "EFL Event";
+ case EXACTNESS_ACTION_CLICK_ON: return "Click On";
+ case EXACTNESS_ACTION_STABILIZE: return "Stabilize";
+ default: return NULL;
+ }
+}
+
+static int
+_event_struct_len_get(Exactness_Action_Type type)
+{
+ switch(type)
+ {
+ case EXACTNESS_ACTION_MOUSE_WHEEL:
+ return sizeof(Exactness_Action_Mouse_Wheel);
+ case EXACTNESS_ACTION_MULTI_DOWN:
+ case EXACTNESS_ACTION_MULTI_UP:
+ return sizeof(Exactness_Action_Multi_Event);
+ case EXACTNESS_ACTION_MULTI_MOVE:
+ return sizeof(Exactness_Action_Multi_Move);
+ case EXACTNESS_ACTION_KEY_DOWN:
+ case EXACTNESS_ACTION_KEY_UP:
+ return sizeof(Exactness_Action_Key_Down_Up);
+ case EXACTNESS_ACTION_EFL_EVENT:
+ return sizeof(Exactness_Action_Efl_Event);
+ case EXACTNESS_ACTION_CLICK_ON:
+ return sizeof(Exactness_Action_Click_On);
+ default: return 0;
+ }
+}
+
+static void
+_action_specific_info_get(const Exactness_Action *act, char output[1024])
+{
+ switch(act->type)
+ {
+ case EXACTNESS_ACTION_MOUSE_WHEEL:
+ {
+ Exactness_Action_Mouse_Wheel *t = act->data;
+ sprintf(output, "Direction %d Z %d", t->direction, t->z);
+ break;
+ }
+ case EXACTNESS_ACTION_MULTI_UP: case EXACTNESS_ACTION_MULTI_DOWN:
+ {
+ Exactness_Action_Multi_Event *t = act->data;
+ if (!t->d)
+ sprintf(output, "Button %d Flags %d", t->b, t->flags);
+ else
+ sprintf(output, "D %d X %d Y %d Rad %f RadX %f RadY %f Pres %f Ang %f FX %f FY %f Flags %d",
+ t->d, t->x, t->y, t->rad, t->radx, t->rady, t->pres, t->ang, t->fx, t->fy, t->flags);
+ break;
+ }
+ case EXACTNESS_ACTION_MULTI_MOVE:
+ {
+ Exactness_Action_Multi_Move *t = act->data;
+ if (!t->d)
+ sprintf(output, "X %d Y %d", t->x, t->y);
+ else
+ sprintf(output, "D %d X %d Y %d Rad %f RadX %f RadY %f Pres %f Ang %f FX %f FY %f",
+ t->d, t->x, t->y, t->rad, t->radx, t->rady, t->pres, t->ang, t->fx, t->fy);
+ break;
+ }
+ case EXACTNESS_ACTION_KEY_UP: case EXACTNESS_ACTION_KEY_DOWN:
+ {
+ Exactness_Action_Key_Down_Up *t = act->data;
+ sprintf(output, "Keyname %s Key %s String %s Compose %s Keycode %d",
+ t->keyname, t->key, t->string, t->compose, t->keycode);
+ break;
+ }
+ case EXACTNESS_ACTION_EFL_EVENT:
+ {
+ Exactness_Action_Efl_Event *t = act->data;
+ sprintf(output, "Widget %s Event %s", t->wdg_name, t->event_name);
+ break;
+ }
+ case EXACTNESS_ACTION_CLICK_ON:
+ {
+ Exactness_Action_Click_On *t = act->data;
+ sprintf(output, "Widget %s", t->wdg_name);
+ break;
+ }
+ default:
+ {
+ output[0] = '\0';
+ break;
+ }
+ }
+}
+
+static Eina_Bool
+_is_hook_duplicate(const Exactness_Action *cur_act, const Exactness_Action *prev_act)
+{
+ if (!prev_act) return EINA_FALSE;
+ if (cur_act->type == prev_act->type)
+ {
+ int len = _event_struct_len_get(cur_act->type);
+ return (!len || !memcmp(cur_act->data, prev_act->data, len));
+ }
+ return EINA_FALSE;
+}
+
+static Eina_Bool
+_are_scenario_entries_different(Exactness_Action *act1, Exactness_Action *act2)
+{
+ if (!act1 ^ !act2) return EINA_TRUE;
+ if (act1->type != act2->type) return EINA_TRUE;
+ switch(act1->type)
+ {
+ case EXACTNESS_ACTION_MOUSE_WHEEL:
+ return !!memcmp(act1->data, act2->data, sizeof(Exactness_Action_Mouse_Wheel));
+ case EXACTNESS_ACTION_MULTI_DOWN: case EXACTNESS_ACTION_MULTI_UP:
+ return !!memcmp(act1->data, act2->data, sizeof(Exactness_Action_Multi_Event));
+ case EXACTNESS_ACTION_MULTI_MOVE:
+ return !!memcmp(act1->data, act2->data, sizeof(Exactness_Action_Multi_Move));
+ case EXACTNESS_ACTION_KEY_UP: case EXACTNESS_ACTION_KEY_DOWN:
+ return !!memcmp(act1->data, act2->data, sizeof(Exactness_Action_Key_Down_Up));
+ case EXACTNESS_ACTION_EFL_EVENT:
+ {
+ Exactness_Action_Efl_Event *e1 = act1->data;
+ Exactness_Action_Efl_Event *e2 = act2->data;
+ return (!!strcmp(e1->wdg_name, e2->wdg_name) ||
+ !!strcmp(e1->event_name, e2->event_name));
+ }
+ case EXACTNESS_ACTION_CLICK_ON:
+ {
+ Exactness_Action_Click_On *e1 = act1->data;
+ Exactness_Action_Click_On *e2 = act2->data;
+ return (!!strcmp(e1->wdg_name, e2->wdg_name));
+ }
+ default:
+ return EINA_FALSE;
+ }
+ return EINA_FALSE;
+}
+
+static Eina_Bool
+_are_images_different(Exactness_Image *e_img1, Exactness_Image *e_img2)
+{
+ unsigned int w, h;
+ int *pxs1 = NULL;
+ int *pxs2 = NULL;
+ if (!e_img1 ^ !e_img2) return EINA_TRUE;
+ if (e_img1->w != e_img2->w) return EINA_TRUE;
+ if (e_img1->h != e_img2->h) return EINA_TRUE;
+ pxs1 = e_img1->pixels;
+ pxs2 = e_img2->pixels;
+ for (w = 0; w < e_img1->w; w++)
+ {
+ for (h = 0; h < e_img1->h; h++)
+ {
+ if (pxs1[h * e_img1->w + w] != pxs2[h * e_img1->w + w])
+ return EINA_TRUE;
+ }
+ }
+ return EINA_FALSE;
+}
+
+static Eina_Bool
+_are_objs_different(Exactness_Object *e_obj1, Exactness_Object *e_obj2, Eina_Bool check_objs)
+{
+ if (!e_obj1 ^ !e_obj2) return EINA_TRUE;
+ Eina_List *itr1 = e_obj1->children;
+ Eina_List *itr2 = e_obj2->children;
+ if (check_objs &&
+ (strcmp(e_obj1->kl_name, e_obj2->kl_name) ||
+ e_obj1->x != e_obj2->x || e_obj1->y != e_obj2->y ||
+ e_obj1->w != e_obj2->w || e_obj1->h != e_obj2->h)) return EINA_TRUE;
+ while (itr1 || itr2)
+ {
+ if ((!itr1) ^ (!itr2)) return EINA_TRUE;
+ e_obj1 = eina_list_data_get(itr1);
+ e_obj2 = eina_list_data_get(itr2);
+
+ if (_are_objs_different(e_obj1, e_obj2, EINA_TRUE)) return EINA_TRUE;
+
+ itr1 = eina_list_next(itr1);
+ itr2 = eina_list_next(itr2);
+ }
+ return EINA_FALSE;
+}
+
+static Eina_Bool
+_are_objs_trees_different(Exactness_Objects *e_objs1, Exactness_Objects *e_objs2)
+{
+ if (!e_objs1 ^ !e_objs2) return EINA_TRUE;
+ Eina_List *itr1 = e_objs1->objs;
+ Eina_List *itr2 = e_objs2->objs;
+ Exactness_Object *e_obj1, *e_obj2;
+ while (itr1 || itr2)
+ {
+ if ((!itr1) ^ (!itr2)) return EINA_TRUE;
+ e_obj1 = eina_list_data_get(itr1);
+ e_obj2 = eina_list_data_get(itr2);
+
+ if (_are_objs_different(e_obj1, e_obj2, EINA_TRUE)) return EINA_TRUE;
+
+ itr1 = eina_list_next(itr1);
+ itr2 = eina_list_next(itr2);
+ }
+ return EINA_FALSE;
+}
+
+static void
+_win_del(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
+{
+ efl_exit(0); /* exit the program's main loop that runs in elm_run() */
+}
+
+static void
+_gui_win_create()
+{
+ Eo *win, *bg;
+
+ elm_policy_set(ELM_POLICY_QUIT, ELM_POLICY_QUIT_LAST_WINDOW_CLOSED);
+ win = elm_win_add(NULL, "Window", ELM_WIN_BASIC);
+ evas_object_smart_callback_add(win, "delete,request", _win_del, NULL);
+ elm_win_maximized_set(win, EINA_TRUE);
+ elm_win_autodel_set(win, EINA_TRUE);
+ elm_win_title_set(win, "Exactness Inspector");
+ efl_gfx_entity_size_set(win, EINA_SIZE2D(1000, 800));
+
+ bg = elm_bg_add(win);
+ evas_object_size_hint_weight_set(bg, 1.000000, 1.000000);
+ efl_gfx_entity_visible_set(bg, EINA_TRUE);
+ elm_win_resize_object_add(win, bg);
+
+ _main_box = elm_box_add(win);
+ elm_box_horizontal_set(_main_box, EINA_TRUE);
+ elm_box_homogeneous_set(_main_box, EINA_TRUE);
+ evas_object_size_hint_weight_set(_main_box, 1.000000, 1.000000);
+ efl_gfx_entity_visible_set(_main_box, EINA_TRUE);
+ elm_win_resize_object_add(win, _main_box);
+
+ efl_gfx_entity_visible_set(win, EINA_TRUE);
+}
+
+static char *
+_grp_text_get(void *data, Evas_Object *gl, const char *part EINA_UNUSED)
+{
+ char buf[256];
+ const char *str = NULL;
+ Eina_Bool compare = !!efl_key_data_get(gl, "_exactness_gl_compare");
+ _Data_Type dt = (_Data_Type) data;
+ switch (dt)
+ {
+ case EX_FONTS_DIR:
+ {
+ char buf2[256];
+ if (!compare)
+ {
+ Exactness_Unit *unit = efl_key_data_get(gl, "unit");
+ sprintf(buf2, "Fonts directory: %s", unit->fonts_path?unit->fonts_path:"None");
+ }
+ else
+ {
+ Eo *gl1 = eina_list_nth(_gls, 0);
+ Eo *gl2 = eina_list_nth(_gls, 1);
+ Exactness_Unit *unit1 = efl_key_data_get(gl1, "unit");
+ Exactness_Unit *unit2 = efl_key_data_get(gl2, "unit");
+ if (!!unit1->fonts_path ^ !!unit2->fonts_path)
+ sprintf(buf2, "Fonts directory comparison: XXXXX");
+ else if (!strcmp(unit1->fonts_path, unit2->fonts_path))
+ sprintf(buf2, "Fonts directory comparison: %s", unit1->fonts_path);
+ else
+ sprintf(buf2, "Fonts directory comparison: "LDIFF(%s)"/"RDIFF(%s),
+ unit1->fonts_path, unit2->fonts_path);
+ }
+ return strdup(buf2);
+ }
+ case EX_SCENARIO: { str = "Scenario"; break; }
+ case EX_IMAGE: { str = "Images"; break; }
+ case EX_OBJ_INFO: { str = "Objects"; break; }
+ default: { str = "Unknown"; break; }
+ }
+ sprintf(buf, "%s%s", str, compare ? " comparison" : "");
+ if (dt == EX_FONTS_DIR) eina_stringshare_del(str);
+ return strdup(buf);
+}
+
+static char *
+_scn_text_get(void *data, Evas_Object *gl, const char *part EINA_UNUSED)
+{
+ Eina_Strbuf *buf = eina_strbuf_new();
+ char *ret = NULL;
+ Eina_Bool compare = !!efl_key_data_get(gl, "_exactness_gl_compare");
+ if (compare)
+ {
+ _Compare_Item_Data *vv = data;
+ Exactness_Action *a1 = vv->p1;
+ Exactness_Action *a2 = vv->p2;
+
+ if (!a1 ^ !a2) return strdup("XXXXX");
+
+ if (a1->delay_ms != a2->delay_ms) eina_strbuf_append_printf(buf, "[+"LDIFF(%.3f)"/+"RDIFF(%.3f)"]: ", a1->delay_ms/1000.0, a2->delay_ms/1000.0);
+ else eina_strbuf_append_printf(buf, "+%.3f: ", a1->delay_ms / 1000.0);
+
+ if (a1->type != a2->type)
+ eina_strbuf_append_printf(buf, "["LDIFF(%s)"/"RDIFF(%s)"] - XXXXXX", _action_name_get(a1), _action_name_get(a2));
+ else
+ {
+ char params1[1024];
+ char params2[2024];
+ _action_specific_info_get(a1, params1);
+ _action_specific_info_get(a2, params2);
+
+ eina_strbuf_append_printf(buf, "%s", _action_name_get(a1));
+ if (*params1 || *params2)
+ {
+ if (strcmp(params1, params2))
+ eina_strbuf_append_printf(buf, " - ["LDIFF(%s)"/"RDIFF(%s)"]", params1, params2);
+ else
+ eina_strbuf_append_printf(buf, " - %s", params1);
+ }
+ }
+ }
+ else
+ {
+ Exactness_Action *act = data;
+ char specific_output[1024];
+ if (act)
+ {
+ eina_strbuf_append_printf(buf, "+%.3f: ", act->delay_ms / 1000.0);
+ eina_strbuf_append_printf(buf, "%s", _action_name_get(act));
+ _action_specific_info_get(act, specific_output);
+ if (*specific_output) eina_strbuf_append_printf(buf, " - %s", specific_output);
+ }
+ else
+ eina_strbuf_append(buf, "XXXXX");
+ }
+
+ ret = eina_strbuf_string_steal(buf);
+ eina_strbuf_free(buf);
+ return ret;
+}
+
+static int
+_unit_shot_no_get(Exactness_Unit *unit, Exactness_Action *act_ref)
+{
+ Eina_List *itr;
+ Exactness_Action *act;
+ int ret = 0;
+ if (!unit) return -1;
+ EINA_LIST_FOREACH(unit->actions, itr, act)
+ {
+ if (act->type == EXACTNESS_ACTION_TAKE_SHOT)
+ {
+ if (act == act_ref) return ret;
+ ret++;
+ }
+ }
+ return -1;
+}
+
+static void
+_goto_shot(void *data EINA_UNUSED, Evas_Object *bt, void *event_info EINA_UNUSED)
+{
+ Eo *gl = efl_key_data_get(bt, "gl");
+ Eina_Bool compare = !!efl_key_data_get(gl, "_exactness_gl_compare");
+ if (compare)
+ {
+ _Compare_Item_Data *vv;
+ Eina_List *itr;
+ Eo *gl1 = eina_list_nth(_gls, 0);
+ Eo *gl2 = eina_list_nth(_gls, 1);
+ Exactness_Unit *unit1 = efl_key_data_get(gl1, "unit");
+ Exactness_Unit *unit2 = efl_key_data_get(gl2, "unit");
+ int shot1_no = (intptr_t)efl_key_data_get(bt, "shot1_no");
+ int shot2_no = (intptr_t)efl_key_data_get(bt, "shot2_no");
+ Exactness_Image *ex_img1 = shot1_no != -1 ? eina_list_nth(unit1->imgs, shot1_no) : NULL;
+ Exactness_Image *ex_img2 = shot2_no != -1 ? eina_list_nth(unit2->imgs, shot2_no) : NULL;
+ EINA_LIST_FOREACH(_comp_vvs, itr, vv)
+ {
+ if (vv->p1 == ex_img1 && vv->p2 == ex_img2)
+ {
+ _Item_Info *ii = eina_hash_find(_item_infos_hash, &vv);
+ if (ii && ii->gl_item)
+ elm_genlist_item_show(ii->gl_item, ELM_GENLIST_ITEM_SCROLLTO_MIDDLE);
+ }
+ }
+ }
+ else
+ {
+ Exactness_Unit *unit = efl_key_data_get(gl, "unit");
+ int shot_no = (intptr_t)efl_key_data_get(bt, "shot_no");
+ Exactness_Image *ex_img = shot_no != -1 ? eina_list_nth(unit->imgs, shot_no) : NULL;
+ _Item_Info *ii = eina_hash_find(_item_infos_hash, &ex_img);
+ if (ii && ii->gl_item)
+ elm_genlist_item_show(ii->gl_item, ELM_GENLIST_ITEM_SCROLLTO_MIDDLE);
+ }
+}
+
+static Evas_Object *
+_scn_content_get(void *data, Evas_Object *gl, const char *part)
+{
+ Eina_Bool compare = !!efl_key_data_get(gl, "_exactness_gl_compare");
+ if (compare)
+ {
+ if (!strcmp(part, "elm.swallow.end"))
+ {
+ _Compare_Item_Data *vv = data;
+ Exactness_Action *v1 = vv->p1;
+ Exactness_Action *v2 = vv->p2;
+ if (v1 && v2 && v1->type == EXACTNESS_ACTION_TAKE_SHOT &&
+ v2->type == EXACTNESS_ACTION_TAKE_SHOT)
+ {
+ Eo *gl1 = eina_list_nth(_gls, 0);
+ Eo *gl2 = eina_list_nth(_gls, 1);
+ Exactness_Unit *unit1 = efl_key_data_get(gl1, "unit");
+ Exactness_Unit *unit2 = efl_key_data_get(gl2, "unit");
+ int shot1_no = _unit_shot_no_get(unit1, v1);
+ int shot2_no = _unit_shot_no_get(unit2, v2);
+ Exactness_Image *ex_img1 = shot1_no != -1 ? eina_list_nth(unit1->imgs, shot1_no) : NULL;
+ Exactness_Image *ex_img2 = shot2_no != -1 ? eina_list_nth(unit2->imgs, shot2_no) : NULL;
+ Exactness_Image *ex_imgO = NULL;
+ exactness_image_compare(ex_img1, ex_img2, &ex_imgO);
+
+ if (ex_imgO)
+ {
+ Eo *bt, *ic, *evas_img;
+
+ bt = elm_button_add(gl);
+ evas_object_size_hint_weight_set(bt, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+ evas_object_size_hint_align_set(bt, EVAS_HINT_FILL, EVAS_HINT_FILL);
+ evas_object_show(bt);
+ efl_key_data_set(bt, "gl", gl);
+ efl_key_data_set(bt, "shot1_no", (void *)(intptr_t)shot1_no);
+ efl_key_data_set(bt, "shot2_no", (void *)(intptr_t)shot2_no);
+ evas_object_smart_callback_add(bt, "clicked", _goto_shot, NULL);
+
+ ic = elm_icon_add(bt);
+ evas_img = elm_image_object_get(ic);
+ evas_object_image_size_set(evas_img, ex_imgO->w, ex_imgO->h);
+ evas_object_image_data_set(evas_img, ex_imgO->pixels);
+ evas_object_show(ic);
+ elm_object_part_content_set(bt, "icon", ic);
+ return bt;
+ }
+ }
+ }
+ }
+ else
+ {
+ if (!strcmp(part, "elm.swallow.end"))
+ {
+ Exactness_Action *v = data;
+ Exactness_Unit *unit = efl_key_data_get(gl, "unit");
+ int shot_no = _unit_shot_no_get(unit, v);
+ Exactness_Image *ex_img = shot_no != -1 ? eina_list_nth(unit->imgs, shot_no) : NULL;
+
+ if (ex_img)
+ {
+ Eo *bt, *ic, *evas_img;
+
+ bt = elm_button_add(gl);
+ evas_object_size_hint_weight_set(bt, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+ evas_object_size_hint_align_set(bt, EVAS_HINT_FILL, EVAS_HINT_FILL);
+ evas_object_show(bt);
+ efl_key_data_set(bt, "gl", gl);
+ efl_key_data_set(bt, "shot_no", (void *)(intptr_t)shot_no);
+ evas_object_smart_callback_add(bt, "clicked", _goto_shot, NULL);
+
+ ic = elm_icon_add(bt);
+ evas_img = elm_image_object_get(ic);
+ evas_object_image_size_set(evas_img, ex_img->w, ex_img->h);
+ evas_object_image_data_set(evas_img, ex_img->pixels);
+ evas_object_show(ic);
+ elm_object_part_content_set(bt, "icon", ic);
+
+ return bt;
+ }
+ }
+ }
+ return NULL;
+}
+
+static Evas_Object *
+_img_content_get(void *data, Evas_Object *gl, const char *part)
+{
+ if (strcmp(part, "elm.swallow.content")) return NULL;
+ Eo *img = elm_image_add(gl);
+ Eo *evas_img = elm_image_object_get(img);
+ Eina_Bool compare = !!efl_key_data_get(gl, "_exactness_gl_compare");
+ if (compare)
+ {
+ _Compare_Item_Data *vv = data;
+ Exactness_Image *ex_img1 = vv->p1;
+ Exactness_Image *ex_img2 = vv->p2;
+ Exactness_Image *ex_imgO = NULL;
+ exactness_image_compare(ex_img1, ex_img2, &ex_imgO);
+
+ evas_object_image_size_set(evas_img, ex_imgO->w, ex_imgO->h);
+ evas_object_image_data_set(evas_img, ex_imgO->pixels);
+ evas_object_size_hint_min_set(img, ELM_SCALE_SIZE(300), ELM_SCALE_SIZE(300));
+ }
+ else
+ {
+ if (!data)
+ {
+ efl_del(img);
+ return NULL;
+ }
+ Exactness_Image *ex_img = data;
+ evas_object_image_size_set(evas_img, ex_img->w, ex_img->h);
+ evas_object_image_data_set(evas_img, ex_img->pixels);
+ evas_object_size_hint_min_set(img, ELM_SCALE_SIZE(300), ELM_SCALE_SIZE(300));
+ }
+ return img;
+}
+
+static char *
+_objs_text_get(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, const char *part EINA_UNUSED)
+{
+ return strdup("Shot");
+}
+
+static char *
+_obj_text_get(void *data, Evas_Object *gl, const char *part EINA_UNUSED)
+{
+ Eina_Strbuf *buf = eina_strbuf_new();
+ char *ret = NULL;
+ Eina_Bool compare = !!efl_key_data_get(gl, "_exactness_gl_compare");
+ if (compare)
+ {
+ _Compare_Item_Data *vv = data;
+ Exactness_Object *e_obj1 = vv->p1;
+ Exactness_Object *e_obj2 = vv->p2;
+ if ((!e_obj1 ^ !e_obj2) || strcmp(e_obj1->kl_name, e_obj2->kl_name))
+ eina_strbuf_append_printf(buf, "("LDIFF(%s)"/"RDIFF(%s)")",
+ e_obj1 ? e_obj1->kl_name : "XXXXX",
+ e_obj2 ? e_obj2->kl_name : "XXXXX");
+ else
+ eina_strbuf_append_printf(buf, "%s", e_obj1->kl_name);
+
+ eina_strbuf_append(buf, " x = ");
+ if ((!e_obj1 ^ !e_obj2) || e_obj1->x != e_obj2->x)
+ eina_strbuf_append_printf(buf, LDIFF(%d)"/"RDIFF(%d),
+ e_obj1 ? e_obj1->x : -1,
+ e_obj2 ? e_obj2->x : -1);
+ else
+ eina_strbuf_append_printf(buf, "%d", e_obj1->x);
+
+ eina_strbuf_append(buf, " y = ");
+ if ((!e_obj1 ^ !e_obj2) || e_obj1->y != e_obj2->y)
+ eina_strbuf_append_printf(buf, LDIFF(%d)"/"RDIFF(%d),
+ e_obj1 ? e_obj1->y : -1,
+ e_obj2 ? e_obj2->y : -1);
+ else
+ eina_strbuf_append_printf(buf, "%d", e_obj1->y);
+
+ eina_strbuf_append(buf, " w = ");
+ if ((!e_obj1 ^ !e_obj2) || e_obj1->w != e_obj2->w)
+ eina_strbuf_append_printf(buf, LDIFF(%d)"/"RDIFF(%d),
+ e_obj1 ? e_obj1->w : -1,
+ e_obj2 ? e_obj2->w : -1);
+ else
+ eina_strbuf_append_printf(buf, "%d", e_obj1->w);
+
+ eina_strbuf_append(buf, " h = ");
+ if ((!e_obj1 ^ !e_obj2) || e_obj1->h != e_obj2->h)
+ eina_strbuf_append_printf(buf, LDIFF(%d)"/"RDIFF(%d),
+ e_obj1 ? e_obj1->h : -1,
+ e_obj2 ? e_obj2->h : -1);
+ else
+ eina_strbuf_append_printf(buf, "%d", e_obj1->h);
+
+ if (e_obj1 && e_obj2 && _are_objs_different(e_obj1, e_obj2, EINA_FALSE))
+ eina_strbuf_append(buf, " - DIFF INSIDE");
+ }
+ else
+ {
+ Exactness_Object *e_obj = data;
+ eina_strbuf_append_printf(buf,
+ "%s: x = %d y = %d w = %d h = %d",
+ e_obj->kl_name,
+ e_obj->x, e_obj->y, e_obj->w, e_obj->h);
+ }
+
+ ret = eina_strbuf_string_steal(buf);
+ eina_strbuf_free(buf);
+ return ret;
+}
+
+static void
+_itc_init()
+{
+ if (!_grp_itc)
+ {
+ _grp_itc = elm_genlist_item_class_new();
+ _grp_itc->item_style = "group_index";
+ _grp_itc->func.text_get = _grp_text_get;
+ }
+
+ if (!_scn_itc)
+ {
+ _scn_itc = elm_genlist_item_class_new();
+ _scn_itc->item_style = "default_style";
+ _scn_itc->func.text_get = _scn_text_get;
+ _scn_itc->func.content_get = _scn_content_get;
+ }
+
+ if (!_img_itc)
+ {
+ _img_itc = elm_genlist_item_class_new();
+ _img_itc->item_style = "full";
+ _img_itc->func.content_get = _img_content_get;
+ }
+
+ if (!_objs_itc)
+ {
+ _objs_itc = elm_genlist_item_class_new();
+ _objs_itc->item_style = "default_style";
+ _objs_itc->func.text_get = _objs_text_get;
+ }
+
+ if (!_obj_itc)
+ {
+ _obj_itc = elm_genlist_item_class_new();
+ _obj_itc->item_style = "default_style";
+ _obj_itc->func.text_get = _obj_text_get;
+ }
+}
+
+static void
+_comp_gl_dragged_cb(Evas_Object *obj, void *data EINA_UNUSED)
+{
+ int x = 0, y = 0;
+ Eo *gl;
+ Eina_List *itr;
+ elm_interface_scrollable_content_pos_get(obj, &x, &y);
+ EINA_LIST_FOREACH(_gls, itr, gl)
+ {
+ if (gl != obj)
+ elm_interface_scrollable_content_pos_set(gl, x, y, EINA_FALSE);
+ }
+}
+
+static void
+_obj_item_realize(Exactness_Object *ex_obj)
+{
+ _Item_Info *ii = eina_hash_find(_item_infos_hash, &ex_obj);
+ if (!ii) return;
+ if (ii->gl_item) return;
+ _obj_item_realize(ii->ex_parent);
+ _Item_Info *iip = eina_hash_find(_item_infos_hash, &(ii->ex_parent));
+ if (iip->gl_item) elm_genlist_item_expanded_set(iip->gl_item, EINA_TRUE);
+}
+
+static void
+_gl_expand_request_cb(void *data EINA_UNUSED, Evas_Object *gl, void *event_info)
+{
+ Elm_Object_Item *glit = event_info;
+ Eina_Bool compare = !!efl_key_data_get(gl, "_exactness_gl_compare");
+ if (compare)
+ {
+ const Elm_Genlist_Item_Class *itc = elm_genlist_item_item_class_get(glit);
+ if (itc == _objs_itc)
+ {
+ _Compare_Item_Data *vv = elm_object_item_data_get(glit);
+ _Item_Info *ii = eina_hash_find(_item_infos_hash, &(vv->p1));
+ if (ii) elm_genlist_item_expanded_set(ii->gl_item, EINA_TRUE);
+ ii = eina_hash_find(_item_infos_hash, &(vv->p2));
+ if (ii) elm_genlist_item_expanded_set(ii->gl_item, EINA_TRUE);
+ }
+ else if (itc == _obj_itc)
+ {
+ _Compare_Item_Data *vv = elm_object_item_data_get(glit);
+ _Item_Info *ii = eina_hash_find(_item_infos_hash, &(vv->p1));
+ if (!ii || !ii->gl_item) _obj_item_realize(vv->p1);
+ if (!ii) ii = eina_hash_find(_item_infos_hash, &(vv->p1));
+ if (ii && ii->gl_item) elm_genlist_item_expanded_set(ii->gl_item, EINA_TRUE);
+
+ ii = eina_hash_find(_item_infos_hash, &(vv->p2));
+ if (!ii || !ii->gl_item) _obj_item_realize(vv->p2);
+ if (!ii) ii = eina_hash_find(_item_infos_hash, &(vv->p2));
+ if (ii && ii->gl_item) elm_genlist_item_expanded_set(ii->gl_item, EINA_TRUE);
+ }
+ }
+ elm_genlist_item_expanded_set(glit, EINA_TRUE);
+}
+
+static void
+_gl_contract_request_cb(void *data EINA_UNUSED, Evas_Object *gl EINA_UNUSED, void *event_info)
+{
+ Elm_Object_Item *glit = event_info;
+ Eina_Bool compare = !!efl_key_data_get(gl, "_exactness_gl_compare");
+ if (compare)
+ {
+ const Elm_Genlist_Item_Class *itc = elm_genlist_item_item_class_get(glit);
+ if (itc == _objs_itc)
+ {
+ _Compare_Item_Data *vv = elm_object_item_data_get(glit);
+ _Item_Info *ii = eina_hash_find(_item_infos_hash, &(vv->p1));
+ if (ii) elm_genlist_item_expanded_set(ii->gl_item, EINA_FALSE);
+ ii = eina_hash_find(_item_infos_hash, &(vv->p2));
+ if (ii) elm_genlist_item_expanded_set(ii->gl_item, EINA_FALSE);
+ }
+ else if (itc == _obj_itc)
+ {
+ _Compare_Item_Data *vv = elm_object_item_data_get(glit);
+ _Item_Info *ii = eina_hash_find(_item_infos_hash, &(vv->p1));
+ if (ii && ii->gl_item) elm_genlist_item_expanded_set(ii->gl_item, EINA_FALSE);
+
+ ii = eina_hash_find(_item_infos_hash, &(vv->p2));
+ if (ii && ii->gl_item) elm_genlist_item_expanded_set(ii->gl_item, EINA_FALSE);
+ }
+ }
+ elm_genlist_item_expanded_set(glit, EINA_FALSE);
+}
+
+static void
+_gl_expanded_cb(void *_data EINA_UNUSED, Evas_Object *gl EINA_UNUSED, void *event_info)
+{
+ Elm_Object_Item *glit = event_info;
+ const Elm_Genlist_Item_Class *itc = elm_genlist_item_item_class_get(glit);
+ Eina_Bool compare = !!efl_key_data_get(gl, "_exactness_gl_compare");
+ if (itc == _objs_itc)
+ {
+ if (compare)
+ {
+ _Compare_Item_Data *vv = elm_object_item_data_get(glit);
+ Exactness_Objects *e_objs1 = vv->p1;
+ Exactness_Objects *e_objs2 = vv->p2;
+ Eina_List *itr1 = e_objs1->main_objs, *itr2 = e_objs2->main_objs;
+
+ while (itr1 || itr2)
+ {
+ Exactness_Object *e_obj1 = eina_list_data_get(itr1);
+ Exactness_Object *e_obj2 = eina_list_data_get(itr2);
+ vv = calloc(1, sizeof(*vv));
+ vv->p1 = e_obj1;
+ vv->p2 = e_obj2;
+ vv->dt = EX_OBJ_INFO;
+ elm_genlist_item_append(gl, _obj_itc, vv, glit,
+ e_obj1->children || e_obj2->children ? ELM_GENLIST_ITEM_TREE : ELM_GENLIST_ITEM_NONE,
+ NULL, NULL);
+ itr1 = eina_list_next(itr1);
+ itr2 = eina_list_next(itr2);
+ }
+ }
+ else
+ {
+ Exactness_Objects *e_objs = elm_object_item_data_get(glit);
+ Eina_List *itr;
+ Exactness_Object *e_obj;
+ EINA_LIST_FOREACH(e_objs->main_objs, itr, e_obj)
+ {
+ _Item_Info *ii = eina_hash_find(_item_infos_hash, &e_obj);
+ if (!ii)
+ {
+ ii = calloc(1, sizeof(*ii));
+ eina_hash_set(_item_infos_hash, &e_obj, ii);
+ }
+ ii->ex_parent = e_objs;
+ ii->gl_item = elm_genlist_item_append(gl, _obj_itc, e_obj, glit,
+ e_obj->children ? ELM_GENLIST_ITEM_TREE : ELM_GENLIST_ITEM_NONE,
+ NULL, NULL);
+ efl_wref_add(ii->gl_item, &(ii->gl_item));
+ }
+ }
+ }
+ else if (itc == _obj_itc)
+ {
+ if (compare)
+ {
+ _Compare_Item_Data *vv = elm_object_item_data_get(glit);
+ Exactness_Object *e_obj1 = vv->p1;
+ Exactness_Object *e_obj2 = vv->p2;
+ Eina_List *itr1 = e_obj1->children, *itr2 = e_obj2->children;
+
+ while (itr1 || itr2)
+ {
+ e_obj1 = eina_list_data_get(itr1);
+ e_obj2 = eina_list_data_get(itr2);
+ vv = calloc(1, sizeof(*vv));
+ vv->p1 = e_obj1;
+ vv->p2 = e_obj2;
+ vv->dt = EX_OBJ_INFO;
+ elm_genlist_item_append(gl, _obj_itc, vv, glit,
+ (e_obj1 && e_obj1->children) || (e_obj2 && e_obj2->children) ?
+ ELM_GENLIST_ITEM_TREE : ELM_GENLIST_ITEM_NONE,
+ NULL, NULL);
+ itr1 = eina_list_next(itr1);
+ itr2 = eina_list_next(itr2);
+ }
+ }
+ else
+ {
+ Exactness_Object *e_obj = elm_object_item_data_get(glit), *e_obj2;
+ Eina_List *itr;
+
+ EINA_LIST_FOREACH(e_obj->children, itr, e_obj2)
+ {
+ _Item_Info *ii = eina_hash_find(_item_infos_hash, &e_obj2);
+ if (!ii)
+ {
+ ii = calloc(1, sizeof(*ii));
+ eina_hash_set(_item_infos_hash, &e_obj2, ii);
+ }
+ ii->ex_parent = e_obj;
+ ii->gl_item = elm_genlist_item_append(gl, _obj_itc, e_obj2, glit,
+ e_obj2->children ? ELM_GENLIST_ITEM_TREE : ELM_GENLIST_ITEM_NONE,
+ NULL, NULL);
+ efl_wref_add(ii->gl_item, &(ii->gl_item));
+ }
+ }
+ }
+}
+
+static void
+_gl_contracted_cb(void *data EINA_UNUSED, Evas_Object *gl EINA_UNUSED, void *event_info)
+{
+ Elm_Object_Item *glit = event_info;
+ elm_genlist_item_subitems_clear(glit);
+}
+
+static void
+_comp_gl_selected_cb(void *data EINA_UNUSED, Evas_Object *gl EINA_UNUSED, void *event_info)
+{
+ _comp_selected_item = event_info;
+ _Compare_Item_Data *vv = elm_object_item_data_get(_comp_selected_item);
+ if (vv->p1)
+ {
+ _Item_Info *ii = eina_hash_find(_item_infos_hash, &(vv->p1));
+ if (!ii || !ii->gl_item) _obj_item_realize(vv->p1);
+ elm_genlist_item_selected_set(ii->gl_item, EINA_TRUE);
+ }
+
+ if (vv->p2)
+ {
+ _Item_Info *ii = eina_hash_find(_item_infos_hash, &(vv->p2));
+ if (!ii || !ii->gl_item) _obj_item_realize(vv->p2);
+ elm_genlist_item_selected_set(ii->gl_item, EINA_TRUE);
+ }
+}
+
+static void
+_scn_item_remove(void *data, Evas_Object *menu EINA_UNUSED, void *item EINA_UNUSED)
+{
+ Eo *glit = data;
+ Exactness_Unit *unit = efl_key_data_get(efl_parent_get(glit), "unit");
+ Exactness_Action *act = elm_object_item_data_get(glit);
+ unit->actions = eina_list_remove(unit->actions, act);
+ if (!eina_list_data_find(_modified_units, unit))
+ _modified_units = eina_list_append(_modified_units, unit);
+ efl_del(glit);
+}
+
+static void
+_gl_clicked_right_cb(void *data, Evas_Object *gl, void *event_info)
+{
+ int x = 0, y = 0;
+ Eo *win = data, *menu;
+ Elm_Object_Item *glit = event_info;
+
+ if (elm_genlist_item_item_class_get(glit) == _scn_itc)
+ {
+ elm_genlist_item_selected_set(glit, EINA_TRUE);
+ evas_pointer_canvas_xy_get(evas_object_evas_get(gl), &x, &y);
+
+ menu = elm_menu_add(win);
+ elm_menu_move(menu, x, y);
+ elm_menu_item_add(menu, NULL, NULL, "Remove", _scn_item_remove, glit);
+ efl_gfx_entity_visible_set(menu, EINA_TRUE);
+ }
+}
+
+static void
+_gl_img_show(void *data, Evas_Object *obj, void *event_info EINA_UNUSED)
+{
+ static Eo *_img_win = NULL;
+ Exactness_Image *ex_img = data;
+ if (_img_win) efl_del(_img_win);
+ _img_win = efl_add(EFL_UI_WIN_CLASS, elm_win_get(obj),
+ efl_ui_win_type_set(efl_added, EFL_UI_WIN_TYPE_DIALOG_BASIC),
+ efl_ui_win_autodel_set(efl_added, EINA_TRUE));
+ efl_wref_add(_img_win, &_img_win);
+
+ Evas_Object *image = elm_image_add(_img_win);
+ Eo *evas_img = elm_image_object_get(image);
+ evas_object_image_size_set(evas_img, ex_img->w, ex_img->h);
+ evas_object_image_data_set(evas_img, ex_img->pixels);
+ efl_content_set(_img_win, image);
+
+ efl_gfx_entity_size_set(_img_win, EINA_SIZE2D(550, 500));
+}
+
+static void
+_gui_unit_display(Exactness_Unit *unit1, Exactness_Unit *unit2)
+{
+ Eina_List *itr1, *itr2;
+ Eo *gl1, *gl2 = NULL, *glc = NULL;
+
+ gl1 = elm_genlist_add(_main_box);
+ elm_genlist_homogeneous_set(gl1, EINA_TRUE);
+ evas_object_size_hint_weight_set(gl1, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+ evas_object_size_hint_align_set(gl1, EVAS_HINT_FILL, EVAS_HINT_FILL);
+ efl_gfx_entity_visible_set(gl1, EINA_TRUE);
+ _gls = eina_list_append(_gls, gl1);
+ elm_box_pack_end(_main_box, gl1);
+
+ efl_key_data_set(gl1, "unit", unit1);
+ evas_object_smart_callback_add(gl1, "expand,request", _gl_expand_request_cb, NULL);
+ evas_object_smart_callback_add(gl1, "contract,request", _gl_contract_request_cb, NULL);
+ evas_object_smart_callback_add(gl1, "expanded", _gl_expanded_cb, NULL);
+ evas_object_smart_callback_add(gl1, "contracted", _gl_contracted_cb, NULL);
+ if (!unit2)
+ evas_object_smart_callback_add(gl1, "clicked,right", _gl_clicked_right_cb, elm_win_get(_main_box));
+
+ if (unit2)
+ {
+ glc = elm_genlist_add(_main_box);
+ elm_genlist_homogeneous_set(glc, EINA_TRUE);
+ evas_object_size_hint_weight_set(glc, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+ evas_object_size_hint_align_set(glc, EVAS_HINT_FILL, EVAS_HINT_FILL);
+ efl_gfx_entity_visible_set(glc, EINA_TRUE);
+ elm_box_pack_end(_main_box, glc);
+
+ evas_object_smart_callback_add(glc, "expand,request", _gl_expand_request_cb, NULL);
+ evas_object_smart_callback_add(glc, "contract,request", _gl_contract_request_cb, NULL);
+ evas_object_smart_callback_add(glc, "expanded", _gl_expanded_cb, NULL);
+ evas_object_smart_callback_add(glc, "contracted", _gl_contracted_cb, NULL);
+
+ efl_key_data_set(glc, "_exactness_gl_compare", glc);
+ elm_interface_scrollable_scroll_down_cb_set(glc, _comp_gl_dragged_cb);
+ elm_interface_scrollable_scroll_up_cb_set(glc, _comp_gl_dragged_cb);
+ evas_object_smart_callback_add(glc, "selected", _comp_gl_selected_cb, NULL);
+
+ gl2 = elm_genlist_add(_main_box);
+ elm_genlist_homogeneous_set(gl2, EINA_TRUE);
+ evas_object_size_hint_weight_set(gl2, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+ evas_object_size_hint_align_set(gl2, EVAS_HINT_FILL, EVAS_HINT_FILL);
+ efl_gfx_entity_visible_set(gl2, EINA_TRUE);
+ _gls = eina_list_append(_gls, gl2);
+ elm_box_pack_end(_main_box, gl2);
+
+ efl_key_data_set(gl2, "unit", unit2);
+ evas_object_smart_callback_add(gl2, "expand,request", _gl_expand_request_cb, NULL);
+ evas_object_smart_callback_add(gl2, "contract,request", _gl_contract_request_cb, NULL);
+ evas_object_smart_callback_add(gl2, "expanded", _gl_expanded_cb, NULL);
+ evas_object_smart_callback_add(gl2, "contracted", _gl_contracted_cb, NULL);
+ }
+ _itc_init();
+
+ if (unit1->fonts_path || (unit2 && unit2->fonts_path))
+ {
+ if (!_show_only_diffs || !unit1 || !unit2 ||
+ !unit1->fonts_path || !unit2->fonts_path ||
+ strcmp(unit1->fonts_path, unit2->fonts_path))
+ {
+ elm_genlist_item_append(gl1, _grp_itc, (void *)EX_FONTS_DIR, NULL, ELM_GENLIST_ITEM_GROUP, NULL, NULL);
+ elm_genlist_item_append(gl2, _grp_itc, (void *)EX_FONTS_DIR, NULL, ELM_GENLIST_ITEM_GROUP, NULL, NULL);
+ elm_genlist_item_append(glc, _grp_itc, (void *)EX_FONTS_DIR, NULL, ELM_GENLIST_ITEM_GROUP, NULL, NULL);
+ }
+ }
+ itr1 = unit1 ? unit1->actions : NULL;
+ itr2 = unit2 ? unit2->actions : NULL;
+
+ if (itr1 || itr2)
+ {
+ elm_genlist_item_append(gl1, _grp_itc, (void *)EX_SCENARIO, NULL, ELM_GENLIST_ITEM_GROUP, NULL, NULL);
+ elm_genlist_item_append(gl2, _grp_itc, (void *)EX_SCENARIO, NULL, ELM_GENLIST_ITEM_GROUP, NULL, NULL);
+ elm_genlist_item_append(glc, _grp_itc, (void *)EX_SCENARIO, NULL, ELM_GENLIST_ITEM_GROUP, NULL, NULL);
+ }
+ while (itr1 || itr2)
+ {
+ Exactness_Action *v1 = itr1 ? eina_list_data_get(itr1) : NULL;
+ Exactness_Action *v2 = itr2 ? eina_list_data_get(itr2) : NULL;
+ if (!_show_only_diffs || _are_scenario_entries_different(v1, v2))
+ {
+ _Item_Info *ii = calloc(1, sizeof(*ii));
+ eina_hash_set(_item_infos_hash, &v1, ii);
+ ii->gl_item = elm_genlist_item_append(gl1, _scn_itc, v1, NULL, ELM_GENLIST_ITEM_NONE, NULL, NULL);
+ if (unit2)
+ {
+ _Compare_Item_Data *vv = calloc(1, sizeof(*vv));
+ vv->p1 = v1;
+ vv->p2 = v2;
+ vv->dt = EX_SCENARIO;
+ ii = calloc(1, sizeof(*ii));
+ eina_hash_set(_item_infos_hash, &v2, ii);
+ ii->gl_item = elm_genlist_item_append(gl2, _scn_itc, v2, NULL, ELM_GENLIST_ITEM_NONE, NULL, NULL);
+ elm_genlist_item_append(glc, _scn_itc, vv, NULL, ELM_GENLIST_ITEM_NONE, NULL, NULL);
+ }
+ }
+ if (itr1) itr1 = eina_list_next(itr1);
+ if (itr2) itr2 = eina_list_next(itr2);
+ }
+
+ itr1 = unit1 ? unit1->imgs : NULL;
+ itr2 = unit2 ? unit2->imgs : NULL;
+
+ if (itr1 || itr2)
+ {
+ elm_genlist_item_append(gl1, _grp_itc, (void *)EX_IMAGE, NULL, ELM_GENLIST_ITEM_GROUP, NULL, NULL);
+ elm_genlist_item_append(gl2, _grp_itc, (void *)EX_IMAGE, NULL, ELM_GENLIST_ITEM_GROUP, NULL, NULL);
+ elm_genlist_item_append(glc, _grp_itc, (void *)EX_IMAGE, NULL, ELM_GENLIST_ITEM_GROUP, NULL, NULL);
+ }
+ while (itr1 || itr2)
+ {
+ Exactness_Image *img1 = itr1 ? eina_list_data_get(itr1) : NULL;
+ Exactness_Image *img2 = itr2 ? eina_list_data_get(itr2) : NULL;
+ if (!_show_only_diffs || _are_images_different(img1, img2))
+ {
+ _Item_Info *ii = calloc(1, sizeof(*ii));
+ eina_hash_set(_item_infos_hash, &img1, ii);
+ ii->gl_item = elm_genlist_item_append(gl1, _img_itc, img1, NULL, ELM_GENLIST_ITEM_NONE, _gl_img_show, img1);
+ if (unit2)
+ {
+ _Compare_Item_Data *vv = calloc(1, sizeof(*vv));
+ vv->p1 = img1;
+ vv->p2 = img2;
+ vv->dt = EX_IMAGE;
+ ii = calloc(1, sizeof(*ii));
+ eina_hash_set(_item_infos_hash, &img2, ii);
+ ii->gl_item = elm_genlist_item_append(gl2, _img_itc, img2, NULL, ELM_GENLIST_ITEM_NONE, NULL, NULL);
+ /* This item info is needed to go to images from scenario shot entry */
+ ii = calloc(1, sizeof(*ii));
+ eina_hash_set(_item_infos_hash, &vv, ii);
+ ii->gl_item = elm_genlist_item_append(glc, _img_itc, vv, NULL, ELM_GENLIST_ITEM_NONE, NULL, NULL);
+ _comp_vvs = eina_list_append(_comp_vvs, vv);
+ }
+ }
+ if (itr1) itr1 = eina_list_next(itr1);
+ if (itr2) itr2 = eina_list_next(itr2);
+ }
+
+ itr1 = unit1 ? unit1->objs : NULL;
+ itr2 = unit2 ? unit2->objs : NULL;
+
+ if (itr1 || itr2)
+ {
+ elm_genlist_item_append(gl1, _grp_itc, (void *)EX_OBJ_INFO, NULL, ELM_GENLIST_ITEM_GROUP, NULL, NULL);
+ elm_genlist_item_append(gl2, _grp_itc, (void *)EX_OBJ_INFO, NULL, ELM_GENLIST_ITEM_GROUP, NULL, NULL);
+ elm_genlist_item_append(glc, _grp_itc, (void *)EX_OBJ_INFO, NULL, ELM_GENLIST_ITEM_GROUP, NULL, NULL);
+ }
+ while (itr1 || itr2)
+ {
+ Exactness_Objects *objs1 = itr1 ? eina_list_data_get(itr1) : NULL;
+ Exactness_Objects *objs2 = itr2 ? eina_list_data_get(itr2) : NULL;
+ if (!_show_only_diffs || _are_objs_trees_different(objs1, objs2))
+ {
+ _Item_Info *ii = calloc(1, sizeof(*ii));
+ eina_hash_set(_item_infos_hash, &objs1, ii);
+ ii->gl_item = elm_genlist_item_append(gl1, _objs_itc, objs1, NULL,
+ ELM_GENLIST_ITEM_TREE, NULL, NULL);
+ efl_wref_add(ii->gl_item, &(ii->gl_item));
+ if (unit2)
+ {
+ _Compare_Item_Data *vv = calloc(1, sizeof(*vv));
+ vv->p1 = objs1;
+ vv->p2 = objs2;
+ vv->dt = EX_OBJ_INFO;
+ ii = calloc(1, sizeof(*ii));
+ eina_hash_set(_item_infos_hash, &objs2, ii);
+ ii->gl_item = elm_genlist_item_append(gl2, _objs_itc, objs2, NULL,
+ ELM_GENLIST_ITEM_TREE, NULL, NULL);
+ efl_wref_add(ii->gl_item, &(ii->gl_item));
+ elm_genlist_item_append(glc, _objs_itc, vv, NULL, ELM_GENLIST_ITEM_TREE, NULL, NULL);
+ }
+ }
+ if (itr1) itr1 = eina_list_next(itr1);
+ if (itr2) itr2 = eina_list_next(itr2);
+ }
+}
+
+static void
+_diff_result_print(Exactness_Unit *unit1, Exactness_Unit *unit2)
+{
+ Eina_List *itr1, *itr2;
+
+ int nb_scenario = 0, nb_diff_scenario = 0;
+ int nb_image = 0, nb_diff_image = 0;
+ int nb_objtree= 0, nb_diff_objtree = 0;
+
+ itr1 = unit1 ? unit1->actions : NULL;
+ itr2 = unit2 ? unit2->actions : NULL;
+
+ while (itr1 || itr2)
+ {
+ Exactness_Action *v1 = itr1 ? eina_list_data_get(itr1) : NULL;
+ Exactness_Action *v2 = itr2 ? eina_list_data_get(itr2) : NULL;
+
+ nb_scenario++;
+ if (_are_scenario_entries_different(v1, v2))
+ nb_diff_scenario++;
+
+ if (itr1) itr1 = eina_list_next(itr1);
+ if (itr2) itr2 = eina_list_next(itr2);
+ }
+
+ itr1 = unit1 ? unit1->imgs : NULL;
+ itr2 = unit2 ? unit2->imgs : NULL;
+
+ while (itr1 || itr2)
+ {
+ Exactness_Image *img1 = itr1 ? eina_list_data_get(itr1) : NULL;
+ Exactness_Image *img2 = itr2 ? eina_list_data_get(itr2) : NULL;
+
+ nb_image++;
+ if (_are_images_different(img1, img2))
+ nb_diff_image++;
+
+ if (itr1) itr1 = eina_list_next(itr1);
+ if (itr2) itr2 = eina_list_next(itr2);
+ }
+
+ itr1 = unit1 ? unit1->objs : NULL;
+ itr2 = unit2 ? unit2->objs : NULL;
+
+ while (itr1 || itr2)
+ {
+ Exactness_Objects *objs1 = itr1 ? eina_list_data_get(itr1) : NULL;
+ Exactness_Objects *objs2 = itr2 ? eina_list_data_get(itr2) : NULL;
+
+ nb_objtree++;
+ if (_are_objs_trees_different(objs1, objs2))
+ nb_diff_objtree++;
+
+ if (itr1) itr1 = eina_list_next(itr1);
+ if (itr2) itr2 = eina_list_next(itr2);
+ }
+
+ printf("%s\nscenario (%d/%d)\nimage (%d/%d)\nobjs_tree (%d/%d)\n",
+ nb_diff_scenario || nb_diff_image || nb_diff_objtree ?
+ "Failure" : "Success",
+ nb_scenario - nb_diff_scenario, nb_scenario,
+ nb_image - nb_diff_image, nb_image,
+ nb_objtree - nb_diff_objtree, nb_objtree);
+}
+
+static Exactness_Image *
+_image_read(const char *filename)
+{
+ int w, h;
+ Evas_Load_Error err;
+ Ecore_Evas *ee = ecore_evas_new(NULL, 0, 0, 100, 100, NULL);
+
+ /* the canvas pointer, de facto */
+ Eo *e = ecore_evas_get(ee);
+
+ Eo *img = evas_object_image_add(e);
+ evas_object_image_file_set(img, filename, NULL);
+ err = evas_object_image_load_error_get(img);
+ if (err != EVAS_LOAD_ERROR_NONE)
+ {
+ fprintf(stderr, "could not load image '%s'. error string is \"%s\"\n",
+ filename, evas_load_error_str(err));
+ return NULL;
+ }
+
+ Exactness_Image *ex_img = malloc(sizeof(*ex_img));
+ int len;
+ evas_object_image_size_get(img, &w, &h);
+ ex_img->w = w;
+ ex_img->h = h;
+ len = w * h * 4;
+ ex_img->pixels = malloc(len);
+ memcpy(ex_img->pixels, evas_object_image_data_get(img, EINA_FALSE), len);
+
+ ecore_evas_free(ee);
+ return ex_img;
+}
+
+static const Ecore_Getopt optdesc = {
+ "exactness_inspect",
+ "%prog [options] [<rec file> | <file1 file2>]",
+ NULL,
+ "(C) 2016 Enlightenment",
+ "BSD",
+ "Inspector for Exactness",
+ 0,
+ {
+ ECORE_GETOPT_STORE_USHORT('d', "delay", "Delay the given recording by a given time (in milliseconds)."),
+ ECORE_GETOPT_STORE_TRUE('c', "clean", "Clean the given recording from wrong actions."),
+ ECORE_GETOPT_STORE_TRUE('l', "list", "List the actions of the given recording."),
+ ECORE_GETOPT_STORE_TRUE('C', "compare", "Compare given files (images files or objects eet files)."),
+ ECORE_GETOPT_STORE_TRUE(0, "show-only-diffs", "Show only differences during comparison."),
+ ECORE_GETOPT_STORE_TRUE(0, "stabilize", "Stabilize after the given shot number in --shot."),
+ ECORE_GETOPT_STORE_TRUE(0, "pack", "Pack the given input files (scenario and images) into the given output."),
+ ECORE_GETOPT_STORE_STR('o', "output", "Output."),
+ ECORE_GETOPT_STORE_USHORT('s', "shot", "Select a specific shot (1 = 1st shot...)."),
+
+ ECORE_GETOPT_LICENSE('L', "license"),
+ ECORE_GETOPT_COPYRIGHT('C', "copyright"),
+ ECORE_GETOPT_VERSION('V', "version"),
+ ECORE_GETOPT_HELP('h', "help"),
+ ECORE_GETOPT_SENTINEL
+ }
+};
+
+int
+main(int argc, char *argv[])
+{
+ Eina_List *units_filenames = NULL;
+ const char *ext = NULL;
+ char *output = NULL;
+ Exactness_Unit *unit = NULL;
+ int ret = 1, args = 0;
+ unsigned short delay = 0, shot = 0;
+ Eina_Bool write_file = EINA_FALSE;
+ Eina_Bool want_quit, clean = EINA_FALSE, list_get = EINA_FALSE, compare_files = EINA_FALSE;
+ Eina_Bool stabilize = EINA_FALSE, show_only_diffs = EINA_FALSE, gui_needed = EINA_TRUE;
+ Eina_Bool pack = EINA_FALSE;
+
+ Ecore_Getopt_Value values[] = {
+ ECORE_GETOPT_VALUE_USHORT(delay),
+ ECORE_GETOPT_VALUE_BOOL(clean),
+ ECORE_GETOPT_VALUE_BOOL(list_get),
+ ECORE_GETOPT_VALUE_BOOL(compare_files),
+ ECORE_GETOPT_VALUE_BOOL(show_only_diffs),
+ ECORE_GETOPT_VALUE_BOOL(stabilize),
+ ECORE_GETOPT_VALUE_BOOL(pack),
+ ECORE_GETOPT_VALUE_STR(output),
+ ECORE_GETOPT_VALUE_USHORT(shot),
+
+ ECORE_GETOPT_VALUE_BOOL(want_quit),
+ ECORE_GETOPT_VALUE_BOOL(want_quit),
+ ECORE_GETOPT_VALUE_BOOL(want_quit),
+ ECORE_GETOPT_VALUE_BOOL(want_quit),
+ ECORE_GETOPT_VALUE_NONE
+ };
+
+ ecore_evas_init();
+ ecore_init();
+ eet_init();
+ elm_init(0, NULL);
+ want_quit = EINA_FALSE;
+
+ args = ecore_getopt_parse(&optdesc, values, argc, argv);
+ if (args < 0)
+ {
+ fprintf(stderr, "Failed parsing arguments.\n");
+ goto end;
+ }
+ if (want_quit)
+ {
+ goto end;
+ }
+ if ((clean || delay || shot || list_get || stabilize || pack) && args == argc)
+ {
+ fprintf(stderr, "Expected scenario (.rec/.exu) as the last argument.\n");
+ ecore_getopt_help(stderr, &optdesc);
+ goto end;
+ }
+ if (shot && (!delay && !stabilize))
+ {
+ fprintf(stderr, "shot option can only be used with delay or stabilize option.\n");
+ goto end;
+ }
+ if (delay && !shot)
+ {
+ fprintf(stderr, "delay option can only be used with shot option.\n");
+ goto end;
+ }
+ if (stabilize && !shot)
+ {
+ fprintf(stderr, "stabilize option can only be used with shot option.\n");
+ goto end;
+ }
+ if (compare_files && argc - args < 2)
+ {
+ fprintf(stderr, "Expected at least two files to compare as last arguments.\n");
+ ecore_getopt_help(stderr, &optdesc);
+ goto end;
+ }
+ if (show_only_diffs && !compare_files)
+ {
+ fprintf(stderr, "--show-only-diffs is available with --compare only\n");
+ goto end;
+ }
+ if (show_only_diffs && output)
+ {
+ fprintf(stderr, "--show-only-diffs works in GUI only\n");
+ goto end;
+ }
+ _show_only_diffs = show_only_diffs;
+
+ if (clean || delay || list_get || stabilize || pack)
+ {
+ int arg;
+ Eina_List *images = NULL;
+ gui_needed = EINA_FALSE;
+ for (arg = args; arg < argc; arg++)
+ {
+ const char *src_file = argv[arg];
+ ext = strrchr(src_file, '.');
+ if (!ext)
+ {
+ fprintf(stderr, "Extension required\n");
+ goto end;
+ }
+ if (!strcmp(ext, ".exu"))
+ {
+ if (!unit) unit = exactness_unit_file_read(src_file);
+ else
+ {
+ fprintf(stderr, "%s - scenario already provided\n", src_file);
+ goto end;
+ }
+ }
+ else if (!strcmp(ext, ".rec"))
+ {
+ if (!unit) unit = legacy_rec_file_read(src_file);
+ else
+ {
+ fprintf(stderr, "%s - scenario already provided\n", src_file);
+ goto end;
+ }
+ }
+ else if (!strcmp(ext, ".png"))
+ {
+ Exactness_Image *ex_img = _image_read(src_file);
+ if (!ex_img)
+ {
+ fprintf(stderr, "Issue while reading %s\n", src_file);
+ goto end;
+ }
+ images = eina_list_append(images, ex_img);
+ }
+ else
+ {
+ fprintf(stderr, "Correct extension (.exu/.rec/.png) required\n");
+ goto end;
+ }
+ }
+ if (unit)
+ {
+ Exactness_Image *ex_img;
+ EINA_LIST_FREE(images, ex_img)
+ {
+ unit->imgs = eina_list_append(unit->imgs, ex_img);
+ unit->nb_shots++;
+ }
+ }
+ }
+ else
+ {
+ int arg;
+ if (output) gui_needed = EINA_FALSE;
+ for (arg = args; arg < argc; arg++)
+ {
+ ext = strrchr(argv[arg], '.');
+ if (!ext)
+ {
+ fprintf(stderr, "Extension required\n");
+ goto end;
+ }
+ if (!strcmp(ext, ".exu"))
+ {
+ Exactness_Unit *ex_unit = exactness_unit_file_read(argv[arg]);
+ units_filenames = eina_list_append(units_filenames, argv[arg]);
+ _units = eina_list_append(_units, ex_unit);
+ }
+ else if (!strcmp(ext, ".rec"))
+ {
+ Exactness_Unit *ex_unit = legacy_rec_file_read(argv[arg]);
+ if (!ex_unit)
+ {
+ fprintf(stderr, "Issue while reading %s\n", argv[arg]);
+ goto end;
+ }
+ _units = eina_list_append(_units, ex_unit);
+ }
+ else if (!strcmp(ext, ".png"))
+ {
+ Exactness_Unit *ex_unit = calloc(1, sizeof(*ex_unit));
+ Exactness_Image *ex_img = _image_read(argv[arg]);
+ if (!ex_img)
+ {
+ fprintf(stderr, "Issue while reading %s\n", argv[arg]);
+ goto end;
+ }
+ ex_unit->imgs = eina_list_append(ex_unit->imgs, ex_img);
+ ex_unit->nb_shots++;
+ _units = eina_list_append(_units, ex_unit);
+ }
+ }
+ }
+
+ if (clean)
+ {
+ Exactness_Action *act;
+ Eina_List *itr, *itr2;
+ EINA_LIST_FOREACH_SAFE(unit->actions, itr, itr2, act)
+ {
+ Exactness_Action *prev_act = eina_list_data_get(eina_list_prev(itr));
+ if (_is_hook_duplicate(act, prev_act))
+ {
+ prev_act->delay_ms += act->delay_ms;
+ unit->actions = eina_list_remove_list(unit->actions, itr);
+ }
+ }
+ EINA_LIST_REVERSE_FOREACH_SAFE(unit->actions, itr, itr2, act)
+ {
+ if (act->type == EXACTNESS_ACTION_TAKE_SHOT) break;
+ unit->actions = eina_list_remove(unit->actions, act);
+ }
+ write_file = EINA_TRUE;
+ }
+
+ if (delay || stabilize)
+ {
+ Exactness_Action *act;
+ Eina_List *itr;
+ unsigned int cur_shot = 0;
+ EINA_LIST_FOREACH(unit->actions, itr, act)
+ {
+ if (act->type == EXACTNESS_ACTION_TAKE_SHOT)
+ {
+ cur_shot++;
+ if (cur_shot == shot)
+ {
+ if (delay) act->delay_ms = delay;
+ if (stabilize)
+ {
+ Exactness_Action *s_act = malloc(sizeof(*s_act));
+ s_act->type = EXACTNESS_ACTION_STABILIZE;
+ s_act->delay_ms = act->delay_ms;
+ s_act->n_evas = act->n_evas;
+ s_act->data = NULL;
+ act->delay_ms = 0; /* Shot right after stabilization */
+ unit->actions = eina_list_prepend_relative(unit->actions, s_act, act);
+ }
+ write_file = EINA_TRUE;
+ break;
+ }
+ }
+ }
+ }
+
+ if (pack) write_file = EINA_TRUE;
+
+ if (list_get)
+ {
+ Exactness_Action *act;
+ Eina_List *itr;
+ if (unit->fonts_path) printf("Fonts dir: %s\n", unit->fonts_path);
+ EINA_LIST_FOREACH(unit->actions, itr, act)
+ {
+ char specific_output[1024];
+ printf("+%.3f: %s", act->delay_ms / 1000.0, _action_name_get(act));
+ _action_specific_info_get(act, specific_output);
+ if (*specific_output) printf(" - %s", specific_output);
+ printf("\n");
+ }
+ }
+
+ if (compare_files && output)
+ {
+ const char *out_ext = strrchr(output, '.');
+ Exactness_Unit *unit1 = NULL, *unit2 = NULL, *unitO = NULL;
+ int nb_diffs = 0;
+ Eina_List *itr1, *itr2;
+ EINA_LIST_FOREACH(_units, itr1, unit)
+ {
+ if (!unit1) unit1 = unit;
+ else if (!unit2) unit2 = unit;
+ else
+ {
+ fprintf(stderr, "Too much files to compare (only 2).\n");
+ goto end;
+ }
+ }
+
+ if (!strcmp(out_ext, ".png"))
+ {
+ if (unit1->nb_shots != 1 || unit2->nb_shots != 1)
+ {
+ fprintf(stderr, "Comparison output can be png only if the number of shots to compare is 1.\n");
+ goto end;
+ }
+ }
+
+ itr1 = unit1 ? unit1->imgs : NULL;
+ itr2 = unit2 ? unit2->imgs : NULL;
+
+ while (itr1 || itr2)
+ {
+ Exactness_Image *ex_img1 = itr1 ? eina_list_data_get(itr1) : NULL;
+ Exactness_Image *ex_img2 = itr2 ? eina_list_data_get(itr2) : NULL;
+ Exactness_Image *ex_imgO = NULL;
+ Eina_Bool has_diff = exactness_image_compare(ex_img1, ex_img2, &ex_imgO);
+ if (has_diff || !strcmp(out_ext, ".exu"))
+ {
+ if (has_diff) nb_diffs++;
+ if (!unitO) unitO = calloc(1, sizeof(*unitO));
+ unitO->imgs = eina_list_append(unitO->imgs, ex_imgO);
+ unitO->nb_shots++;
+ }
+ itr1 = eina_list_next(itr1);
+ itr2 = eina_list_next(itr2);
+ }
+ if (!strcmp(out_ext, ".png"))
+ {
+ Ecore_Evas *ee;
+ Eo *e, *img;
+ if (unitO->nb_shots == 1)
+ {
+ Exactness_Image *ex_imgO = eina_list_data_get(unitO->imgs);
+ ee = ecore_evas_new(NULL, 0, 0, 100, 100, NULL);
+ e = ecore_evas_get(ee);
+ img = evas_object_image_add(e);
+ evas_object_image_size_set(img, ex_imgO->w, ex_imgO->h);
+ evas_object_image_data_set(img, ex_imgO->pixels);
+ evas_object_image_save(img, output, NULL, NULL);
+ ecore_evas_free(ee);
+ goto end;
+ }
+ ret = 0;
+ }
+ else if (!strcmp(out_ext, ".exu"))
+ {
+ _diff_result_print(unit1, unit2);
+ if (nb_diffs) exactness_unit_file_write(unitO, output);
+ else ret = 0;
+ }
+ else
+ {
+ fprintf(stderr, "Correct output extension (.exu/.png) required\n");
+ }
+ goto end;
+ }
+
+ ret = 0;
+ if (write_file)
+ {
+ if (!output)
+ {
+ fprintf(stderr, "An output file is required to write the modifications.\n");
+ }
+ else
+ {
+ const char *out_ext = strrchr(output, '.');
+ if (!out_ext || strcmp(out_ext, ".exu"))
+ {
+ fprintf(stderr, "Only exu extension is supported as output.\n");
+ goto end;
+ }
+ exactness_unit_file_write(unit, output);
+ }
+ goto end;
+ }
+
+ if (gui_needed)
+ {
+ Eina_List *itr;
+ Exactness_Unit *unit1 = NULL, *unit2 = NULL;
+ Eina_Bool need_compare = compare_files && eina_list_count(_units) == 2;
+ _item_infos_hash = eina_hash_pointer_new(NULL);
+ _gui_win_create();
+ EINA_LIST_FOREACH(_units, itr, unit)
+ {
+ if (need_compare)
+ {
+ if (!unit1) unit1 = unit;
+ else unit2 = unit;
+ }
+ else _gui_unit_display(unit, NULL);
+ }
+ if (need_compare) _gui_unit_display(unit1, unit2);
+ elm_run();
+ EINA_LIST_FREE(_modified_units, unit)
+ {
+ int i = 0;
+ EINA_LIST_FOREACH(_units, itr, unit2)
+ {
+ if (unit2 == unit) break;
+ i++;
+ }
+ exactness_unit_file_write(unit, eina_list_nth(units_filenames, i));
+ }
+ }
+
+end:
+ elm_shutdown();
+ eet_shutdown();
+ ecore_shutdown();
+ ecore_evas_shutdown();
+
+ return ret;
+}
diff --git a/src/bin/exactness/meson.build b/src/bin/exactness/meson.build
new file mode 100644
index 0000000000..6303e3fffe
--- /dev/null
+++ b/src/bin/exactness/meson.build
@@ -0,0 +1,42 @@
+exactness_bin = executable('exactness',
+ [ 'exactness.c' ],
+ dependencies: [ ecore, ecore_evas, ecore_file, exactness ],
+ install: true,
+ )
+
+exactness_inject_bin = executable('exactness_inject',
+ [ 'injector.c' ],
+ dependencies: [ elementary, exactness ],
+ install: true,
+ )
+
+exactness_inspect_bin = executable('exactness_inspect',
+ [ 'inspect.c' ],
+ dependencies: [ elementary, exactness ],
+ install: true,
+ )
+
+edjs = custom_target('player_entry',
+ input : 'player_entry.edc',
+ output : 'player_entry.edj',
+ install : true,
+ install_dir : 'share/exactness',
+ command : edje_cc_exe + [
+ '-id', join_paths(meson.source_root(), 'data', 'elementary', 'themes', 'img'),
+ '-sd', join_paths(meson.source_root(), 'data', 'elementary', 'themes', 'snd'),
+ '@INPUT@', '@OUTPUT@'],
+ depends : edje_cc)
+
+exactness_play_bin = executable('exactness_play',
+ [ 'player.c', edjs ],
+ dependencies: [ elementary, exactness ],
+ c_args: '-DDATA_DIR="'+join_paths(dir_data, 'exactness')+'"',
+ install: true,
+ )
+
+exactness_record_bin = executable('exactness_record',
+ [ 'recorder.c' ],
+ dependencies: [ elementary, exactness ],
+ install: true,
+ )
+
diff --git a/src/bin/exactness/player.c b/src/bin/exactness/player.c
new file mode 100644
index 0000000000..a2700f4653
--- /dev/null
+++ b/src/bin/exactness/player.c
@@ -0,0 +1,1393 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#define _POSIX_
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <unistd.h>
+
+#ifdef HAVE_FORK
+# ifdef HAVE_SYS_WAIT_H
+# include <sys/wait.h>
+# endif
+# ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+# endif
+# ifdef HAVE_SYS_SYSINFO_H
+# include <sys/sysinfo.h>
+# endif
+#endif
+
+#ifndef EFL_EO_API_SUPPORT
+#define EFL_EO_API_SUPPORT
+#endif
+#include <Eina.h>
+#include <Eo.h>
+#include <Evas.h>
+#include <Ecore.h>
+#include <Ecore_Getopt.h>
+#include <Ecore_File.h>
+#include <Ecore_Con.h>
+#include <Elementary.h>
+#include <Exactness.h>
+
+#include "exactness_private.h"
+
+#define PATH_ 1024
+#define IMAGE_FILENAME_EXT ".png"
+#define PAUSE_KEY_STR "F2"
+
+typedef struct
+{
+ Eina_Debug_Session *session;
+ int srcid;
+ void *buffer;
+ unsigned int size;
+} _Main_Loop_Info;
+
+#define WRAPPER_TO_XFER_MAIN_LOOP(foo) \
+static void \
+_intern_main_loop ## foo(void *data) \
+{ \
+ _Main_Loop_Info *info = data; \
+ _main_loop ## foo(info->session, info->srcid, info->buffer, info->size); \
+ free(info->buffer); \
+ free(info); \
+} \
+static Eina_Bool \
+foo(Eina_Debug_Session *session, int srcid, void *buffer, int size) \
+{ \
+ _Main_Loop_Info *info = calloc(1, sizeof(*info)); \
+ info->session = session; \
+ info->srcid = srcid; \
+ info->size = size; \
+ if (info->size) \
+ { \
+ info->buffer = malloc(info->size); \
+ memcpy(info->buffer, buffer, info->size); \
+ } \
+ ecore_main_loop_thread_safe_call_async(_intern_main_loop ## foo, info); \
+ return EINA_TRUE; \
+}
+
+#ifndef WORDS_BIGENDIAN
+#define SWAP_64(x) x
+#define SWAP_32(x) x
+#define SWAP_16(x) x
+#define SWAP_DBL(x) x
+#else
+#define SWAP_64(x) eina_swap64(x)
+#define SWAP_32(x) eina_swap32(x)
+#define SWAP_16(x) eina_swap16(x)
+#define SWAP_DBL(x) SWAP_64(x)
+#endif
+
+#define EXTRACT_INT(_buf) \
+({ \
+ int __i; \
+ memcpy(&__i, _buf, sizeof(int)); \
+ _buf += sizeof(int); \
+ SWAP_32(__i); \
+})
+
+#define EXTRACT_DOUBLE(_buf) \
+({ \
+ double __d; \
+ memcpy(&__d, _buf, sizeof(double)); \
+ _buf += sizeof(double); \
+ SWAP_DBL(__d); \
+})
+
+#define EXTRACT_STRING(_buf) \
+({ \
+ char *__s = _buf ? strdup(_buf) : NULL; \
+ int __len = (__s ? strlen(__s) : 0) + 1; \
+ _buf += __len; \
+ __s; \
+})
+
+#define STORE_INT(_buf, __i) \
+({ \
+ int __si = SWAP_32(__i); \
+ memcpy(_buf, &__si, sizeof(int)); \
+ _buf += sizeof(int); \
+})
+
+typedef enum
+{
+ FTYPE_UNKNOWN,
+ FTYPE_DIR,
+ FTYPE_REC = FTYPE_DIR,
+ FTYPE_EXU,
+ FTYPE_REMOTE
+} File_Type;
+
+static File_Type _dest_type = FTYPE_UNKNOWN;
+static Eina_Stringshare *_dest = NULL;
+static Exactness_Unit *_dest_unit = NULL;
+
+static File_Type _src_type = FTYPE_UNKNOWN;
+static Eina_Stringshare *_src_filename = NULL;
+static Exactness_Unit *_src_unit = NULL;
+
+static const char *_test_name = NULL;
+static int _verbose = 0;
+
+static Evas *(*_evas_new)(void) = NULL;
+static Eina_List *_evas_list = NULL;
+
+static Eina_List *_cur_event_list = NULL;
+
+static int _cur_shot_id = 0;
+static Eina_Bool _shot_needed = EINA_FALSE;
+static Eina_Bool _scan_objects = EINA_FALSE, _disable_shots = EINA_FALSE, _stabilize_shots = EINA_FALSE;
+
+static Eina_Debug_Session *_last_debug_session = NULL;
+static int _last_debug_src_cid = 0;
+static int _take_shot_op = EINA_DEBUG_OPCODE_INVALID;
+
+static Eina_Bool _stabilization_timer_cb(void *);
+static double _speed = 1.0;
+
+static Eina_Bool _exit_required = EINA_FALSE;
+static Eina_Bool _pause_request = EINA_FALSE;
+static Eina_Bool _playing_status = EINA_FALSE;
+
+static void
+_printf(int verbose, const char *fmt, ...)
+{
+ va_list ap;
+ if (!_verbose || verbose > _verbose) return;
+
+ va_start(ap, fmt);
+ vprintf(fmt, ap);
+ va_end(ap);
+}
+
+static Exactness_Image *
+_snapshot_shot_get(Evas *e)
+{
+ Exactness_Image *ex_img;
+ Evas_Object *snapshot;
+ void *pixels;
+ int w, h, nb_bytes;
+
+ if (!e) return NULL;
+
+ evas_output_size_get(e, &w, &h);
+ if ((w < 1) || (h < 1)) return NULL;
+
+ snapshot = efl_key_data_get(e, "_snapshot");
+ if (!snapshot)
+ {
+ snapshot = evas_object_image_filled_add(e);
+ if (snapshot)
+ {
+ evas_object_image_snapshot_set(snapshot, EINA_TRUE);
+ evas_object_geometry_set(snapshot, 0, 0, w, h);
+ efl_gfx_entity_visible_set(snapshot, EINA_TRUE);
+ efl_key_data_set(e, "_snapshot", snapshot);
+ }
+ return NULL;
+ }
+
+ pixels = evas_object_image_data_get(snapshot, EINA_FALSE);
+ if (!pixels) return NULL;
+
+ ex_img = malloc(sizeof(*ex_img));
+ nb_bytes = w * h * 4;
+ ex_img->w = w;
+ ex_img->h = h;
+ ex_img->pixels = malloc(nb_bytes);
+ memcpy(ex_img->pixels, pixels, nb_bytes);
+ return ex_img;
+}
+
+static void
+_evas_render_post_cb(void *data EINA_UNUSED, const Efl_Event *event)
+{
+ if (_shot_needed)
+ {
+ Evas_Event_Render_Post *post = event->info;
+ void *e_data = efl_key_data_get(event->object, "_shot");
+
+ // Nothing was updated, so let's not bother sending nothingness
+ if (post && !post->updated_area) return;
+ Exactness_Image *ex_shot = efl_key_data_get(event->object, "_last_shot");
+ if (!ex_shot) ex_shot = _snapshot_shot_get(event->object);
+ if (!ex_shot) return;
+
+ efl_key_data_set(event->object, "_last_shot", NULL);
+
+ if (e_data)
+ {
+ if (_dest_type == FTYPE_DIR)
+ {
+ char *filename = e_data;
+ Eo *o = evas_object_image_add(event->object);
+ evas_object_image_size_set(o, ex_shot->w, ex_shot->h);
+ evas_object_image_data_set(o, ex_shot->pixels);
+ _printf(1, "Shot taken (%s).\n", filename);
+ if (!evas_object_image_save(o, filename, NULL, NULL))
+ {
+ printf("Cannot save widget to <%s>\n", filename);
+ }
+ free(filename);
+ }
+ else if (_dest_type == FTYPE_EXU)
+ {
+ Exactness_Image *ex_img = e_data;
+ memcpy(ex_img, ex_shot, sizeof(Exactness_Image));
+ ex_shot->pixels = NULL;
+ _printf(1, "Shot taken (in %s).\n", _dest);
+ }
+ else if (_dest_type == FTYPE_REMOTE)
+ {
+ int len = sizeof(int) + sizeof(int) + ex_shot->w * ex_shot->h * 4;
+ char *buf = alloca(len);
+ char *tmp = buf;
+ STORE_INT(tmp, ex_shot->w);
+ STORE_INT(tmp, ex_shot->h);
+ memcpy(tmp, ex_shot->pixels, ex_shot->w * ex_shot->h * 4);
+ eina_debug_session_send(_last_debug_session, _last_debug_src_cid, _take_shot_op, buf, len);
+ }
+ }
+ exactness_image_free(ex_shot);
+ efl_key_data_set(event->object, "_shot", NULL);
+ evas_object_del(efl_key_data_get(event->object, "_snapshot"));
+ efl_key_data_set(event->object, "_snapshot", NULL);
+ /* This part is needed when the shot is needed at the end of the scenario.
+ * As it is async, we need to wait for the shot termination. */
+ _shot_needed = EINA_FALSE;
+ if (_exit_required) ecore_main_loop_quit();
+ }
+}
+
+static void
+_shot_do(Evas *e)
+{
+ void *e_data = NULL;
+ if (!e) return;
+
+ if (!_disable_shots)
+ {
+ if (_dest_type == FTYPE_DIR)
+ {
+ int dir_name_len;
+ char *filename;
+
+ dir_name_len = strlen(_dest) + 1; /* includes space of a '/' */
+ filename = malloc(strlen(_test_name) + strlen(IMAGE_FILENAME_EXT) +
+ dir_name_len + 8); /* also space for serial */
+
+ sprintf(filename, "%s/%s%c%03d%s", _dest, _test_name,
+ SHOT_DELIMITER, _cur_shot_id, IMAGE_FILENAME_EXT);
+ e_data = filename;
+ }
+ else if (_dest_type == FTYPE_EXU)
+ {
+ Exactness_Image *ex_img = malloc(sizeof(*ex_img));
+ _dest_unit->imgs = eina_list_append(_dest_unit->imgs, ex_img);
+ _dest_unit->nb_shots++;
+ e_data = ex_img;
+ }
+ else if (_dest_type == FTYPE_REMOTE)
+ {
+ e_data = e;
+ }
+ }
+ efl_key_data_set(e, "_shot", e_data);
+ _shot_needed = EINA_TRUE;
+ Efl_Event ev;
+ ev.info = NULL;
+ ev.object = e;
+ _evas_render_post_cb(NULL, &ev);
+
+ if (_scan_objects && _dest_type == FTYPE_EXU)
+ {
+ Eina_Iterator *iter;
+ Eo *obj;
+ Exactness_Objects *e_objs = calloc(1, sizeof(*e_objs));
+ iter = eo_objects_iterator_new();
+ EINA_ITERATOR_FOREACH(iter, obj)
+ {
+ if (!efl_isa(obj, EFL_CANVAS_OBJECT_CLASS) &&
+ !efl_isa(obj, EFL_CANVAS_SCENE_INTERFACE)) continue;
+ Exactness_Object *e_obj = calloc(1, sizeof(*e_obj));
+ Eo *parent = efl_parent_get(obj);
+ e_obj->id = (long long) obj;
+ if (efl_isa(parent, EFL_CANVAS_OBJECT_CLASS) ||
+ efl_isa(parent, EFL_CANVAS_SCENE_INTERFACE))
+ {
+ e_obj->parent_id = (long long) efl_parent_get(obj);
+ }
+ else
+ {
+ e_obj->parent_id = 0;
+ }
+ e_obj->kl_name = eina_stringshare_add(efl_class_name_get(obj));
+ if (efl_isa(obj, EFL_CANVAS_OBJECT_CLASS))
+ {
+ Eina_Size2D sz = efl_gfx_entity_size_get(obj);
+ e_obj->w = sz.w;
+ e_obj->h = sz.h;
+ Eina_Position2D pos = efl_gfx_entity_position_get(obj);
+ e_obj->x = pos.x;
+ e_obj->y = pos.y;
+ }
+ e_objs->objs = eina_list_append(e_objs->objs, e_obj);
+ }
+ eina_iterator_free(iter);
+ _dest_unit->objs = eina_list_append(_dest_unit->objs, e_objs);
+ }
+}
+
+static void
+_feed_event(Exactness_Action_Type type, unsigned int n_evas, void *data)
+{
+ static Evas_Object *rect = NULL;
+ static unsigned int rect_evas;
+
+ Eo *e = eina_list_nth(_evas_list, n_evas);
+
+ if (rect && rect_evas != n_evas)
+ {
+ efl_del(rect);
+ rect = NULL;
+ }
+ if (_verbose && !rect)
+ {
+ rect = evas_object_rectangle_add(e);
+ evas_object_repeat_events_set(rect, EINA_TRUE);
+ evas_object_color_set(rect, 255, 0, 0, 255);
+ evas_object_resize(rect, 15, 15);
+ evas_object_layer_set(rect, 100);
+ evas_object_show(rect);
+ rect_evas = n_evas;
+ }
+
+ switch (type)
+ {
+ case EXACTNESS_ACTION_MOUSE_IN:
+ {
+ _printf(1, "Mouse in\n");
+ _printf(2, "%s evas_event_feed_mouse_in n_evas=<%d>\n", __func__, n_evas);
+ if (e) evas_event_feed_mouse_in(e, time(NULL), NULL);
+ break;
+ }
+ case EXACTNESS_ACTION_MOUSE_OUT:
+ {
+ _printf(1, "Mouse out\n");
+ _printf(2, "%s evas_event_feed_mouse_out n_evas=<%d>\n", __func__, n_evas);
+ if (e) evas_event_feed_mouse_out(e, time(NULL), NULL);
+ break;
+ }
+ case EXACTNESS_ACTION_MOUSE_WHEEL:
+ {
+ Exactness_Action_Mouse_Wheel *t = data;
+ _printf(1, "Mouse wheel\n");
+ _printf(2, "%s evas_event_feed_mouse_wheel n_evas=<%d>\n", __func__, n_evas);
+ if (e) evas_event_feed_mouse_wheel(e, t->direction, t->z, time(NULL), NULL);
+
+ break;
+ }
+ case EXACTNESS_ACTION_MULTI_DOWN:
+ {
+ Exactness_Action_Multi_Event *t = data;
+ _printf(2, "%s evas_event_feed_multi_down n_evas=<%d>\n", __func__, n_evas);
+ if (!t->d)
+ {
+ if (e) evas_event_feed_mouse_down(e, t->b, t->flags, time(NULL), NULL);
+ if (rect) evas_object_color_set(rect, 255, 255, 0, 255);
+ }
+ else
+ {
+ if (e) evas_event_feed_multi_down(e,
+ t->d, t->x, t->y, t->rad,
+ t->radx, t->rady, t->pres, t->ang, t->fx, t->fy,
+ t->flags, time(NULL), NULL);
+ }
+
+ break;
+ }
+ case EXACTNESS_ACTION_MULTI_UP:
+ {
+ Exactness_Action_Multi_Event *t = data;
+ _printf(2, "%s evas_event_feed_multi_up n_evas=<%d>\n", __func__, n_evas);
+ if (!t->d)
+ {
+ if (e) evas_event_feed_mouse_up(e, t->b, t->flags, time(NULL), NULL);
+ if (rect) evas_object_color_set(rect, 255, 0, 0, 255);
+ }
+ else
+ {
+ if (e) evas_event_feed_multi_up(e,
+ t->d, t->x, t->y, t->rad,
+ t->radx, t->rady, t->pres, t->ang, t->fx, t->fy,
+ t->flags, time(NULL), NULL);
+ }
+
+ break;
+ }
+ case EXACTNESS_ACTION_MULTI_MOVE:
+ {
+ Exactness_Action_Multi_Move *t = data;
+ _printf(2, "%s evas_event_feed_multi_move n_evas=<%d>\n", __func__, n_evas);
+ if (!t->d)
+ {
+ if (e) evas_event_feed_mouse_move(e, t->x, t->y, time(NULL), NULL);
+ if (rect)
+ {
+ evas_object_move(rect, t->x, t->y);
+ evas_object_color_set(rect, 255, 0, 0, 255);
+ }
+ }
+ else
+ {
+ if (e) evas_event_feed_multi_move(e,
+ t->d, t->x, t->y, t->rad,
+ t->radx, t->rady, t->pres, t->ang, t->fx, t->fy,
+ time(NULL), NULL);
+ }
+
+ break;
+ }
+ case EXACTNESS_ACTION_KEY_DOWN:
+ {
+ Exactness_Action_Key_Down_Up *t = data;
+ _printf(2, "%s evas_event_feed_key_down n_evas=<%d>\n", __func__, n_evas);
+ if (e)
+ evas_event_feed_key_down_with_keycode(e,
+ t->keyname, t->key, t->string,
+ t->compose, time(NULL), NULL, t->keycode);
+ break;
+ }
+ case EXACTNESS_ACTION_KEY_UP:
+ {
+ Exactness_Action_Key_Down_Up *t = data;
+ _printf(2, "%s evas_event_feed_key_up n_evas=<%d>\n", __func__, n_evas);
+ if (e) evas_event_feed_key_up_with_keycode(e,
+ t->keyname, t->key, t->string,
+ t->compose, time(NULL), NULL, t->keycode);
+
+ break;
+ }
+ case EXACTNESS_ACTION_TAKE_SHOT:
+ {
+ _printf(2, "%s take shot n_evas=<%d>\n", __func__, n_evas);
+ if (rect) evas_object_color_set(rect, 0, 0, 255, 255);
+ _cur_shot_id++;
+ if (_dest_type != FTYPE_UNKNOWN && e) _shot_do(e);
+ break;
+ }
+ case EXACTNESS_ACTION_EFL_EVENT:
+ {
+ Exactness_Action_Efl_Event *t = data;
+ Eina_Bool found = EINA_FALSE;
+ Eina_List *itr;
+ EINA_LIST_FOREACH(_evas_list, itr, e)
+ {
+ Eo *o = efl_name_find(e, t->wdg_name);
+ if (o)
+ {
+ _printf(2, "%s EFL event invoke %s on %s\n",
+ __func__, t->event_name, t->wdg_name);
+ Efl_Event_Description d;
+ found = EINA_TRUE;
+ memset(&d, 0, sizeof(d));
+ d.name = t->event_name;
+ d.legacy_is = EINA_TRUE;
+ efl_event_callback_legacy_call(o, &d, NULL);
+#if 0
+ /* Remove when events stuff work well */
+ Eina_Size2D sz = efl_gfx_size_get(o);
+ Eina_Position2D pos = efl_gfx_position_get(o);
+ if (!strcmp(t->event_name, "clicked") ||
+ !strcmp(t->event_name, "clicked,double"))
+ {
+ int x = pos.x + (sz.w / 2);
+ int y = pos.y + (sz.h / 2);
+ evas_event_feed_mouse_move(e, x, y, time(NULL), NULL);
+ evas_event_feed_mouse_down(e, 0, EVAS_BUTTON_NONE, time(NULL), NULL);
+ evas_event_feed_mouse_up(e, 0, EVAS_BUTTON_NONE, time(NULL), NULL);
+ if (rect)
+ {
+ evas_object_move(rect, x, y);
+ evas_object_color_set(rect, 255, 0, 0, 255);
+ }
+ if (!strcmp(t->event_name, "clicked,double"))
+ {
+ evas_event_feed_mouse_down(e, 0, EVAS_BUTTON_DOUBLE_CLICK,
+ time(NULL), NULL);
+ evas_event_feed_mouse_up(e, 0, EVAS_BUTTON_DOUBLE_CLICK,
+ time(NULL), NULL);
+ }
+ }
+#endif
+ }
+ }
+ if (!found) fprintf(stderr, "Failed finding %s.\n", t->wdg_name);
+ break;
+ }
+ case EXACTNESS_ACTION_CLICK_ON:
+ {
+ Exactness_Action_Click_On *t = data;
+ Eina_List *itr;
+ Eo *o;
+ n_evas = 0;
+ EINA_LIST_FOREACH(_evas_list, itr, e)
+ {
+ o = efl_name_find(e, t->wdg_name);
+ if (o) goto wdg_found;
+ n_evas++;
+ }
+ o = NULL;
+wdg_found:
+ if (o)
+ {
+ Eina_Size2D sz = efl_gfx_entity_size_get(o);
+ Eina_Position2D pos = efl_gfx_entity_position_get(o);
+ int x = pos.x + (sz.w / 2);
+ int y = pos.y + (sz.h / 2);
+ Exactness_Action_Multi_Move *d_move = calloc(1, sizeof(*d_move));
+ Exactness_Action_Multi_Event *d_event = calloc(1, sizeof(*d_event));
+ Exactness_Action *act, *prev_act = eina_list_data_get(_cur_event_list);
+
+ _printf(2, "%s click on %s\n", __func__, t->wdg_name);
+ act = calloc(1, sizeof(*act));
+ act->type = EXACTNESS_ACTION_MULTI_MOVE;
+ act->delay_ms = 100;
+ act->n_evas = n_evas;
+ act->data = d_move;
+ d_move->x = x;
+ d_move->y = y;
+ _cur_event_list = eina_list_append_relative(_cur_event_list,
+ act, prev_act);
+ prev_act = act;
+
+ act = calloc(1, sizeof(*act));
+ act->type = EXACTNESS_ACTION_MULTI_DOWN;
+ act->delay_ms = 100;
+ act->n_evas = n_evas;
+ act->data = d_event;
+ d_event->b = 1;
+ _cur_event_list = eina_list_append_relative(_cur_event_list,
+ act, prev_act);
+ prev_act = act;
+
+ act = calloc(1, sizeof(*act));
+ act->type = EXACTNESS_ACTION_MULTI_UP;
+ act->delay_ms = 100;
+ act->n_evas = n_evas;
+ d_event = calloc(1, sizeof(*d_event));
+ act->data = d_event;
+ d_event->b = 1;
+ _cur_event_list = eina_list_append_relative(_cur_event_list,
+ act, prev_act);
+ }
+ else fprintf(stderr, "Failed finding %s.\n", t->wdg_name);
+ break;
+ }
+ case EXACTNESS_ACTION_STABILIZE:
+ {
+ _printf(2, "%s stabilize\n", __func__);
+ if (rect) evas_object_color_set(rect, 255, 165, 0, 255);
+ ecore_timer_add(0.1, _stabilization_timer_cb, NULL);
+ break;
+ }
+ default: /* All non-input events are not handeled */
+ break;
+ }
+}
+
+static Eina_Bool
+_feed_event_timer_cb(void *data EINA_UNUSED)
+{
+ if (_pause_request) return ECORE_CALLBACK_CANCEL;
+ Exactness_Action *act = eina_list_data_get(_cur_event_list);
+ if (act) _feed_event(act->type, act->n_evas, act->data);
+
+ _cur_event_list = eina_list_next(_cur_event_list);
+ if (!_cur_event_list)
+ { /* Finished reading all events */
+ _exit_required = EINA_TRUE;
+ if (!_shot_needed) ecore_main_loop_quit();
+ }
+ else
+ {
+ if (act->type != EXACTNESS_ACTION_STABILIZE)
+ {
+ act = eina_list_data_get(_cur_event_list);
+ _printf(2, " %s timer_time=<%f>\n", __func__, act->delay_ms / 1000.0);
+ ecore_timer_add(act->delay_ms / 1000.0, _feed_event_timer_cb, NULL);
+ }
+ }
+ return ECORE_CALLBACK_CANCEL;
+}
+
+static Eina_Bool
+_stabilization_timer_cb(void *data EINA_UNUSED)
+{
+ Eina_List *itr;
+ Evas *e;
+#define STAB_MAX 5
+ static int need_more = STAB_MAX;
+ _printf(2, "Not stable yet!\n");
+ EINA_LIST_FOREACH(_evas_list, itr, e)
+ {
+ if (!e) continue;
+ Exactness_Image *last_img = efl_key_data_get(e, "_last_stab_shot");
+ Exactness_Image *cur_img = _snapshot_shot_get(e);
+ if (!last_img || exactness_image_compare(last_img, cur_img, NULL)) need_more = STAB_MAX;
+ exactness_image_free(last_img);
+ efl_key_data_set(e, "_last_stab_shot", cur_img);
+ }
+ EINA_LIST_FOREACH(_evas_list, itr, e)
+ {
+ if (!need_more)
+ {
+ evas_object_del(efl_key_data_get(e, "_snapshot"));
+ efl_key_data_set(e, "_snapshot", NULL);
+ }
+ }
+ if (!need_more)
+ {
+ _playing_status = EINA_FALSE;
+ if (_src_type != FTYPE_REMOTE && !_pause_request)
+ {
+ Exactness_Action *act = eina_list_data_get(_cur_event_list);
+ _printf(2, " %s timer_time=<%f>\n", __func__, act->delay_ms / 1000.0);
+ ecore_timer_add(act->delay_ms / 1000.0, _feed_event_timer_cb, NULL);
+ }
+ need_more = STAB_MAX;
+ return ECORE_CALLBACK_CANCEL;
+ }
+ need_more--;
+ return ECORE_CALLBACK_RENEW;
+}
+
+static void
+_main_loop_mouse_in_cb(Eina_Debug_Session *session EINA_UNUSED, int srcid EINA_UNUSED, void *buffer, int size EINA_UNUSED)
+{
+ char *buf = buffer;
+ int n_evas = EXTRACT_INT(buf);
+ _feed_event(EXACTNESS_ACTION_MOUSE_IN, n_evas, NULL);
+}
+
+static void
+_main_loop_mouse_out_cb(Eina_Debug_Session *session EINA_UNUSED, int srcid EINA_UNUSED, void *buffer, int size EINA_UNUSED)
+{
+ char *buf = buffer;
+ int n_evas = EXTRACT_INT(buf);
+ _feed_event(EXACTNESS_ACTION_MOUSE_OUT, n_evas, NULL);
+}
+
+static void
+_main_loop_mouse_wheel_cb(Eina_Debug_Session *session EINA_UNUSED, int srcid EINA_UNUSED, void *buffer, int size EINA_UNUSED)
+{
+ char *buf = buffer;
+ Exactness_Action_Mouse_Wheel t;
+ int n_evas = EXTRACT_INT(buf);
+ t.direction = EXTRACT_INT(buf);
+ t.z = EXTRACT_INT(buf);
+ _feed_event(EXACTNESS_ACTION_MOUSE_WHEEL, n_evas, &t);
+}
+
+static void
+_main_loop_multi_down_cb(Eina_Debug_Session *session EINA_UNUSED, int srcid EINA_UNUSED, void *buffer, int size EINA_UNUSED)
+{
+ char *buf = buffer;
+ Exactness_Action_Multi_Event t;
+ int n_evas = EXTRACT_INT(buf);
+ t.d = EXTRACT_INT(buf);
+ t.b = EXTRACT_INT(buf);
+ t.x = EXTRACT_INT(buf);
+ t.y = EXTRACT_INT(buf);
+ t.rad = EXTRACT_DOUBLE(buf);
+ t.radx = EXTRACT_DOUBLE(buf);
+ t.rady = EXTRACT_DOUBLE(buf);
+ t.pres = EXTRACT_DOUBLE(buf);
+ t.ang = EXTRACT_DOUBLE(buf);
+ t.fx = EXTRACT_DOUBLE(buf);
+ t.fy = EXTRACT_DOUBLE(buf);
+ t.flags = EXTRACT_INT(buf);
+ _feed_event(EXACTNESS_ACTION_MULTI_DOWN, n_evas, &t);
+}
+
+static void
+_main_loop_multi_up_cb(Eina_Debug_Session *session EINA_UNUSED, int srcid EINA_UNUSED, void *buffer, int size EINA_UNUSED)
+{
+ char *buf = buffer;
+ Exactness_Action_Multi_Event t;
+ int n_evas = EXTRACT_INT(buf);
+ t.d = EXTRACT_INT(buf);
+ t.b = EXTRACT_INT(buf);
+ t.x = EXTRACT_INT(buf);
+ t.y = EXTRACT_INT(buf);
+ t.rad = EXTRACT_DOUBLE(buf);
+ t.radx = EXTRACT_DOUBLE(buf);
+ t.rady = EXTRACT_DOUBLE(buf);
+ t.pres = EXTRACT_DOUBLE(buf);
+ t.ang = EXTRACT_DOUBLE(buf);
+ t.fx = EXTRACT_DOUBLE(buf);
+ t.fy = EXTRACT_DOUBLE(buf);
+ t.flags = EXTRACT_INT(buf);
+ _feed_event(EXACTNESS_ACTION_MULTI_UP, n_evas, &t);
+}
+
+static void
+_main_loop_multi_move_cb(Eina_Debug_Session *session EINA_UNUSED, int srcid EINA_UNUSED, void *buffer, int size EINA_UNUSED)
+{
+ char *buf = buffer;
+ Exactness_Action_Multi_Move t;
+ int n_evas = EXTRACT_INT(buf);
+ t.d = EXTRACT_INT(buf);
+ t.x = EXTRACT_INT(buf);
+ t.y = EXTRACT_INT(buf);
+ t.rad = EXTRACT_DOUBLE(buf);
+ t.radx = EXTRACT_DOUBLE(buf);
+ t.rady = EXTRACT_DOUBLE(buf);
+ t.pres = EXTRACT_DOUBLE(buf);
+ t.ang = EXTRACT_DOUBLE(buf);
+ t.fx = EXTRACT_DOUBLE(buf);
+ t.fy = EXTRACT_DOUBLE(buf);
+ _feed_event(EXACTNESS_ACTION_MULTI_MOVE, n_evas, &t);
+}
+
+static void
+_main_loop_key_down_cb(Eina_Debug_Session *session EINA_UNUSED, int srcid EINA_UNUSED, void *buffer, int size EINA_UNUSED)
+{
+ char *buf = buffer;
+ Exactness_Action_Key_Down_Up t;
+ int n_evas = EXTRACT_INT(buf);
+ t.keyname = EXTRACT_STRING(buf);
+ t.key = EXTRACT_STRING(buf);
+ t.string = EXTRACT_STRING(buf);
+ t.compose = EXTRACT_STRING(buf);
+ t.keycode = EXTRACT_INT(buf);
+ _feed_event(EXACTNESS_ACTION_KEY_DOWN, n_evas, &t);
+}
+
+static void
+_main_loop_key_up_cb(Eina_Debug_Session *session EINA_UNUSED, int srcid EINA_UNUSED, void *buffer, int size EINA_UNUSED)
+{
+ char *buf = buffer;
+ Exactness_Action_Key_Down_Up t;
+ int n_evas = EXTRACT_INT(buf);
+ t.keyname = EXTRACT_STRING(buf);
+ t.key = EXTRACT_STRING(buf);
+ t.string = EXTRACT_STRING(buf);
+ t.compose = EXTRACT_STRING(buf);
+ t.keycode = EXTRACT_INT(buf);
+ _feed_event(EXACTNESS_ACTION_KEY_UP, n_evas, &t);
+}
+
+static void
+_main_loop_take_shot_cb(Eina_Debug_Session *session, int srcid, void *buffer, int size EINA_UNUSED)
+{
+ char *buf = buffer;
+ int n_evas = EXTRACT_INT(buf);
+ _feed_event(EXACTNESS_ACTION_TAKE_SHOT, n_evas, NULL);
+ _last_debug_session = session;
+ _last_debug_src_cid = srcid;
+}
+
+static void
+_main_loop_efl_event_cb(Eina_Debug_Session *session EINA_UNUSED, int srcid EINA_UNUSED, void *buffer, int size EINA_UNUSED)
+{
+ char *buf = buffer;
+ Exactness_Action_Efl_Event t;
+ t.wdg_name = EXTRACT_STRING(buf);
+ t.event_name = EXTRACT_STRING(buf);
+ _feed_event(EXACTNESS_ACTION_EFL_EVENT, 0, &t);
+}
+
+static void
+_main_loop_click_on_cb(Eina_Debug_Session *session EINA_UNUSED, int srcid EINA_UNUSED, void *buffer, int size EINA_UNUSED)
+{
+ char *buf = buffer;
+ Exactness_Action_Click_On t;
+ t.wdg_name = EXTRACT_STRING(buf);
+ _feed_event(EXACTNESS_ACTION_CLICK_ON, 0, &t);
+}
+
+static void
+_main_loop_stabilize_cb(Eina_Debug_Session *session EINA_UNUSED, int srcid EINA_UNUSED, void *buffer EINA_UNUSED, int size EINA_UNUSED)
+{
+ _feed_event(EXACTNESS_ACTION_STABILIZE, 0, NULL);
+}
+
+static void
+_main_loop_finish_cb(Eina_Debug_Session *session EINA_UNUSED, int srcid EINA_UNUSED, void *buffer EINA_UNUSED, int size EINA_UNUSED)
+{
+ ecore_main_loop_quit();
+}
+
+WRAPPER_TO_XFER_MAIN_LOOP(_mouse_in_cb)
+WRAPPER_TO_XFER_MAIN_LOOP(_mouse_out_cb)
+WRAPPER_TO_XFER_MAIN_LOOP(_mouse_wheel_cb)
+WRAPPER_TO_XFER_MAIN_LOOP(_multi_down_cb)
+WRAPPER_TO_XFER_MAIN_LOOP(_multi_up_cb)
+WRAPPER_TO_XFER_MAIN_LOOP(_multi_move_cb)
+WRAPPER_TO_XFER_MAIN_LOOP(_key_down_cb)
+WRAPPER_TO_XFER_MAIN_LOOP(_key_up_cb)
+WRAPPER_TO_XFER_MAIN_LOOP(_take_shot_cb)
+WRAPPER_TO_XFER_MAIN_LOOP(_efl_event_cb)
+WRAPPER_TO_XFER_MAIN_LOOP(_click_on_cb)
+WRAPPER_TO_XFER_MAIN_LOOP(_stabilize_cb)
+WRAPPER_TO_XFER_MAIN_LOOP(_finish_cb)
+
+EINA_DEBUG_OPCODES_ARRAY_DEFINE(_debug_ops,
+ {"Exactness/Actions/Mouse In", NULL, &_mouse_in_cb},
+ {"Exactness/Actions/Mouse Out", NULL, &_mouse_out_cb},
+ {"Exactness/Actions/Mouse Wheel", NULL, &_mouse_wheel_cb},
+ {"Exactness/Actions/Multi Down", NULL, &_multi_down_cb},
+ {"Exactness/Actions/Multi Up", NULL, &_multi_up_cb},
+ {"Exactness/Actions/Multi Move", NULL, &_multi_move_cb},
+ {"Exactness/Actions/Key Down", NULL, &_key_down_cb},
+ {"Exactness/Actions/Key Up", NULL, &_key_up_cb},
+ {"Exactness/Actions/Take Shot", &_take_shot_op, &_take_shot_cb},
+ {"Exactness/Actions/EFL Event", NULL, &_efl_event_cb},
+ {"Exactness/Actions/Click On", NULL, &_click_on_cb},
+ {"Exactness/Actions/Stabilize", NULL, &_stabilize_cb},
+ {"Exactness/Actions/Finish", NULL, &_finish_cb},
+ {NULL, NULL, NULL}
+);
+
+static Eina_Bool
+_src_feed(void *data EINA_UNUSED)
+{
+ if (!_evas_list) return EINA_TRUE;
+ _cur_event_list = _src_unit->actions;
+ Exactness_Action *act = eina_list_data_get(_cur_event_list);
+
+ if (act && act->delay_ms)
+ {
+ _printf(2, " Waiting <%f>\n", act->delay_ms / 1000.0);
+ ecore_timer_add(act->delay_ms / 1000.0, _feed_event_timer_cb, NULL);
+ }
+ else
+ {
+ _feed_event_timer_cb(NULL);
+ }
+ return EINA_FALSE;
+}
+
+static Eina_Bool
+_src_open()
+{
+ if (_src_type != FTYPE_REMOTE)
+ {
+ Eina_List *itr, *itr2;
+ Exactness_Action *act;
+ _printf(2, "<%s> Source file is <%s>\n", __func__, _src_filename);
+ if (_src_type == FTYPE_EXU)
+ {
+ _src_unit = exactness_unit_file_read(_src_filename);
+ }
+ else if (_src_type == FTYPE_REC)
+ {
+ _src_unit = legacy_rec_file_read(_src_filename);
+ }
+ if (!_src_unit) return EINA_FALSE;
+ if (_stabilize_shots)
+ {
+ Exactness_Action_Type last_action_type = EXACTNESS_ACTION_UNKNOWN;
+ EINA_LIST_FOREACH_SAFE(_src_unit->actions, itr, itr2, act)
+ {
+ if (act->type == EXACTNESS_ACTION_TAKE_SHOT &&
+ last_action_type != EXACTNESS_ACTION_STABILIZE)
+ {
+ Exactness_Action *act2 = calloc(1, sizeof(*act2));
+ act2->type = EXACTNESS_ACTION_STABILIZE;
+ _src_unit->actions = eina_list_prepend_relative(_src_unit->actions, act2, act);
+ }
+ last_action_type = act->type;
+ }
+ }
+ if (_speed && _speed != 1)
+ {
+ EINA_LIST_FOREACH(_src_unit->actions, itr, act)
+ act->delay_ms /= _speed;
+ }
+ }
+ else
+ {
+ eina_debug_opcodes_register(NULL, _debug_ops(), NULL, NULL);
+ }
+ return EINA_TRUE;
+}
+
+static int
+_prg_invoke(const char *full_path, int argc, char **argv)
+{
+ Eina_Value *ret__;
+ int real__;
+
+ void (*efl_main)(void *data, const Efl_Event *ev);
+ int (*elm_main)(int argc, char **argv);
+ int (*c_main)(int argc, char **argv);
+ Eina_Module *h = eina_module_new(full_path);
+ if (!h || !eina_module_load(h))
+ {
+ fprintf(stderr, "Failed loading %s.\n", full_path);
+ if (h) eina_module_free(h);
+ return 1;
+ }
+ efl_main = eina_module_symbol_get(h, "efl_main");
+ elm_main = eina_module_symbol_get(h, "elm_main");
+ c_main = eina_module_symbol_get(h, "main");
+ _evas_new = eina_module_symbol_get(h, "evas_new");
+ if (!_evas_new)
+ {
+ fprintf(stderr, "Failed loading symbol 'evas_new' from %s.\n", full_path);
+ eina_module_free(h);
+ return 1;
+ }
+
+ if (efl_main)
+ {
+ elm_init(argc, argv);
+ elm_theme_overlay_add(NULL, DATA_DIR"/exactness_play.edj");
+ efl_event_callback_add(efl_main_loop_get(), EFL_LOOP_EVENT_ARGUMENTS, efl_main, NULL);
+ ret__ = efl_loop_begin(efl_main_loop_get());
+ real__ = efl_loop_exit_code_process(ret__);
+ elm_shutdown();
+ }
+ else if (elm_main)
+ {
+ elm_init(argc, argv);
+ elm_theme_overlay_add(NULL, DATA_DIR"/exactness_play.edj");
+ real__ = elm_main(argc, argv);
+ elm_shutdown();
+ }
+ else if (c_main)
+ {
+ real__ = c_main(argc, argv);
+ }
+ else
+ {
+ fprintf(stderr, "Failed loading symbol 'efl_main', 'elm_main' or 'main' from %s.\n", full_path);
+ eina_module_free(h);
+ real__ = 1;
+ }
+
+ return real__;
+}
+
+static Eina_Stringshare *
+_prg_full_path_guess(const char *prg)
+{
+ char full_path[PATH_];
+ if (strchr(prg, '/')) return eina_stringshare_add(prg);
+ char *paths = strdup(getenv("PATH"));
+ Eina_Stringshare *ret = NULL;
+ while (paths && *paths && !ret)
+ {
+ char *real_path;
+ char *colon = strchr(paths, ':');
+ if (colon) *colon = '\0';
+
+ sprintf(full_path, "%s/%s", paths, prg);
+ real_path = ecore_file_realpath(full_path);
+ if (*real_path)
+ {
+ ret = eina_stringshare_add(real_path);
+ // check if executable
+ }
+ free(real_path);
+
+ paths += strlen(paths);
+ if (colon) paths++;
+ }
+ return ret;
+}
+
+static Eina_Bool
+_mkdir(const char *path, Eina_Bool skip_last)
+{
+ if (!ecore_file_exists(path))
+ {
+ const char *cur = path + 1;
+ do
+ {
+ char *slash = strchr(cur, '/');
+ if (slash) *slash = '\0';
+ else if (skip_last) return EINA_TRUE;
+ if (!ecore_file_exists(path) && !ecore_file_mkdir(path)) return EINA_FALSE;
+ if (slash) *slash = '/';
+ if (slash) cur = slash + 1;
+ else cur = NULL;
+ }
+ while (cur);
+ }
+ return EINA_TRUE;
+}
+
+static void
+_old_shots_rm_cb(const char *name, const char *path, void *data)
+{
+ const char *prefix = data;
+ unsigned int len = strlen(prefix);
+ if (!strncmp(name, prefix, len) && (strlen(name) > len) && (name[len] == SHOT_DELIMITER))
+ {
+ char *buf = alloca(strlen(path) + strlen(name));
+ sprintf(buf, "%s/%s", path, name);
+ if (unlink(buf))
+ {
+ printf("Failed deleting '%s/%s': ", path, name);
+ perror("");
+ }
+ }
+}
+
+static void
+_evas_del_cb(void *data EINA_UNUSED, const Efl_Event *event)
+{
+ Eina_List *p = eina_list_data_find_list(_evas_list, event->object);
+ eina_list_data_set(p, NULL);
+}
+
+static void
+_event_key_cb(void *data EINA_UNUSED, const Efl_Event *event)
+{
+ Efl_Input_Key *evk = event->info;
+ if (!evk) return;
+ const char *key = efl_input_key_name_get(evk);
+
+ if (!strcmp(key, PAUSE_KEY_STR) && efl_input_key_pressed_get(evk))
+ {
+ _pause_request = !_pause_request;
+ if (_pause_request) _printf(1, "Pausing scenario\n");
+ else
+ {
+ _printf(1, "Playing scenario\n");
+ if (!_playing_status)
+ _feed_event_timer_cb(NULL);
+ }
+ }
+}
+
+EFL_CALLBACKS_ARRAY_DEFINE(_evas_callbacks,
+ { EFL_EVENT_DEL, _evas_del_cb },
+ { EFL_CANVAS_SCENE_EVENT_RENDER_POST, _evas_render_post_cb },
+ { EFL_EVENT_KEY_DOWN, _event_key_cb },
+ { EFL_EVENT_KEY_UP, _event_key_cb }
+ )
+
+static Evas *
+_my_evas_new(int w EINA_UNUSED, int h EINA_UNUSED)
+{
+ Evas *e;
+ if (!_evas_new) return NULL;
+ e = _evas_new();
+ if (e)
+ {
+ _printf(1, "New Evas\n");
+ _evas_list = eina_list_append(_evas_list, e);
+ efl_event_callback_array_add(e, _evas_callbacks(), NULL);
+ }
+ return e;
+}
+
+static const Ecore_Getopt optdesc = {
+ "exactness_play",
+ "%prog [options] <-s|-o|-v|-t|-h> command",
+ PACKAGE_VERSION,
+ "(C) 2017 Enlightenment",
+ "BSD",
+ "A scenario player for EFL based applications.",
+ 1,
+ {
+ ECORE_GETOPT_STORE_STR('o', "output",
+ " Set the destination for the shots.\n"
+ " If a .exu is given, the shots are stored in the file.\n"
+ " Otherwise the given path is considered as a directory\n"
+ " where shots will be stored.\n"
+ " If omitted, the output type (exu or dir) is determined\n"
+ " by the given test extension (resp. exu or rec)."),
+ ECORE_GETOPT_STORE_STR('t', "test", "Test to run on the given application"),
+ ECORE_GETOPT_STORE_TRUE('s', "show-on-screen", "Show on screen."),
+ ECORE_GETOPT_STORE_TRUE(0, "scan-objects", "Extract information of all the objects at every shot."),
+ ECORE_GETOPT_STORE_TRUE(0, "external-injection", "Expect events injection via Eina debug channel."),
+ ECORE_GETOPT_STORE_TRUE(0, "disable-screenshots", "Disable screenshots."),
+ ECORE_GETOPT_STORE_STR('f', "fonts-dir", "Specify a directory of the fonts that should be used."),
+ ECORE_GETOPT_STORE_TRUE(0, "stabilize-shots", "Wait for the frames to be stable before taking the shots."),
+ ECORE_GETOPT_STORE_DOUBLE(0, "speed", "Set the speed used to play the given test (default 1.0)."),
+ ECORE_GETOPT_COUNT('v', "verbose", "Turn verbose messages on."),
+
+ ECORE_GETOPT_LICENSE('L', "license"),
+ ECORE_GETOPT_COPYRIGHT('C', "copyright"),
+ ECORE_GETOPT_VERSION('V', "version"),
+ ECORE_GETOPT_HELP('h', "help"),
+ ECORE_GETOPT_SENTINEL
+ }
+};
+
+int main(int argc, char **argv)
+{
+ int pret = 1, opt_args = 0;
+ char *src = NULL, *dest = NULL, *eq;
+ char *fonts_dir = NULL;
+ const char *chosen_fonts = NULL;
+ Eina_Bool show_on_screen = EINA_FALSE;
+ Eina_Bool want_quit = EINA_FALSE, external_injection = EINA_FALSE;
+
+ Ecore_Getopt_Value values[] = {
+ ECORE_GETOPT_VALUE_STR(dest),
+ ECORE_GETOPT_VALUE_STR(src),
+ ECORE_GETOPT_VALUE_BOOL(show_on_screen),
+ ECORE_GETOPT_VALUE_BOOL(_scan_objects),
+ ECORE_GETOPT_VALUE_BOOL(external_injection),
+ ECORE_GETOPT_VALUE_BOOL(_disable_shots),
+ ECORE_GETOPT_VALUE_STR(fonts_dir),
+ ECORE_GETOPT_VALUE_BOOL(_stabilize_shots),
+ ECORE_GETOPT_VALUE_DOUBLE(_speed),
+ ECORE_GETOPT_VALUE_INT(_verbose),
+
+ ECORE_GETOPT_VALUE_BOOL(want_quit),
+ ECORE_GETOPT_VALUE_BOOL(want_quit),
+ ECORE_GETOPT_VALUE_BOOL(want_quit),
+ ECORE_GETOPT_VALUE_BOOL(want_quit),
+ ECORE_GETOPT_VALUE_NONE
+ };
+
+ eina_init();
+ eet_init();
+ ecore_init();
+
+ opt_args = ecore_getopt_parse(&optdesc, values, argc, argv);
+ if (opt_args < 0)
+ {
+ fprintf(stderr, "Failed parsing arguments.\n");
+ goto end;
+ }
+ if (want_quit) goto end;
+
+ /* Check for a sentinel */
+ if (argv[opt_args] && !strcmp(argv[opt_args], "--")) opt_args++;
+
+ /* Check for env variables */
+ do
+ {
+ eq = argv[opt_args] ? strchr(argv[opt_args], '=') : NULL;
+ if (eq)
+ {
+ char *var = malloc(eq - argv[opt_args] + 1);
+ memcpy(var, argv[opt_args], eq - argv[opt_args]);
+ var[eq - argv[opt_args]] = '\0';
+ setenv(var, eq + 1, 1);
+ opt_args++;
+ }
+ } while (eq);
+
+ if (dest)
+ {
+ _dest = eina_stringshare_add(dest);
+ if (!strcmp(_dest + strlen(_dest) - 4,".exu"))
+ {
+ _dest_type = FTYPE_EXU;
+ if (!_mkdir(_dest, EINA_TRUE))
+ {
+ fprintf(stderr, "Path for %s cannot be created\n", _dest);
+ goto end;
+ }
+ }
+ else
+ {
+ _dest_type = FTYPE_DIR;
+ if (!_mkdir(_dest, EINA_FALSE))
+ {
+ fprintf(stderr, "Directory %s cannot be created\n", _dest);
+ goto end;
+ }
+ }
+ }
+ if (!src && !external_injection)
+ {
+ fprintf(stderr, "no test file specified\n");
+ goto end;
+ }
+ if (src && external_injection)
+ {
+ fprintf(stderr, "Cannot inject events from a source file and from outside simultaneously\n");
+ goto end;
+ }
+ if (external_injection)
+ {
+ _src_type = FTYPE_REMOTE;
+ if (_dest_type == FTYPE_UNKNOWN) _dest_type = FTYPE_REMOTE;
+ }
+ if (src)
+ {
+ _src_filename = eina_stringshare_add(src);
+ if (!strcmp(_src_filename + strlen(_src_filename) - 4,".exu"))
+ {
+ _src_type = FTYPE_EXU;
+ if (_dest_type == FTYPE_UNKNOWN)
+ {
+ _dest_type = FTYPE_EXU;
+ _dest = "./output.exu";
+ }
+ }
+ else if (!strcmp(_src_filename + strlen(_src_filename) - 4,".rec"))
+ {
+ _src_type = FTYPE_REC;
+ if (_dest_type == FTYPE_UNKNOWN)
+ {
+ _dest_type = FTYPE_DIR;
+ _dest = ".";
+ }
+ }
+ char *slash = strrchr(_src_filename, '/');
+ if (slash) _test_name = strdup(slash + 1);
+ else _test_name = strdup(_src_filename);
+ char *dot = strrchr(_test_name, '.');
+ if (dot) *dot = '\0';
+ }
+
+ if (_scan_objects && _dest_type != FTYPE_EXU)
+ {
+ fprintf(stderr, "Scan objects options is available only if the destination is a EXU file\n");
+ goto end;
+ }
+
+ if (_dest_type == FTYPE_EXU) _dest_unit = calloc(1, sizeof(*_dest_unit));
+
+ if (_dest_type == FTYPE_DIR && _test_name)
+ eina_file_dir_list(_dest, 0, _old_shots_rm_cb, (void *)_test_name);
+
+ if (!_src_open())
+ {
+ fprintf(stderr, "Unable to read source file\n");
+ goto end;
+ }
+
+ if (!show_on_screen) setenv("ELM_ENGINE", "buffer", 1);
+ if (_src_unit && _src_unit->fonts_path)
+ {
+ char buf[PATH_];
+ if (!fonts_dir) fonts_dir = "./fonts";
+ sprintf(buf, "%s/%s", fonts_dir, _src_unit->fonts_path);
+ if (!ecore_file_exists(buf))
+ {
+ fprintf(stderr, "Unable to use the fonts path '%s' provided in %s\n",
+ _src_unit->fonts_path, _src_filename);
+ goto end;
+ }
+ chosen_fonts = _src_unit->fonts_path;
+ }
+ if (fonts_dir)
+ {
+ Eina_Tmpstr *fonts_conf_name = NULL;
+ if (!ecore_file_exists(fonts_dir))
+ {
+ fprintf(stderr, "Unable to find fonts directory %s\n", fonts_dir);
+ goto end;
+ }
+ if (!chosen_fonts)
+ {
+ Eina_List *dated_fonts = ecore_file_ls(fonts_dir);
+ char *date_dir;
+ chosen_fonts = eina_stringshare_add(eina_list_last_data_get(dated_fonts));
+ EINA_LIST_FREE(dated_fonts, date_dir) free(date_dir);
+ }
+ if (chosen_fonts)
+ {
+ int tmp_fd = eina_file_mkstemp("/tmp/fonts_XXXXXX.conf", &fonts_conf_name);
+ FILE *tmp_f = fdopen(tmp_fd, "wb");
+ fprintf(tmp_f,
+ "<?xml version=\"1.0\"?>\n<!DOCTYPE fontconfig SYSTEM \"fonts.dtd\">\n<fontconfig>\n"
+ "<dir prefix=\"default\">%s/%s</dir>\n</fontconfig>\n",
+ fonts_dir, chosen_fonts);
+ fclose(tmp_f);
+ close(tmp_fd);
+
+ setenv("FONTCONFIG_FILE", fonts_conf_name, 1);
+ }
+ }
+ efl_object_init();
+ evas_init();
+
+ if (argv[opt_args])
+ {
+ /* Replace the current command line to hide the Exactness part */
+ int len = argv[argc - 1] + strlen(argv[argc - 1]) - argv[opt_args];
+ memcpy(argv[0], argv[opt_args], len);
+ memset(argv[0] + len, 0, _POSIX_PATH_MAX - len);
+
+ int i;
+ for (i = opt_args; i < argc; i++)
+ {
+ if (i != opt_args)
+ {
+ argv[i - opt_args] = argv[0] + (argv[i] - argv[opt_args]);
+ }
+ _printf(1, "%s ", argv[i - opt_args]);
+ }
+ _printf(1, "\n");
+ }
+ else
+ {
+ Eina_List *itr;
+ Exactness_Source_Code *code;
+ Eina_Tmpstr *f_output = NULL;
+ EINA_LIST_FOREACH(_src_unit->codes, itr, code)
+ {
+ if (!strcmp(code->language, "C") && code->command)
+ {
+ int status;
+ Ecore_Exe *exe;
+ Eina_Tmpstr *f_code;
+ Eina_Strbuf *sbuf;
+ int fd_code = eina_file_mkstemp("exactness_XXXXXX.c", &f_code);
+ int fd_output = eina_file_mkstemp("exactness_XXXXXX.output", &f_output);
+ close(fd_output);
+ write(fd_code, code->content, strlen(code->content));
+ close(fd_code);
+
+ sbuf = eina_strbuf_new();
+ eina_strbuf_append(sbuf, code->command);
+ eina_strbuf_replace_all(sbuf, "$SRC", f_code);
+ eina_strbuf_replace_all(sbuf, "$DEST", f_output);
+ exe = ecore_exe_pipe_run(eina_strbuf_string_get(sbuf), ECORE_EXE_NONE, NULL);
+#ifdef HAVE_FORK
+ waitpid(ecore_exe_pid_get(exe), &status, 0);
+#endif
+ }
+ }
+ if (!f_output)
+ {
+ fprintf(stderr, "no program specified\nUse -h for more information\n");
+ goto end;
+ }
+ argv[0] = strdup(f_output);
+ }
+
+
+ ecore_evas_callback_new_set(_my_evas_new);
+ if (_src_type != FTYPE_REMOTE)
+ ecore_idler_add(_src_feed, NULL);
+ pret = _prg_invoke(_prg_full_path_guess(argv[0]), argc - opt_args, argv);
+
+ if (_dest && _dest_unit)
+ {
+ if (_src_unit)
+ {
+ Exactness_Unit *tmp = NULL;
+ if (_src_type == FTYPE_EXU) tmp = exactness_unit_file_read(_src_filename);
+ if (_src_type == FTYPE_REC) tmp = legacy_rec_file_read(_src_filename);
+ _dest_unit->actions = tmp->actions;
+ _dest_unit->codes = tmp->codes;
+ }
+ exactness_unit_file_write(_dest_unit, _dest);
+ }
+
+end:
+ eet_shutdown();
+ eina_shutdown();
+ return pret;
+}
diff --git a/src/bin/exactness/player_entry.edc b/src/bin/exactness/player_entry.edc
new file mode 100644
index 0000000000..b0d1966d6e
--- /dev/null
+++ b/src/bin/exactness/player_entry.edc
@@ -0,0 +1,932 @@
+collections {
+ #include "../../../data/elementary/themes/fonts.edc"
+ group { name: "elm/entry/cursor/default";
+ min: 1 0;
+ images.image: "white_bar_vert_glow.png" COMP;
+ parts {
+ part { name: "cursor"; mouse_events: 0;
+ clip_to: "clipper";
+ description { state: "default" 0.0;
+ rel1.offset: -4 -4;
+ rel2.offset: 3 3;
+ image.normal: "white_bar_vert_glow.png";
+ image.border: 4 4 4 4;
+ fill.smooth: 0;
+ color: 255 255 255 0;
+ color_class: "entry_cursor";
+ min: 9 10;
+ }
+ description { state: "visible" 0.0;
+ inherit: "default" 0.0;
+ color: 255 255 255 255;
+ }
+ }
+ part { name: "clipper"; type: RECT;
+ description { state: "default" 0.0;
+ rel1.to: "cursor";
+ rel2.to: "cursor";
+ fixed: 1 1;
+ }
+ description { state: "hidden" 0.0;
+ inherit: "default" 0.0;
+ visible: 0;
+ }
+ }
+ }
+ programs {
+ program {
+ signal: "selection,changed"; source: "elm.text";
+ action: STATE_SET "hidden" 0.0;
+ target: "clipper";
+ }
+ program {
+ signal: "selection,cleared"; source: "elm.text";
+ action: STATE_SET "default" 0.0;
+ target: "clipper";
+ }
+ program {
+ signal: "selection,reset"; source: "elm.text";
+ action: STATE_SET "default" 0.0;
+ target: "clipper";
+ }
+ program {
+ signal: "elm,action,focus"; source: "elm";
+ action: ACTION_STOP;
+ target: "cursor_show";
+ target: "cursor_hide";
+ target: "cursor_show_timer";
+ target: "cursor_hide_timer";
+ after: "cursor_show";
+ }
+ program {
+ signal: "elm,action,unfocus"; source: "elm";
+ action: ACTION_STOP;
+ target: "cursor_show";
+ target: "cursor_hide";
+ target: "cursor_show_timer";
+ target: "cursor_hide_timer";
+ after: "cursor_hide_stop";
+ }
+ program {
+ signal: "elm,action,show,cursor"; source: "elm";
+ action: ACTION_STOP;
+ target: "cursor_show";
+ target: "cursor_hide";
+ target: "cursor_show_timer";
+ target: "cursor_hide_timer";
+ after: "cursor_show";
+ }
+ program { name: "cursor_hide_stop";
+ action: STATE_SET "default" 0.0;
+ target: "cursor";
+ }
+ program { name: "cursor_show";
+ action: STATE_SET "default" 0.0;
+ target: "cursor";
+ after: "cursor_show_timer";
+ }
+ program { name: "cursor_hide";
+ action: STATE_SET "default" 0.0;
+ target: "cursor";
+ transition: SINUSOIDAL 0.2;
+ after: "cursor_hide_timer";
+ }
+ program { name: "cursor_show_timer";
+ in: 0.5 0.0;
+ after: "cursor_hide";
+ }
+ program { name: "cursor_hide_timer";
+ in: 0.2 0.0;
+ after: "cursor_show";
+ }
+ }
+ }
+
+ group { name: "elm/entry/selection/default";
+ parts {
+ part { name: "base"; type: RECT;
+ description { state: "default" 0.0;
+ color: 51 153 255 255;
+ }
+ }
+ }
+ }
+
+ group { name: "elm/entry/anchor/default";
+ images.image: "horizontal_separated_bar_small_glow.png" COMP;
+ parts {
+ part { name: "bar";
+ description { state: "default" 0.0;
+ image.normal: "horizontal_separated_bar_small_glow.png";
+ image.border: 4 4 4 4;
+ fill.smooth: 0;
+ fixed: 0 1;
+ rel1.relative: 0.0 1.0;
+ rel1.offset: -3 -5;
+ rel2.offset: 2 4;
+ }
+ }
+ }
+ }
+
+ group { name: "elm/entry/base/default";
+ sounds {
+ sample { name: "key-tap1" LOSSY 64;
+ source: "kbd-tap.wav";
+ }
+ sample { name: "key-tap2" LOSSY 64;
+ source: "kbd-tap2.wav";
+ }
+ sample { name: "key-tap3" LOSSY 64;
+ source: "kbd-tap3.wav";
+ }
+ sample { name: "key-tap4" LOSSY 64;
+ source: "kbd-tap4.wav";
+ }
+ sample { name: "key-tap5" LOSSY 64;
+ source: "kbd-tap5.wav";
+ }
+ }
+
+ styles {
+ style { name: "entry_style";
+ base: "font="FN" font_size=10 color=#ffffff style=shadow,bottom shadow_color=#00000080 wrap=word text_class=entry_text color_class=entry_text left_margin=2 right_margin=2";
+ ENABLED_TEXTBLOCK_TAGS
+ }
+ style { name: "entry_nowrap_style";
+ base: "font="FN" font_size=10 color=#ffffff style=shadow,bottom shadow_color=#00000080 text_class=entry_text color_class=entry_text left_margin=2 right_margin=2";
+ ENABLED_TEXTBLOCK_TAGS
+ }
+ style { name: "entry_disabled_style";
+ base: "font="FN" font_size=10 color=#151515 style=shadow,bottom shadow_color=#ffffff19 wrap=word text_class=entry_text_disabled color_class=entry_text_disabled left_margin=2 right_margin=2";
+ DISABLED_TEXTBLOCK_TAGS
+ }
+ style { name: "entry_nowrap_disabled_style";
+ base: "font="FN" font_size=10 color=#151515 style=shadow,bottom shadow_color=#ffffff19 text_class=entry_text_disabled color_class=entry_text_disabled left_margin=2 right_margin=2";
+ DISABLED_TEXTBLOCK_TAGS
+ }
+ style { name: "entry_guide_style";
+ base: "font="FN" font_size=10 color=#000000 style=shadow,bottom shadow_color=#ffffff19 wrap=word text_class=entry_guide_text color_class=entry_guide_text left_margin=2 right_margin=2 ellipsis=0.0";
+ DISABLED_TEXTBLOCK_TAGS
+ }
+ }
+ // data.item: "context_menu_orientation" "horizontal";
+ parts {
+ part { name: "elm.swallow.background"; type: SWALLOW;
+ description { state: "default" 0.0;
+ rel1.offset: 1 1;
+ rel2.offset: -2 -2;
+ }
+ }
+ part { name: "elm.guide"; type: TEXTBLOCK; mouse_events: 0;
+ scale: 1;
+ description { state: "default" 0.0;
+ rel1.to: "elm.text";
+ rel2.to: "elm.text";
+ text { style: "entry_guide_style";
+ min: 0 1;
+ align: 0.0 0.0;
+ }
+ }
+ description { state: "hidden" 0.0;
+ inherit: "default" 0.0;
+ visible: 0;
+ }
+ }
+ part { name: "elm.text"; type: TEXTBLOCK;
+ scale: 1;
+ entry_mode: EDITABLE;
+ select_mode: DEFAULT;
+ // select_mode: EXPLICIT;
+ cursor_mode: BEFORE;
+ multiline: 1;
+ source: "elm/entry/selection/default"; // selection under
+ // source2: "X"; // selection over
+ // source3: "X"; // cursor under
+ source4: "elm/entry/cursor/default"; // cursorover
+ // source5: "elm/entry/anchor/default"; // anchor under
+ source6: "elm/entry/anchor/default"; // anchor over
+ description { state: "default" 0.0;
+ /* we gotta use 0 0 here, because of scrolled entries */
+ fixed: 0 0;
+ rel1.offset: 2 2;
+ rel2.offset: -3 -3;
+ text { style: "entry_style";
+ min: 0 1;
+ align: 0.0 0.0;
+ }
+ }
+ description { state: "disabled" 0.0;
+ inherit: "default" 0.0;
+ text { style: "entry_disabled_style";
+ min: 0 1;
+ }
+ }
+ }
+ }
+ programs {
+ program {
+ signal: "load"; source: "";
+ action: FOCUS_SET;
+ target: "elm.text";
+ }
+ program {
+ signal: "elm,state,disabled"; source: "elm";
+ action: STATE_SET "disabled" 0.0;
+ target: "elm.text";
+ }
+ program {
+ signal: "elm,state,enabled"; source: "elm";
+ action: STATE_SET "default" 0.0;
+ target: "elm.text";
+ }
+ program {
+ signal: "elm,guide,disabled"; source: "elm";
+ action: STATE_SET "hidden" 0.0;
+ target: "elm.guide";
+ }
+ program {
+ signal: "elm,guide,enabled"; source: "elm";
+ action: STATE_SET "default" 0.0;
+ target: "elm.guide";
+ }
+ program { name: "key-down";
+ signal: "entry,keydown"; source: "elm.text";
+ script {
+ new buf[32];
+ snprintf(buf, 31, "key-down%i", (rand() % 5) + 1);
+ run_program(get_program_id(buf));
+ }
+ }
+ program { name: "key-down1";
+ action: PLAY_SAMPLE "key-tap1" 1.0 INPUT;
+ }
+ program { name: "key-down2";
+ action: PLAY_SAMPLE "key-tap2" 1.0 INPUT;
+ }
+ program { name: "key-down3";
+ action: PLAY_SAMPLE "key-tap3" 1.0 INPUT;
+ }
+ program { name: "key-down4";
+ action: PLAY_SAMPLE "key-tap4" 1.0 INPUT;
+ }
+ program { name: "key-down5";
+ action: PLAY_SAMPLE "key-tap5" 1.0 INPUT;
+ }
+ }
+ }
+
+ group { name: "elm/entry/base-mixedwrap/default";
+ inherit: "elm/entry/base/default";
+ styles {
+ style { name: "entry_style_mixedwrap";
+ base: "font="FN" font_size=10 color=#ffffff style=shadow,bottom shadow_color=#00000080 wrap=mixed text_class=entry_text color_class=entry_text left_margin=2 right_margin=2";
+ ENABLED_TEXTBLOCK_TAGS
+ }
+ style { name: "entry_disabled_style_mixedwrap";
+ base: "font="FN" font_size=10 color=#151515 style=shadow,bottom shadow_color=#ffffff19 wrap=mixed text_class=entry_text_disabled color_class=entry_text_disabled left_margin=2 right_margin=2";
+ DISABLED_TEXTBLOCK_TAGS
+ }
+ style { name: "entry_guide_style_mixedwrap";
+ base: "font="FN" font_size=10 color=#000000 style=shadow,bottom shadow_color=#ffffff19 wrap=mixed text_class=entry_guide_text color_class=entry_guide_text left_margin=2 right_margin=2 ellipsis=0.0";
+ DISABLED_TEXTBLOCK_TAGS
+ }
+ }
+ parts {
+ part { name: "elm.guide"; type: TEXTBLOCK; mouse_events: 0;
+ scale: 1;
+ description { state: "default" 0.0;
+ rel1.to: "elm.text";
+ rel2.to: "elm.text";
+ text { style: "entry_guide_style_mixedwrap";
+ min: 0 1;
+ align: 0.0 0.0;
+ }
+ }
+ description { state: "hidden" 0.0;
+ inherit: "default" 0.0;
+ visible: 0;
+ }
+ }
+ part { name: "elm.text";
+ description { state: "default" 0.0;
+ fixed: 1 0;
+ text { style: "entry_style_mixedwrap";
+ min: 0 1;
+ align: 0.0 0.0;
+ }
+ }
+ description { state: "disabled" 0.0;
+ inherit: "default" 0.0;
+ text { style: "entry_disabled_style_mixedwrap";
+ min: 0 1;
+ }
+ }
+ }
+ }
+ }
+
+ group { name: "elm/entry/base-charwrap/default";
+ inherit: "elm/entry/base/default";
+ styles {
+ style { name: "entry_style_charwrap";
+ base: "font="FN" font_size=10 color=#ffffff style=shadow,bottom shadow_color=#00000080 wrap=char text_class=entry_text color_class=entry_text left_margin=2 right_margin=2";
+ ENABLED_TEXTBLOCK_TAGS
+ }
+ style { name: "entry_disabled_style_charwrap";
+ base: "font="FN" font_size=10 color=#151515 style=shadow,bottom shadow_color=#ffffff19 wrap=char text_class=entry_text_disabled color_class=entry_text_disabled left_margin=2 right_margin=2";
+ DISABLED_TEXTBLOCK_TAGS
+ }
+ style { name: "entry_guide_style_charwrap";
+ base: "font="FN" font_size=10 color=#000000 style=shadow,bottom shadow_color=#ffffff19 wrap=char text_class=entry_guide_text color_class=entry_guide_text left_margin=2 right_margin=2 ellipsis=0.0";
+ DISABLED_TEXTBLOCK_TAGS
+ }
+ }
+ parts {
+ part { name: "elm.guide"; type: TEXTBLOCK; mouse_events: 0;
+ scale: 1;
+ description { state: "default" 0.0;
+ rel1.to: "elm.text";
+ rel2.to: "elm.text";
+ text { style: "entry_guide_style_charwrap";
+ min: 0 1;
+ align: 0.0 0.0;
+ }
+ }
+ description { state: "hidden" 0.0;
+ inherit: "default" 0.0;
+ visible: 0;
+ }
+ }
+ part { name: "elm.text";
+ description { state: "default" 0.0;
+ fixed: 1 1;
+ text { style: "entry_style_charwrap";
+ min: 0 1;
+ align: 0.0 0.0;
+ }
+ }
+ description { state: "disabled" 0.0;
+ inherit: "default" 0.0;
+ text { style: "entry_disabled_style_charwrap";
+ min: 0 1;
+ }
+ }
+ }
+ }
+ }
+
+ group { name: "elm/entry/base-nowrap/default";
+ inherit: "elm/entry/base/default";
+ parts {
+ part { name: "elm.guide"; type: TEXTBLOCK; mouse_events: 0;
+ scale: 1;
+ description { state: "default" 0.0;
+ rel1.to: "elm.text";
+ rel2.to: "elm.text";
+ text { style: "entry_guide_style";
+ min: 0 1;
+ align: 0.0 0.0;
+ }
+ }
+ description { state: "hidden" 0.0;
+ inherit: "default" 0.0;
+ visible: 0;
+ }
+ }
+ part { name: "elm.text";
+ description { state: "default" 0.0;
+ text { style: "entry_nowrap_style";
+ min: 1 1;
+ ellipsis: -1;
+ align: 0.0 0.0;
+ }
+ }
+ description { state: "disabled" 0.0;
+ inherit: "default" 0.0;
+ text { style: "entry_nowrap_disabled_style";
+ min: 0 1;
+ }
+ }
+ }
+ }
+ }
+
+ group { name: "elm/entry/base-single/default";
+ inherit: "elm/entry/base/default";
+ styles {
+ style { name: "entry_single_style";
+ base: "font="FN" font_size=10 color=#ffffff style=shadow,bottom shadow_color=#00000080 wrap=none text_class=entry_text color_class=entry_text left_margin=2 right_margin=2";
+ ENABLED_TEXTBLOCK_TAGS
+ }
+ style { name: "entry_single_disabled_style";
+ base: "font="FN" font_size=10 color=#151515 style=shadow,bottom shadow_color=#ffffff19 wrap=none text_class=entry_text_disabled color_class=entry_text_disabled left_margin=2 right_margin=2";
+ DISABLED_TEXTBLOCK_TAGS
+ }
+ style { name: "entry_single_guide_style";
+ base: "font="FN" font_size=10 color=#000000 style=shadow,bottom shadow_color=#ffffff19 wrap=none text_class=entry_guide_text color_class=entry_guide_text left_margin=2 right_margin=2 ellipsis=0.0";
+ DISABLED_TEXTBLOCK_TAGS
+ }
+ }
+ parts {
+ part { name: "elm.guide"; type: TEXTBLOCK; mouse_events: 0;
+ scale: 1;
+ description { state: "default" 0.0;
+ rel1.to: "elm.text";
+ rel2.to: "elm.text";
+ text { style: "entry_single_guide_style";
+ min: 0 1;
+ align: 0.0 0.5;
+ }
+ }
+ description { state: "hidden" 0.0;
+ inherit: "default" 0.0;
+ visible: 0;
+ }
+ }
+ part { name: "elm.text";
+ multiline: 0;
+ description { state: "default" 0.0;
+ text { style: "entry_single_style";
+ min: 1 1;
+ ellipsis: -1;
+ max: 0 0;
+ align: 0.0 0.5;
+ }
+ }
+ description { state: "disabled" 0.0;
+ inherit: "default" 0.0;
+ text { style: "entry_single_disabled_style";
+ }
+ }
+ }
+ }
+ }
+
+ group { name: "elm/entry/base-single/spinner/default";
+ alias: "elm/entry/base-single/spinner/vertical";
+ inherit: "elm/entry/base-single/default";
+ styles {
+ style { name: "entry_single_spinner_style";
+ base: "font="FN" font_size=10 color=#ffffff style=shadow,bottom shadow_color=#00000080 align=center wrap=none text_class=entry_text color_class=entry_text left_margin=2 right_margin=2";
+ ENABLED_TEXTBLOCK_TAGS
+ }
+ }
+ parts {
+ part { name: "elm.text";
+ description { state: "default" 0.0;
+ text.style: "entry_single_spinner_style";
+ }
+ }
+ }
+ }
+
+ group { name: "elm/entry/base-single-noedit/default";
+ inherit: "elm/entry/base/default";
+ parts {
+ part { name: "elm.text";
+ entry_mode: PLAIN;
+ multiline: 0;
+ source: "elm/entry/selection/default"; // selection under
+ source4: ""; // cursorover
+ source6: "elm/entry/anchor/default"; // anchor over
+ description { state: "default" 0.0;
+ text { style: "entry_single_style";
+ min: 1 1;
+ ellipsis: -1;
+ max: 0 0;
+ align: 0.0 0.5;
+ }
+ }
+ description { state: "disabled" 0.0;
+ inherit: "default" 0.0;
+ text { style: "entry_single_disabled_style";
+ }
+ }
+ }
+ }
+ }
+
+ group { name: "elm/entry/base-noedit/default";
+ inherit: "elm/entry/base/default";
+ parts {
+ part { name: "elm.text";
+ entry_mode: PLAIN;
+ source: "elm/entry/selection/default"; // selection under
+ source4: ""; // cursorover
+ source6: "elm/entry/anchor/default"; // anchor over
+ description { state: "default" 0.0;
+ fixed: 1 0;
+ text { style: "entry_style";
+ min: 0 1;
+ align: 0.0 0.0;
+ }
+ }
+ description { state: "disabled" 0.0;
+ inherit: "default" 0.0;
+ text { style: "entry_disabled_style";
+ }
+ }
+ }
+ }
+ }
+
+ group { name: "elm/entry/base-noedit-mixedwrap/default";
+ inherit: "elm/entry/base/default";
+ parts {
+ part { name: "elm.text";
+ entry_mode: PLAIN;
+ source: "elm/entry/selection/default"; // selection under
+ source4: ""; // cursorover
+ source6: "elm/entry/anchor/default"; // anchor over
+ description { state: "default" 0.0;
+ fixed: 1 0;
+ text { style: "entry_style_mixedwrap";
+ min: 0 1;
+ align: 0.0 0.0;
+ }
+ }
+ description { state: "disabled" 0.0;
+ inherit: "default" 0.0;
+ text { style: "entry_disabled_style_mixedwrap";
+ }
+ }
+ }
+ }
+ }
+
+ group { name: "elm/entry/base-noedit-charwrap/default";
+ inherit: "elm/entry/base/default";
+ parts {
+ part { name: "elm.text";
+ entry_mode: PLAIN;
+ source: "elm/entry/selection/default"; // selection under
+ source4: ""; // cursorover
+ source6: "elm/entry/anchor/default"; // anchor under
+ description { state: "default" 0.0;
+ fixed: 1 0;
+ text { style: "entry_style_charwrap";
+ min: 0 1;
+ align: 0.0 0.0;
+ }
+ }
+ description { state: "disabled" 0.0;
+ inherit: "default" 0.0;
+ text { style: "entry_disabled_style_charwrap";
+ }
+ }
+ }
+ }
+ }
+
+ group { name: "elm/entry/base-nowrap-noedit/default";
+ inherit: "elm/entry/base/default";
+ parts {
+ part { name: "elm.text";
+ entry_mode: PLAIN;
+ source: "elm/entry/selection/default"; // selection under
+ source4: ""; // cursorover
+ source6: "elm/entry/anchor/default"; // anchor under
+ description { state: "default" 0.0;
+ text { style: "entry_style";
+ min: 1 1;
+ ellipsis: -1;
+ align: 0.0 0.0;
+ }
+ }
+ description { state: "disabled" 0.0;
+ inherit: "default" 0.0;
+ text { style: "entry_disabled_style";
+ }
+ }
+ }
+ }
+ }
+
+ group { name: "elm/entry/base-password/default";
+ inherit: "elm/entry/base/default";
+ parts {
+ part { name: "elm.guide"; type: TEXTBLOCK; mouse_events: 0;
+ scale: 1;
+ description { state: "default" 0.0;
+ rel1.to: "elm.text";
+ rel2.to: "elm.text";
+ text { style: "entry_single_guide_style";
+ min: 0 1;
+ align: 0.0 0.5;
+ }
+ }
+ description { state: "hidden" 0.0;
+ inherit: "default" 0.0;
+ visible: 0;
+ }
+ }
+ part { name: "elm.text";
+ entry_mode: PASSWORD;
+ multiline: 0;
+ source: "elm/entry/selection/default"; // selection under
+ source4: "elm/entry/cursor/default"; // cursorover
+ source6: "elm/entry/anchor/default"; // anchor under
+ description { state: "default" 0.0;
+ text { style: "entry_single_style";
+ repch: "*";
+ min: 1 1;
+ ellipsis: -1;
+ max: 0 0;
+ align: 0.0 0.5;
+ }
+ }
+ description { state: "disabled" 0.0;
+ inherit: "default" 0.0;
+ text { style: "entry_single_disabled_style";
+ }
+ }
+ }
+ }
+ }
+
+ group { name: "elm/entry/magnifier/default";
+ images.image: "frame_rounded.png" COMP;
+ parts {
+ part { name: "bg"; type: RECT; mouse_events: 0;
+ description { state: "default" 0.0;
+ rel1.offset: 10 10;
+ rel1.to: "over";
+ rel2.offset: -11 -11;
+ rel2.to: "over";
+ color: 48 48 48 255;
+ }
+ description { state: "hidden" 0.0;
+ inherit: "default" 0.0;
+ visible: 0;
+ }
+ }
+ part { name: "elm.swallow.content"; type: SWALLOW; mouse_events: 0;
+ description { state: "default" 0.0;
+ rel1.offset: 10 10;
+ rel1.to: "over";
+ rel2.offset: -11 -11;
+ rel2.to: "over";
+ }
+ description { state: "hidden" 0.0;
+ inherit: "default" 0.0;
+ visible: 0;
+ }
+ }
+ part { name: "over"; mouse_events: 0;
+ scale: 1;
+ description { state: "default" 0.0;
+ min: 128 64;
+ align: 0 0;
+ image.normal: "frame_rounded.png";
+ image.border: 14 14 14 14;
+ image.middle: 0;
+ fill.smooth: 0;
+ }
+ description { state: "hidden" 0.0;
+ inherit: "default" 0.0;
+ visible: 0;
+ }
+ }
+ }
+ programs {
+ program { name: "magnifier_show";
+ signal: "elm,action,show,magnifier"; source: "elm";
+ action: STATE_SET "default" 0.0;
+ target: "elm.swallow.content";
+ target: "bg";
+ target: "over";
+ }
+ program { name: "magnifier_hide";
+ signal: "elm,action,hide,magnifier"; source: "elm";
+ action: STATE_SET "hidden" 0.0;
+ target: "elm.swallow.content";
+ target: "bg";
+ target: "over";
+ }
+ }
+ }
+
+ group { name: "elm/entry/handler/start/default";
+ images.image: "handle_pick_up_left.png" COMP;
+ parts {
+ part { name: "base"; mouse_events: 0;
+ scale: 1;
+ description { state: "default" 0.0;
+ min: 21 27; // 42 54
+ image.normal: "handle_pick_up_left.png";
+ align: (29/42) (11/54);
+ color_class: "entry_selection_handler";
+ visible: 0;
+ }
+ description { state: "visible" 0.0;
+ inherit: "default" 0.0;
+ visible: 1;
+ }
+ }
+ part { name: "event"; type: RECT;
+ scale: 1;
+ description { state: "default" 0.0;
+ color: 0 0 0 0;
+ rel1.to: "base";
+ rel2.to: "base";
+ min: 32 32;
+ visible: 0;
+ }
+ description { state: "visible" 0.0;
+ inherit: "default" 0.0;
+ visible: 1;
+ }
+ }
+ }
+ programs {
+ program {
+ signal: "elm,handler,show"; source: "elm";
+ action: STATE_SET "visible" 0.0;
+ target: "base";
+ target: "event";
+ }
+ program {
+ signal: "elm,handler,hide"; source: "elm";
+ action: STATE_SET "default" 0.0;
+ target: "base";
+ target: "event";
+ }
+ }
+ }
+
+ group { name: "elm/entry/handler/end/default";
+ images.image: "handle_pick_up_right.png" COMP;
+ parts {
+ part { name: "base"; mouse_events: 0;
+ scale: 1;
+ description { state: "default" 0.0;
+ min: 21 27; // 42 54
+ image.normal: "handle_pick_up_right.png";
+ align: (12/42) (11/54);
+ color_class: "entry_selection_handler";
+ visible: 0;
+ }
+ description { state: "visible" 0.0;
+ inherit: "default" 0.0;
+ visible: 1;
+ }
+ }
+ part { name: "event"; type: RECT;
+ scale: 1;
+ description { state: "default" 0.0;
+ color: 0 0 0 0;
+ rel1.to: "base";
+ rel2.to: "base";
+ min: 32 32;
+ visible: 0;
+ }
+ description { state: "visible" 0.0;
+ inherit: "default" 0.0;
+ visible: 1;
+ }
+ }
+ }
+ programs {
+ program {
+ signal: "elm,handler,show"; source: "elm";
+ action: STATE_SET "visible" 0.0;
+ target: "base";
+ target: "event";
+ }
+ program {
+ signal: "elm,handler,hide"; source: "elm";
+ action: STATE_SET "default" 0.0;
+ target: "base";
+ target: "event";
+ }
+ }
+ }
+
+ ///////////////////////////////////////////////////////////////////////////////
+ // emoticon images from:
+ // Tanya - Latvia
+ // http://lazycrazy.deviantart.com/
+ // http://lazycrazy.deviantart.com/art/Very-Emotional-Emoticons-144461621
+ group { name: "elm/entry/emoticon/angry/default"; images.image:
+ "emo-angry.png" COMP; parts { part { name: "icon"; mouse_events: 0; description { state: "default" 0.0; max: 64 64; image.normal:
+ "emo-angry.png"; } } } }
+ group { name: "elm/entry/emoticon/angry-shout/default"; images.image:
+ "emo-angry-shout.png" COMP; parts { part { name: "icon"; mouse_events: 0; description { state: "default" 0.0; max: 64 64; image.normal:
+ "emo-angry-shout.png"; } } } }
+ group { name: "elm/entry/emoticon/crazy-laugh/default"; images.image:
+ "emo-crazy-laugh.png" COMP; parts { part { name: "icon"; mouse_events: 0; description { state: "default" 0.0; max: 64 64; image.normal:
+ "emo-crazy-laugh.png"; } } } }
+ group { name: "elm/entry/emoticon/evil-laugh/default"; images.image:
+ "emo-evil-laugh.png" COMP; parts { part { name: "icon"; mouse_events: 0; description { state: "default" 0.0; max: 64 64; image.normal:
+ "emo-evil-laugh.png"; } } } }
+ group { name: "elm/entry/emoticon/evil/default"; images.image:
+ "emo-evil.png" COMP; parts { part { name: "icon"; mouse_events: 0; description { state: "default" 0.0; max: 64 64; image.normal:
+ "emo-evil.png"; } } } }
+ group { name: "elm/entry/emoticon/goggle-smile/default"; images.image:
+ "emo-goggle-smile.png" COMP; parts { part { name: "icon"; mouse_events: 0; description { state: "default" 0.0; max: 64 64; image.normal:
+ "emo-goggle-smile.png"; } } } }
+ group { name: "elm/entry/emoticon/grumpy/default"; images.image:
+ "emo-grumpy.png" COMP; parts { part { name: "icon"; mouse_events: 0; description { state: "default" 0.0; max: 64 64; image.normal:
+ "emo-grumpy.png"; } } } }
+ group { name: "elm/entry/emoticon/grumpy-smile/default"; images.image:
+ "emo-grumpy-smile.png" COMP; parts { part { name: "icon"; mouse_events: 0; description { state: "default" 0.0; max: 64 64; image.normal:
+ "emo-grumpy-smile.png"; } } } }
+ group { name: "elm/entry/emoticon/guilty/default"; images.image:
+ "emo-guilty.png" COMP; parts { part { name: "icon"; mouse_events: 0; description { state: "default" 0.0; max: 64 64; image.normal:
+ "emo-guilty.png"; } } } }
+ group { name: "elm/entry/emoticon/guilty-smile/default"; images.image:
+ "emo-guilty-smile.png" COMP; parts { part { name: "icon"; mouse_events: 0; description { state: "default" 0.0; max: 64 64; image.normal:
+ "emo-guilty-smile.png"; } } } }
+ group { name: "elm/entry/emoticon/haha/default"; images.image:
+ "emo-haha.png" COMP; parts { part { name: "icon"; mouse_events: 0; description { state: "default" 0.0; max: 64 64; image.normal:
+ "emo-haha.png"; } } } }
+ group { name: "elm/entry/emoticon/half-smile/default"; images.image:
+ "emo-half-smile.png" COMP; parts { part { name: "icon"; mouse_events: 0; description { state: "default" 0.0; max: 64 64; image.normal:
+ "emo-half-smile.png"; } } } }
+ group { name: "elm/entry/emoticon/happy-panting/default"; images.image:
+ "emo-happy-panting.png" COMP; parts { part { name: "icon"; mouse_events: 0; description { state: "default" 0.0; max: 64 64; image.normal:
+ "emo-happy-panting.png"; } } } }
+ group { name: "elm/entry/emoticon/happy/default"; images.image:
+ "emo-happy.png" COMP; parts { part { name: "icon"; mouse_events: 0; description { state: "default" 0.0; max: 64 64; image.normal:
+ "emo-happy.png"; } } } }
+ group { name: "elm/entry/emoticon/indifferent/default"; images.image:
+ "emo-indifferent.png" COMP; parts { part { name: "icon"; mouse_events: 0; description { state: "default" 0.0; max: 64 64; image.normal:
+ "emo-indifferent.png"; } } } }
+ group { name: "elm/entry/emoticon/kiss/default"; images.image:
+ "emo-kiss.png" COMP; parts { part { name: "icon"; mouse_events: 0; description { state: "default" 0.0; max: 64 64; image.normal:
+ "emo-kiss.png"; } } } }
+ group { name: "elm/entry/emoticon/knowing-grin/default"; images.image:
+ "emo-knowing-grin.png" COMP; parts { part { name: "icon"; mouse_events: 0; description { state: "default" 0.0; max: 64 64; image.normal:
+ "emo-knowing-grin.png"; } } } }
+ group { name: "elm/entry/emoticon/laugh/default"; images.image:
+ "emo-laugh.png" COMP; parts { part { name: "icon"; mouse_events: 0; description { state: "default" 0.0; max: 64 64; image.normal:
+ "emo-laugh.png"; } } } }
+ group { name: "elm/entry/emoticon/little-bit-sorry/default"; images.image:
+ "emo-little-bit-sorry.png" COMP; parts { part { name: "icon"; mouse_events: 0; description { state: "default" 0.0; max: 64 64; image.normal:
+ "emo-little-bit-sorry.png"; } } } }
+ group { name: "elm/entry/emoticon/love-lots/default"; images.image:
+ "emo-love-lots.png" COMP; parts { part { name: "icon"; mouse_events: 0; description { state: "default" 0.0; max: 64 64; image.normal:
+ "emo-love-lots.png"; } } } }
+ group { name: "elm/entry/emoticon/love/default"; images.image:
+ "emo-love.png" COMP; parts { part { name: "icon"; mouse_events: 0; description { state: "default" 0.0; max: 64 64; image.normal:
+ "emo-love.png"; } } } }
+ group { name: "elm/entry/emoticon/minimal-smile/default"; images.image:
+ "emo-minimal-smile.png" COMP; parts { part { name: "icon"; mouse_events: 0; description { state: "default" 0.0; max: 64 64; image.normal:
+ "emo-minimal-smile.png"; } } } }
+ group { name: "elm/entry/emoticon/not-happy/default"; images.image:
+ "emo-not-happy.png" COMP; parts { part { name: "icon"; mouse_events: 0; description { state: "default" 0.0; max: 64 64; image.normal:
+ "emo-not-happy.png"; } } } }
+ group { name: "elm/entry/emoticon/not-impressed/default"; images.image:
+ "emo-not-impressed.png" COMP; parts { part { name: "icon"; mouse_events: 0; description { state: "default" 0.0; max: 64 64; image.normal:
+ "emo-not-impressed.png"; } } } }
+ group { name: "elm/entry/emoticon/omg/default"; images.image:
+ "emo-omg.png" COMP; parts { part { name: "icon"; mouse_events: 0; description { state: "default" 0.0; max: 64 64; image.normal:
+ "emo-omg.png"; } } } }
+ group { name: "elm/entry/emoticon/opensmile/default"; images.image:
+ "emo-opensmile.png" COMP; parts { part { name: "icon"; mouse_events: 0; description { state: "default" 0.0; max: 64 64; image.normal:
+ "emo-opensmile.png"; } } } }
+ group { name: "elm/entry/emoticon/smile/default"; images.image:
+ "emo-smile.png" COMP; parts { part { name: "icon"; mouse_events: 0; description { state: "default" 0.0; max: 64 64; image.normal:
+ "emo-smile.png"; } } } }
+ group { name: "elm/entry/emoticon/sorry/default"; images.image:
+ "emo-sorry.png" COMP; parts { part { name: "icon"; mouse_events: 0; description { state: "default" 0.0; max: 64 64; image.normal:
+ "emo-sorry.png"; } } } }
+ group { name: "elm/entry/emoticon/squint-laugh/default"; images.image:
+ "emo-squint-laugh.png" COMP; parts { part { name: "icon"; mouse_events: 0; description { state: "default" 0.0; max: 64 64; image.normal:
+ "emo-squint-laugh.png"; } } } }
+ group { name: "elm/entry/emoticon/surprised/default"; images.image:
+ "emo-surprised.png" COMP; parts { part { name: "icon"; mouse_events: 0; description { state: "default" 0.0; max: 64 64; image.normal:
+ "emo-surprised.png"; } } } }
+ group { name: "elm/entry/emoticon/suspicious/default"; images.image:
+ "emo-suspicious.png" COMP; parts { part { name: "icon"; mouse_events: 0; description { state: "default" 0.0; max: 64 64; image.normal:
+ "emo-suspicious.png"; } } } }
+ group { name: "elm/entry/emoticon/tongue-dangling/default"; images.image:
+ "emo-tongue-dangling.png" COMP; parts { part { name: "icon"; mouse_events: 0; description { state: "default" 0.0; max: 64 64; image.normal:
+ "emo-tongue-dangling.png"; } } } }
+ group { name: "elm/entry/emoticon/tongue-poke/default"; images.image:
+ "emo-tongue-poke.png" COMP; parts { part { name: "icon"; mouse_events: 0; description { state: "default" 0.0; max: 64 64; image.normal:
+ "emo-tongue-poke.png"; } } } }
+ group { name: "elm/entry/emoticon/uh/default"; images.image:
+ "emo-uh.png" COMP; parts { part { name: "icon"; mouse_events: 0; description { state: "default" 0.0; max: 64 64; image.normal:
+ "emo-uh.png"; } } } }
+ group { name: "elm/entry/emoticon/unhappy/default"; images.image:
+ "emo-unhappy.png" COMP; parts { part { name: "icon"; mouse_events: 0; description { state: "default" 0.0; max: 64 64; image.normal:
+ "emo-unhappy.png"; } } } }
+ group { name: "elm/entry/emoticon/very-sorry/default"; images.image:
+ "emo-very-sorry.png" COMP; parts { part { name: "icon"; mouse_events: 0; description { state: "default" 0.0; max: 64 64; image.normal:
+ "emo-very-sorry.png"; } } } }
+ group { name: "elm/entry/emoticon/what/default"; images.image:
+ "emo-what.png" COMP; parts { part { name: "icon"; mouse_events: 0; description { state: "default" 0.0; max: 64 64; image.normal:
+ "emo-what.png"; } } } }
+ group { name: "elm/entry/emoticon/wink/default"; images.image:
+ "emo-wink.png" COMP; parts { part { name: "icon"; mouse_events: 0; description { state: "default" 0.0; max: 64 64; image.normal:
+ "emo-wink.png"; } } } }
+ group { name: "elm/entry/emoticon/worried/default"; images.image:
+ "emo-worried.png" COMP; parts { part { name: "icon"; mouse_events: 0; description { state: "default" 0.0; max: 64 64; image.normal:
+ "emo-worried.png"; } } } }
+ group { name: "elm/entry/emoticon/wtf/default"; images.image:
+ "emo-wtf.png" COMP; parts { part { name: "icon"; mouse_events: 0; description { state: "default" 0.0; max: 64 64; image.normal:
+ "emo-wtf.png"; } } } }
+ //------------------------------------------------------------
+}
diff --git a/src/bin/exactness/recorder.c b/src/bin/exactness/recorder.c
new file mode 100644
index 0000000000..11a2087d08
--- /dev/null
+++ b/src/bin/exactness/recorder.c
@@ -0,0 +1,531 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <unistd.h>
+
+#include <sys/types.h>
+#ifdef HAVE_SYS_SYSINFO_H
+# include <sys/sysinfo.h>
+#endif
+
+#ifndef EFL_EO_API_SUPPORT
+#define EFL_EO_API_SUPPORT
+#endif
+#include <Eina.h>
+#include <Eo.h>
+#include <Evas.h>
+#include <Ecore.h>
+#include <Ecore_File.h>
+#include <Ecore_Getopt.h>
+#include <Ecore_Con.h>
+#include <Elementary.h>
+#include <Exactness.h>
+
+#include <exactness_private.h>
+
+#define MAX_PATH 1024
+#define STABILIZE_KEY_STR "F1"
+#define SHOT_KEY_STR "F2"
+#define SAVE_KEY_STR "F3"
+
+static Evas *(*_evas_new)(void) = NULL;
+static const char *_out_filename = NULL;
+static const char *_test_name = NULL;
+static int _verbose = 0;
+
+static Eina_List *_evas_list = NULL;
+static unsigned int _last_evas_id = 0;
+
+static Exactness_Unit *_unit = NULL;
+
+static char *_shot_key = NULL;
+static unsigned int _last_timestamp = 0.0;
+
+static void
+_printf(int verbose, const char *fmt, ...)
+{
+ va_list ap;
+ if (!_verbose || verbose > _verbose) return;
+
+ va_start(ap, fmt);
+ vprintf(fmt, ap);
+ va_end(ap);
+}
+
+static Exactness_Action_Type
+_event_pointer_type_get(Efl_Pointer_Action t)
+{
+ switch(t)
+ {
+ case EFL_POINTER_ACTION_IN: return EXACTNESS_ACTION_MOUSE_IN;
+ case EFL_POINTER_ACTION_OUT: return EXACTNESS_ACTION_MOUSE_OUT;
+ case EFL_POINTER_ACTION_DOWN: return EXACTNESS_ACTION_MULTI_DOWN;
+ case EFL_POINTER_ACTION_UP: return EXACTNESS_ACTION_MULTI_UP;
+ case EFL_POINTER_ACTION_MOVE: return EXACTNESS_ACTION_MULTI_MOVE;
+ case EFL_POINTER_ACTION_WHEEL: return EXACTNESS_ACTION_MOUSE_WHEEL;
+ default: return EXACTNESS_ACTION_UNKNOWN;
+ }
+}
+
+static void
+_output_write()
+{
+ if (_unit) exactness_unit_file_write(_unit, _out_filename);
+}
+
+static void
+_add_to_list(Exactness_Action_Type type, unsigned int n_evas, unsigned int timestamp, void *data, int len)
+{
+ if (_unit)
+ {
+ const Exactness_Action *prev_v = eina_list_last_data_get(_unit->actions);
+ if (prev_v)
+ {
+ if (prev_v->type == type &&
+ timestamp == _last_timestamp &&
+ prev_v->n_evas == n_evas &&
+ (!len || !memcmp(prev_v->data, data, len))) return;
+ }
+ _printf(1, "Recording %s\n", _exactness_action_type_to_string_get(type));
+ Exactness_Action *act = malloc(sizeof(*act));
+ act->type = type;
+ act->n_evas = n_evas;
+ act->delay_ms = timestamp - _last_timestamp;
+ _last_timestamp = timestamp;
+ if (len)
+ {
+ act->data = malloc(len);
+ memcpy(act->data, data, len);
+ }
+ _unit->actions = eina_list_append(_unit->actions, act);
+ }
+}
+
+static int
+_evas_id_get(Evas *e)
+{
+ return (intptr_t)efl_key_data_get(e, "__evas_id");
+}
+
+static void
+_event_pointer_cb(void *data, const Efl_Event *event)
+{
+ Eo *eo_e = data;
+ Eo *evp = event->info;
+ if (!evp) return;
+
+ int timestamp = efl_input_timestamp_get(evp);
+ int n_evas = _evas_id_get(eo_e);
+ Efl_Pointer_Action action = efl_input_pointer_action_get(evp);
+ Exactness_Action_Type evt = _event_pointer_type_get(action);
+
+ if (!timestamp) return;
+
+ _printf(2, "Calling \"%s\" timestamp=<%u>\n", _exactness_action_type_to_string_get(evt), timestamp);
+
+ switch (action)
+ {
+ case EFL_POINTER_ACTION_MOVE:
+ {
+ double rad = 0, radx = 0, rady = 0, pres = 0, ang = 0, fx = 0, fy = 0;
+ int tool = efl_input_pointer_touch_id_get(evp);
+ Eina_Position2D pos = efl_input_pointer_position_get(evp);
+ Exactness_Action_Multi_Move t = { tool, pos.x, pos.y, rad, radx, rady, pres, ang, fx, fy };
+ if (n_evas >= 0) _add_to_list(evt, n_evas, timestamp, &t, sizeof(t));
+ break;
+ }
+ case EFL_POINTER_ACTION_DOWN: case EFL_POINTER_ACTION_UP:
+ {
+ double rad = 0, radx = 0, rady = 0, pres = 0, ang = 0, fx = 0, fy = 0;
+ int b = efl_input_pointer_button_get(evp);
+ int tool = efl_input_pointer_touch_id_get(evp);
+ Eina_Position2D pos = efl_input_pointer_position_get(evp);
+ Efl_Pointer_Flags flags = efl_input_pointer_button_flags_get(evp);
+ Exactness_Action_Multi_Event t = { tool, b, pos.x, pos.y, rad, radx, rady, pres, ang,
+ fx, fy, flags };
+ if (n_evas >= 0) _add_to_list(evt, n_evas, timestamp, &t, sizeof(t));
+ break;
+ }
+ case EFL_POINTER_ACTION_IN: case EFL_POINTER_ACTION_OUT:
+ {
+ if (n_evas >= 0) _add_to_list(evt, n_evas, timestamp, NULL, 0);
+ break;
+ }
+ case EFL_POINTER_ACTION_WHEEL:
+ {
+ Eina_Bool horiz = efl_input_pointer_wheel_horizontal_get(evp);
+ int z = efl_input_pointer_wheel_delta_get(evp);
+ Exactness_Action_Mouse_Wheel t = { horiz, z };
+ if (n_evas >= 0) _add_to_list(evt, n_evas, timestamp, &t, sizeof(t));
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+static void
+_event_key_cb(void *data, const Efl_Event *event)
+{
+ Efl_Input_Key *evk = event->info;
+ Eo *eo_e = data;
+ if (!evk) return;
+ const char *key = efl_input_key_name_get(evk);
+ int timestamp = efl_input_timestamp_get(evk);
+ unsigned int n_evas = _evas_id_get(eo_e);
+ Exactness_Action_Type evt = EXACTNESS_ACTION_KEY_UP;
+
+ if (efl_input_key_pressed_get(evk))
+ {
+ if (!strcmp(key, _shot_key))
+ {
+ _printf(2, "Take Screenshot: %s timestamp=<%u>\n", __func__, timestamp);
+ _add_to_list(EXACTNESS_ACTION_TAKE_SHOT, n_evas, timestamp, NULL, 0);
+ return;
+ }
+ if (!strcmp(key, STABILIZE_KEY_STR))
+ {
+ _printf(2, "Stabilize: %s timestamp=<%u>\n", __func__, timestamp);
+ _add_to_list(EXACTNESS_ACTION_STABILIZE, n_evas, timestamp, NULL, 0);
+ return;
+ }
+ if (!strcmp(key, SAVE_KEY_STR))
+ {
+ _output_write();
+ _printf(2, "Save events: %s timestamp=<%u>\n", __func__, timestamp);
+ return;
+ }
+ evt = EXACTNESS_ACTION_KEY_DOWN;
+ }
+ else
+ {
+ if (!strcmp(key, _shot_key) || !strcmp(key, SAVE_KEY_STR) || !strcmp(key, STABILIZE_KEY_STR)) return;
+ }
+ if (_unit)
+ { /* Construct duplicate strings, free them when list if freed */
+ Exactness_Action_Key_Down_Up t;
+ t.keyname = eina_stringshare_add(key);
+ t.key = eina_stringshare_add(efl_input_key_sym_get(evk));
+ t.string = eina_stringshare_add(efl_input_key_string_get(evk));
+ t.compose = eina_stringshare_add(efl_input_key_compose_string_get(evk));
+ t.keycode = efl_input_key_code_get(evk);
+ _add_to_list(evt, n_evas, timestamp, &t, sizeof(t));
+ }
+}
+
+// note: "hold" event comes from above (elm), not below (ecore)
+EFL_CALLBACKS_ARRAY_DEFINE(_event_pointer_callbacks,
+ { EFL_EVENT_POINTER_MOVE, _event_pointer_cb },
+ { EFL_EVENT_POINTER_DOWN, _event_pointer_cb },
+ { EFL_EVENT_POINTER_UP, _event_pointer_cb },
+ { EFL_EVENT_POINTER_IN, _event_pointer_cb },
+ { EFL_EVENT_POINTER_OUT, _event_pointer_cb },
+ { EFL_EVENT_POINTER_WHEEL, _event_pointer_cb },
+ { EFL_EVENT_FINGER_MOVE, _event_pointer_cb },
+ { EFL_EVENT_FINGER_DOWN, _event_pointer_cb },
+ { EFL_EVENT_FINGER_UP, _event_pointer_cb },
+ { EFL_EVENT_KEY_DOWN, _event_key_cb },
+ { EFL_EVENT_KEY_UP, _event_key_cb }
+ )
+
+static Evas *
+_my_evas_new(int w EINA_UNUSED, int h EINA_UNUSED)
+{
+ Evas *e;
+ if (!_evas_new) return NULL;
+ e = _evas_new();
+ if (e)
+ {
+ _printf(1, "New Evas\n");
+ _evas_list = eina_list_append(_evas_list, e);
+ efl_key_data_set(e, "__evas_id", (void *)(intptr_t)_last_evas_id++);
+ efl_event_callback_array_add(e, _event_pointer_callbacks(), e);
+ }
+ return e;
+}
+
+static int
+_prg_invoke(const char *full_path, int argc, char **argv)
+{
+ Eina_Value *ret__;
+ int real__;
+
+ void (*efl_main)(void *data, const Efl_Event *ev);
+ int (*elm_main)(int argc, char **argv);
+ int (*c_main)(int argc, char **argv);
+ Eina_Module *h = eina_module_new(full_path);
+ if (!h || !eina_module_load(h))
+ {
+ fprintf(stderr, "Failed loading %s.\n", full_path);
+ if (h) eina_module_free(h);
+ return EINA_FALSE;
+ }
+ efl_main = eina_module_symbol_get(h, "efl_main");
+ elm_main = eina_module_symbol_get(h, "elm_main");
+ c_main = eina_module_symbol_get(h, "main");
+ _evas_new = eina_module_symbol_get(h, "evas_new");
+ if (!_evas_new)
+ {
+ fprintf(stderr, "Failed loading symbol 'evas_new' from %s.\n", full_path);
+ eina_module_free(h);
+ return 1;
+ }
+ if (efl_main)
+ {
+ elm_init(argc, argv);
+ efl_event_callback_add(efl_main_loop_get(), EFL_LOOP_EVENT_ARGUMENTS, efl_main, NULL);
+ ret__ = efl_loop_begin(efl_main_loop_get());
+ real__ = efl_loop_exit_code_process(ret__);
+ elm_shutdown();
+ }
+ else if (elm_main)
+ {
+ elm_init(argc, argv);
+ real__ = elm_main(argc, argv);
+ elm_shutdown();
+ }
+ else if (c_main)
+ {
+ real__ = c_main(argc, argv);
+ }
+ else
+ {
+ fprintf(stderr, "Failed loading symbol 'efl_main', 'elm_main' or 'main' from %s.\n", full_path);
+ eina_module_free(h);
+ real__ = 1;
+ }
+ return real__;
+}
+
+static Eina_Stringshare *
+_prg_full_path_guess(const char *prg)
+{
+ char full_path[MAX_PATH];
+ if (strchr(prg, '/')) return eina_stringshare_add(prg);
+ char *paths = strdup(getenv("PATH"));
+ Eina_Stringshare *ret = NULL;
+ while (paths && *paths && !ret)
+ {
+ char *real_path;
+ char *colon = strchr(paths, ':');
+ if (colon) *colon = '\0';
+
+ sprintf(full_path, "%s/%s", paths, prg);
+ real_path = ecore_file_realpath(full_path);
+ if (*real_path)
+ {
+ ret = eina_stringshare_add(real_path);
+ // check if executable
+ }
+ free(real_path);
+
+ paths += strlen(paths);
+ if (colon) paths++;
+ }
+ return ret;
+}
+
+static Eina_Bool
+_mkdir(const char *dir)
+{
+ if (!ecore_file_exists(dir))
+ {
+ const char *cur = dir + 1;
+ do
+ {
+ char *slash = strchr(cur, '/');
+ if (slash) *slash = '\0';
+ if (!ecore_file_exists(dir) && !ecore_file_mkdir(dir)) return EINA_FALSE;
+ if (slash) *slash = '/';
+ if (slash) cur = slash + 1;
+ else cur = NULL;
+ }
+ while (cur);
+ }
+ return EINA_TRUE;
+}
+
+static const Ecore_Getopt optdesc = {
+ "exactness_record",
+ "%prog [options] <-v|-t|-h> command",
+ PACKAGE_VERSION,
+ "(C) 2017 Enlightenment",
+ "BSD",
+ "A scenario recorder for EFL based applications.\n"
+ "\tF1 - Request stabilization\n"
+ "\tF2 - Request shot\n"
+ "\tF3 - Request to save the scenario\n",
+ 1,
+ {
+ ECORE_GETOPT_STORE_STR('t', "test", "Name of the filename where to store the test."),
+ ECORE_GETOPT_STORE_STR('f', "fonts-dir", "Specify a directory of the fonts that should be used."),
+ ECORE_GETOPT_COUNT('v', "verbose", "Turn verbose messages on."),
+
+ ECORE_GETOPT_LICENSE('L', "license"),
+ ECORE_GETOPT_COPYRIGHT('C', "copyright"),
+ ECORE_GETOPT_VERSION('V', "version"),
+ ECORE_GETOPT_HELP('h', "help"),
+ ECORE_GETOPT_SENTINEL
+ }
+};
+
+int main(int argc, char **argv)
+{
+ char *dest = NULL, *eq;
+ char *fonts_dir = NULL;
+ int pret = 1, opt_args = 0;
+ Eina_Bool want_quit = EINA_FALSE;
+
+ Ecore_Getopt_Value values[] = {
+ ECORE_GETOPT_VALUE_STR(dest),
+ ECORE_GETOPT_VALUE_STR(fonts_dir),
+ ECORE_GETOPT_VALUE_INT(_verbose),
+
+ ECORE_GETOPT_VALUE_BOOL(want_quit),
+ ECORE_GETOPT_VALUE_BOOL(want_quit),
+ ECORE_GETOPT_VALUE_BOOL(want_quit),
+ ECORE_GETOPT_VALUE_BOOL(want_quit),
+ ECORE_GETOPT_VALUE_NONE
+ };
+
+ eina_init();
+ ecore_init();
+
+ opt_args = ecore_getopt_parse(&optdesc, values, argc, argv);
+ if (opt_args < 0)
+ {
+ fprintf(stderr, "Failed parsing arguments.\n");
+ goto end;
+ }
+ if (want_quit) goto end;
+
+ /* Check for a sentinel */
+ if (argv[opt_args] && !strcmp(argv[opt_args], "--")) opt_args++;
+
+ /* Check for env variables */
+ do
+ {
+ eq = argv[opt_args] ? strchr(argv[opt_args], '=') : NULL;
+ if (eq)
+ {
+ char *var = malloc(eq - argv[opt_args] + 1);
+ memcpy(var, argv[opt_args], eq - argv[opt_args]);
+ var[eq - argv[opt_args]] = '\0';
+ setenv(var, eq + 1, 1);
+ opt_args++;
+ }
+ } while (eq);
+ _out_filename = eina_stringshare_add(dest);
+
+ if (!_out_filename)
+ {
+ fprintf(stderr, "no test file specified\n");
+ goto end;
+ }
+ else
+ {
+ char *slash = strrchr(_out_filename, '/');
+ if (slash) _test_name = strdup(slash + 1);
+ else _test_name = strdup(_out_filename);
+ char *dot = strrchr(_test_name, '.');
+ if (dot) *dot = '\0';
+ if (slash)
+ {
+ *slash = '\0';
+ if (!_mkdir(_out_filename))
+ {
+ fprintf(stderr, "Can't create %s\n", _out_filename);
+ goto end;
+ }
+ *slash = '/';
+ }
+ }
+ if (strcmp(_out_filename + strlen(_out_filename) - 4,".exu"))
+ {
+ fprintf(stderr, "A file with a exu extension is required - %s invalid\n", _out_filename);
+ goto end;
+ }
+
+ if (strcmp(_out_filename + strlen(_out_filename) - 4,".exu"))
+ {
+ fprintf(stderr, "A file with a exu extension is required - %s invalid\n", _out_filename);
+ goto end;
+ }
+
+ if (!argv[opt_args])
+ {
+ fprintf(stderr, "no program specified\nUse -h for more information\n");
+ goto end;
+ }
+
+ efl_object_init();
+ evas_init();
+
+ if (!_unit)
+ {
+ _unit = calloc(1, sizeof(*_unit));
+ }
+
+ if (fonts_dir)
+ {
+ Eina_Tmpstr *fonts_conf_name = NULL;
+ if (!ecore_file_exists(fonts_dir))
+ {
+ fprintf(stderr, "Unable to find fonts directory %s\n", fonts_dir);
+ goto end;
+ }
+ Eina_List *dated_fonts = ecore_file_ls(fonts_dir);
+ char *date_dir;
+ _unit->fonts_path = strdup(eina_list_last_data_get(dated_fonts));
+ EINA_LIST_FREE(dated_fonts, date_dir) free(date_dir);
+ if (_unit->fonts_path)
+ {
+ int tmp_fd = eina_file_mkstemp("/tmp/fonts_XXXXXX.conf", &fonts_conf_name);
+ FILE *tmp_f = fdopen(tmp_fd, "wb");
+ fprintf(tmp_f,
+ "<?xml version=\"1.0\"?>\n<!DOCTYPE fontconfig SYSTEM \"fonts.dtd\">\n<fontconfig>\n"
+ "<dir prefix=\"default\">%s/%s</dir>\n</fontconfig>\n",
+ fonts_dir, _unit->fonts_path);
+ fclose(tmp_f);
+ close(tmp_fd);
+
+ setenv("FONTCONFIG_FILE", fonts_conf_name, 1);
+ }
+ }
+
+ /* Replace the current command line to hide the Exactness part */
+ int len = argv[argc - 1] + strlen(argv[argc - 1]) - argv[opt_args];
+ memcpy(argv[0], argv[opt_args], len);
+ memset(argv[0] + len, 0, MAX_PATH - len);
+
+ int i;
+ for (i = opt_args; i < argc; i++)
+ {
+ if (i != opt_args)
+ {
+ argv[i - opt_args] = argv[0] + (argv[i] - argv[opt_args]);
+ }
+ _printf(1, "%s ", argv[i - opt_args]);
+ }
+ _printf(1, "\n");
+
+ if (!_shot_key) _shot_key = getenv("SHOT_KEY");
+ if (!_shot_key) _shot_key = SHOT_KEY_STR;
+
+ ecore_evas_callback_new_set(_my_evas_new);
+ _last_timestamp = ecore_time_get() * 1000;
+ pret = _prg_invoke(_prg_full_path_guess(argv[0]), argc - opt_args, argv);
+
+ _output_write();
+ //free_events(_events_list, EINA_TRUE);
+ //_events_list = NULL;
+
+ pret = 0;
+end:
+ eina_shutdown();
+ return pret;
+}
diff --git a/src/lib/exactness/Exactness.h b/src/lib/exactness/Exactness.h
new file mode 100644
index 0000000000..d5587c3fbf
--- /dev/null
+++ b/src/lib/exactness/Exactness.h
@@ -0,0 +1,268 @@
+#ifndef _EXACTNESS_H
+#define _EXACTNESS_H
+
+#include <Evas.h>
+
+#ifdef EAPI
+# undef EAPI
+#endif
+
+#ifdef _WIN32
+# ifdef EXACTNESS_BUILD
+# ifdef DLL_EXPORT
+# define EAPI __declspec(dllexport)
+# else
+# define EAPI
+# endif /* ! DLL_EXPORT */
+# else
+# define EAPI __declspec(dllimport)
+# endif /* ! EXACTNESS_BUILD */
+#else
+# ifdef __GNUC__
+# if __GNUC__ >= 4
+# define EAPI __attribute__ ((visibility("default")))
+# else
+# define EAPI
+# endif
+# else
+# define EAPI
+# endif
+#endif /* ! _WIN32 */
+
+/**
+ * @page exactness_main Exactness
+ *
+ * @date 2018 (created)
+ *
+ * This page describes the public structures and APIs available for Exactness.
+ *
+ * @addtogroup Exactness
+ * @{
+ */
+
+/**
+ * @typedef Exactness_Action_Type
+ * The type values for an Exactness action.
+ */
+typedef enum
+{
+ EXACTNESS_ACTION_UNKNOWN = 0,
+ EXACTNESS_ACTION_MOUSE_IN,
+ EXACTNESS_ACTION_MOUSE_OUT,
+ EXACTNESS_ACTION_MOUSE_WHEEL,
+ EXACTNESS_ACTION_MULTI_DOWN,
+ EXACTNESS_ACTION_MULTI_UP,
+ EXACTNESS_ACTION_MULTI_MOVE,
+ EXACTNESS_ACTION_KEY_DOWN,
+ EXACTNESS_ACTION_KEY_UP,
+ EXACTNESS_ACTION_TAKE_SHOT,
+ EXACTNESS_ACTION_EFL_EVENT,
+ EXACTNESS_ACTION_CLICK_ON,
+ EXACTNESS_ACTION_STABILIZE,
+ EXACTNESS_ACTION_LAST = EXACTNESS_ACTION_STABILIZE
+ /* Add any supported actions here and update _LAST */
+} Exactness_Action_Type;
+
+/**
+ * @typedef Exactness_Action_Mouse_Wheel
+ * The type for the Exactness Mouse Wheel action.
+ */
+typedef struct
+{
+ int direction;
+ int z;
+} Exactness_Action_Mouse_Wheel;
+
+/**
+ * @typedef Exactness_Action_Key_Down_Up
+ * The type for the Exactness Key Down Up action.
+ */
+typedef struct
+{
+ const char *keyname;
+ const char *key;
+ const char *string;
+ const char *compose;
+ unsigned int keycode;
+} Exactness_Action_Key_Down_Up;
+
+/**
+ * @typedef Exactness_Action_Multi_Event
+ * The type for the Exactness Multi Event action.
+ */
+typedef struct
+{
+ int d;
+ int b; /* In case of simple mouse down/up, corresponds to the button */
+ int x;
+ int y;
+ double rad;
+ double radx;
+ double rady;
+ double pres;
+ double ang;
+ double fx;
+ double fy;
+ Evas_Button_Flags flags;
+} Exactness_Action_Multi_Event;
+
+/**
+ * @typedef Exactness_Action_Multi_Move
+ * The type for the Exactness Multi Move action.
+ */
+typedef struct
+{
+ int d;
+ int x;
+ int y;
+ double rad;
+ double radx;
+ double rady;
+ double pres;
+ double ang;
+ double fx;
+ double fy;
+} Exactness_Action_Multi_Move;
+
+/**
+ * @typedef Exactness_Action_Efl_Event
+ * The type for the Exactness EFL Event action.
+ */
+typedef struct
+{
+ char *wdg_name;
+ char *event_name;
+} Exactness_Action_Efl_Event;
+
+/**
+ * @typedef Exactness_Action_Click_On
+ * The type for the Exactness Click on (widget) action.
+ */
+typedef struct
+{
+ char *wdg_name;
+} Exactness_Action_Click_On;
+
+/**
+ * @typedef Exactness_Action
+ * The type for the Exactness action.
+ */
+typedef struct
+{
+ Exactness_Action_Type type; /**< The action type */
+ unsigned int n_evas; /**< The evas number on which the action has to be applied */
+ unsigned int delay_ms; /**< The delay (in ms) to wait for this action */
+ void *data; /**< The specific action data */
+} Exactness_Action;
+
+/**
+ * @typedef Exactness_Object
+ * The type for the Exactness object.
+ */
+typedef struct
+{
+ long long id; /**< The Eo pointer */
+ long long parent_id; /**< The Eo parent pointer */
+ const char *kl_name; /**< The class name */
+
+ Eina_List *children; /* NOT EET */
+
+ /* Evas stuff */
+ int x; /**< The X coordinate */
+ int y; /**< The Y coordinate */
+ int w; /**< The object width */
+ int h; /**< The object height */
+} Exactness_Object;
+
+/**
+ * @typedef Exactness_Objects
+ * The type for the Exactness objects list.
+ */
+typedef struct
+{
+ Eina_List *objs; /**< List of all the objects */
+ /* main_objs not in EET */
+ Eina_List *main_objs; /**< List of the main objects */
+} Exactness_Objects;
+
+/**
+ * @typedef Exactness_Image
+ * The type for the Exactness Image.
+ */
+typedef struct
+{
+ unsigned int w; /**< Width of the image */
+ unsigned int h; /**< Height of the image */
+ void *pixels; /**< Pixels of the image */
+} Exactness_Image;
+
+typedef struct
+{
+ char *language; /**< String describing the language of the content e.g "C"...*/
+ char *content; /**< Content used as source */
+ char *command; /**< Command needed to generate the application from the content */
+} Exactness_Source_Code;
+
+typedef struct
+{
+ Eina_List *actions; /**< List of Exactness_Action */
+ /* imgs not in EET */
+ Eina_List *imgs; /**< List of Exactness_Image */
+ Eina_List *objs; /**< List of Exactness_Objects */
+ Eina_List *codes; /**< List of Exactness_Source_Code */
+ const char *fonts_path; /**< Path to the fonts to use, relative to the fonts dir given in parameter to the player/recorder */
+ int nb_shots; /**< The number of shots present in the unit */
+} Exactness_Unit;
+
+/**
+ * @brief Read an unit from a given file
+ *
+ * @param filename Name of the file containing the unit
+ *
+ * @return the unit
+ */
+EAPI Exactness_Unit *exactness_unit_file_read(const char *filename);
+
+/**
+ * @brief Write an unit into the given file
+ *
+ * @param unit Unit to store
+ * @param filename Name of the file containing the unit
+ *
+ * @return EINA_TRUE on success, EINA_FALSE otherwise
+ */
+EAPI Eina_Bool exactness_unit_file_write(Exactness_Unit *unit, const char *filename);
+
+/**
+ * @brief Compare two images
+ *
+ * @param img1 first image
+ * @param img2 second image
+ * @param imgO pointer for the diff image. Can be NULL
+ *
+ * @return EINA_TRUE if the images are different, EINA_FALSE otherwise
+ */
+EAPI Eina_Bool exactness_image_compare(Exactness_Image *img1, Exactness_Image *img2, Exactness_Image **imgO);
+
+/**
+ * @brief Free the given image
+ *
+ * @param img the image
+ *
+ */
+EAPI void exactness_image_free(Exactness_Image *img);
+
+/**
+ * @brief Read a legacy file and convert it to an unit
+ *
+ * @param filename Name of the legacy file
+ *
+ * @return the unit
+ */
+EAPI Exactness_Unit *legacy_rec_file_read(const char *filename);
+
+/**
+ * @}
+ */
+
+#endif /* _EXACTNESS_H */
diff --git a/src/lib/exactness/exactness_private.h b/src/lib/exactness/exactness_private.h
new file mode 100644
index 0000000000..68bf4d8ddb
--- /dev/null
+++ b/src/lib/exactness/exactness_private.h
@@ -0,0 +1,10 @@
+#ifndef _EXACTNESS_PRIVATE_H
+#define _EXACTNESS_PRIVATE_H
+
+#include <Exactness.h>
+
+/* private header */
+EAPI const char *_exactness_action_type_to_string_get(Exactness_Action_Type type);
+
+#define SHOT_DELIMITER '+'
+#endif
diff --git a/src/lib/exactness/legacy_file.c b/src/lib/exactness/legacy_file.c
new file mode 100644
index 0000000000..78ef333551
--- /dev/null
+++ b/src/lib/exactness/legacy_file.c
@@ -0,0 +1,876 @@
+#include <stdio.h>
+#include <limits.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <Eina.h>
+#include <Eet.h>
+#include <Evas.h>
+
+#include "Exactness.h"
+
+#define CACHE_FILE_ENTRY "cache"
+
+enum _Tsuite_Event_Type
+{ /* Add any supported events here */
+ TSUITE_EVENT_NOT_SUPPORTED = 0,
+ TSUITE_EVENT_MOUSE_IN,
+ TSUITE_EVENT_MOUSE_OUT,
+ TSUITE_EVENT_MOUSE_DOWN,
+ TSUITE_EVENT_MOUSE_UP,
+ TSUITE_EVENT_MOUSE_MOVE,
+ TSUITE_EVENT_MOUSE_WHEEL,
+ TSUITE_EVENT_MULTI_DOWN,
+ TSUITE_EVENT_MULTI_UP,
+ TSUITE_EVENT_MULTI_MOVE,
+ TSUITE_EVENT_KEY_DOWN,
+ TSUITE_EVENT_KEY_UP,
+ TSUITE_EVENT_KEY_DOWN_WITH_KEYCODE,
+ TSUITE_EVENT_KEY_UP_WITH_KEYCODE,
+ TSUITE_EVENT_TAKE_SHOT
+};
+typedef enum _Tsuite_Event_Type Tsuite_Event_Type;
+
+struct _eet_event_type_mapping
+{
+ Tsuite_Event_Type t;
+ const char *name;
+};
+typedef struct _eet_event_type_mapping eet_event_type_mapping;
+
+struct _Variant_Type_st
+{
+ const char *type;
+ Eina_Bool unknow : 1;
+};
+typedef struct _Variant_Type_st Variant_Type_st;
+
+struct _Variant_st
+{
+ Variant_Type_st t;
+ void *data; /* differently than the union type, we
+ * don't need to pre-allocate the memory
+ * for the field*/
+};
+typedef struct _Variant_st Variant_st;
+
+struct _Timer_Data
+{
+ unsigned int recent_event_time;
+ Eina_List *current_event;
+};
+typedef struct _Timer_Data Timer_Data;
+
+struct _Tsuite_Data
+{
+ int serial; /**< Serial number of current-file */
+ Timer_Data *td;
+};
+typedef struct _Tsuite_Data Tsuite_Data;
+
+struct _mouse_in_mouse_out
+{
+ unsigned int timestamp;
+ int n_evas;
+};
+
+struct _mouse_down_mouse_up
+{
+ int b;
+ Evas_Button_Flags flags;
+ unsigned int timestamp;
+ int n_evas;
+};
+
+struct _mouse_move
+{
+ int x;
+ int y;
+ unsigned int timestamp;
+ int n_evas;
+};
+
+struct _mouse_wheel
+{
+ int direction;
+ int z;
+ unsigned int timestamp;
+ int n_evas;
+};
+
+struct _key_down_key_up
+{
+ unsigned int timestamp;
+ const char *keyname;
+ const char *key;
+ const char *string;
+ const char *compose;
+ int n_evas;
+};
+
+struct _key_down_key_up_with_keycode
+{
+ unsigned int timestamp;
+ const char *keyname;
+ const char *key;
+ const char *string;
+ const char *compose;
+ int n_evas;
+ unsigned int keycode;
+};
+
+struct _multi_event
+{
+ int d;
+ int b; /* In case of simple mouse down/up, corresponds to the button */
+ int x;
+ int y;
+ double rad;
+ double radx;
+ double rady;
+ double pres;
+ double ang;
+ double fx;
+ double fy;
+ Evas_Button_Flags flags;
+ unsigned int timestamp;
+ int n_evas;
+};
+
+struct _multi_move
+{
+ int d;
+ int x;
+ int y;
+ double rad;
+ double radx;
+ double rady;
+ double pres;
+ double ang;
+ double fx;
+ double fy;
+ unsigned int timestamp;
+ int n_evas;
+};
+
+typedef struct _mouse_in_mouse_out mouse_in_mouse_out;
+typedef struct _mouse_down_mouse_up mouse_down_mouse_up;
+typedef struct _mouse_move mouse_move;
+typedef struct _mouse_wheel mouse_wheel;
+typedef struct _multi_event multi_event;
+typedef struct _multi_move multi_move;
+typedef struct _key_down_key_up key_down_key_up;
+typedef struct _key_down_key_up_with_keycode key_down_key_up_with_keycode;
+typedef struct _mouse_in_mouse_out take_screenshot;
+
+/* START - EET support typedefs */
+#define TSUITE_EVENT_MOUSE_IN_STR "tsuite_event_mouse_in"
+#define TSUITE_EVENT_MOUSE_OUT_STR "tsuite_event_mouse_out"
+#define TSUITE_EVENT_MOUSE_DOWN_STR "tsuite_event_mouse_down"
+#define TSUITE_EVENT_MOUSE_UP_STR "tsuite_event_mouse_up"
+#define TSUITE_EVENT_MOUSE_MOVE_STR "tsuite_event_mouse_move"
+#define TSUITE_EVENT_MOUSE_WHEEL_STR "tsuite_event_mouse_wheel"
+#define TSUITE_EVENT_MULTI_DOWN_STR "tsuite_event_multi_down"
+#define TSUITE_EVENT_MULTI_UP_STR "tsuite_event_multi_up"
+#define TSUITE_EVENT_MULTI_MOVE_STR "tsuite_event_multi_move"
+#define TSUITE_EVENT_KEY_DOWN_STR "tsuite_event_key_down"
+#define TSUITE_EVENT_KEY_UP_STR "tsuite_event_key_up"
+#define TSUITE_EVENT_KEY_DOWN_WITH_KEYCODE_STR "tsuite_event_key_down_with_keycode"
+#define TSUITE_EVENT_KEY_UP_WITH_KEYCODE_STR "tsuite_event_key_up_with_keycode"
+#define TSUITE_EVENT_TAKE_SHOT_STR "tsuite_event_take_shot"
+
+struct _Lists_st
+{
+ Eina_List *variant_list;
+ unsigned int first_timestamp;
+};
+typedef struct _Lists_st Lists_st;
+
+struct _data_desc
+{
+ Eet_Data_Descriptor *take_screenshot;
+ Eet_Data_Descriptor *mouse_in_mouse_out;
+ Eet_Data_Descriptor *mouse_down_mouse_up;
+ Eet_Data_Descriptor *mouse_move;
+ Eet_Data_Descriptor *mouse_wheel;
+ Eet_Data_Descriptor *multi_event;
+ Eet_Data_Descriptor *multi_move;
+ Eet_Data_Descriptor *key_down_key_up;
+ Eet_Data_Descriptor *key_down_key_up_with_keycode;
+
+ /* list, variant EET desc support */
+ Eet_Data_Descriptor *lists_descriptor;
+ Eet_Data_Descriptor *variant_descriptor;
+ Eet_Data_Descriptor *variant_unified_descriptor;
+};
+typedef struct _data_desc data_desc;
+/* END - EET support typedefs */
+
+static data_desc *_desc = NULL; /* this struct holds descs (alloc on init) */
+
+static eet_event_type_mapping eet_mapping[] = {
+ { TSUITE_EVENT_MOUSE_IN, TSUITE_EVENT_MOUSE_IN_STR },
+ { TSUITE_EVENT_MOUSE_OUT, TSUITE_EVENT_MOUSE_OUT_STR },
+ { TSUITE_EVENT_MOUSE_DOWN, TSUITE_EVENT_MOUSE_DOWN_STR },
+ { TSUITE_EVENT_MOUSE_UP, TSUITE_EVENT_MOUSE_UP_STR },
+ { TSUITE_EVENT_MOUSE_MOVE, TSUITE_EVENT_MOUSE_MOVE_STR },
+ { TSUITE_EVENT_MOUSE_WHEEL, TSUITE_EVENT_MOUSE_WHEEL_STR },
+ { TSUITE_EVENT_MULTI_DOWN, TSUITE_EVENT_MULTI_DOWN_STR },
+ { TSUITE_EVENT_MULTI_UP, TSUITE_EVENT_MULTI_UP_STR },
+ { TSUITE_EVENT_MULTI_MOVE, TSUITE_EVENT_MULTI_MOVE_STR },
+ { TSUITE_EVENT_KEY_DOWN, TSUITE_EVENT_KEY_DOWN_STR },
+ { TSUITE_EVENT_KEY_UP, TSUITE_EVENT_KEY_UP_STR },
+ { TSUITE_EVENT_KEY_DOWN_WITH_KEYCODE, TSUITE_EVENT_KEY_DOWN_WITH_KEYCODE_STR },
+ { TSUITE_EVENT_KEY_UP_WITH_KEYCODE, TSUITE_EVENT_KEY_UP_WITH_KEYCODE_STR },
+ { TSUITE_EVENT_TAKE_SHOT, TSUITE_EVENT_TAKE_SHOT_STR },
+ { TSUITE_EVENT_NOT_SUPPORTED, NULL }
+};
+
+static Tsuite_Event_Type
+_event_mapping_type_get(const char *name)
+{
+ int i;
+ for (i = 0; eet_mapping[i].name != NULL; ++i)
+ if (strcmp(name, eet_mapping[i].name) == 0)
+ return eet_mapping[i].t;
+
+ return TSUITE_EVENT_NOT_SUPPORTED;
+}
+
+static unsigned int
+_evt_time_get(unsigned int tm, Variant_st *v)
+{
+ if (!v) return tm;
+ switch(_event_mapping_type_get(v->t.type))
+ {
+ case TSUITE_EVENT_MOUSE_IN:
+ {
+ mouse_in_mouse_out *t = v->data;
+ return t->timestamp;
+ }
+ case TSUITE_EVENT_MOUSE_OUT:
+ {
+ mouse_in_mouse_out *t = v->data;
+ return t->timestamp;
+ }
+ case TSUITE_EVENT_MOUSE_DOWN:
+ {
+ mouse_down_mouse_up *t = v->data;
+ return t->timestamp;
+ }
+ case TSUITE_EVENT_MOUSE_UP:
+ {
+ mouse_down_mouse_up *t = v->data;
+ return t->timestamp;
+ }
+ case TSUITE_EVENT_MOUSE_MOVE:
+ {
+ mouse_move *t = v->data;
+ return t->timestamp;
+ }
+ case TSUITE_EVENT_MOUSE_WHEEL:
+ {
+ mouse_wheel *t = v->data;
+ return t->timestamp;
+ }
+ case TSUITE_EVENT_MULTI_DOWN:
+ {
+ multi_event *t = v->data;
+ return t->timestamp;
+ }
+ case TSUITE_EVENT_MULTI_UP:
+ {
+ multi_event *t = v->data;
+ return t->timestamp;
+ }
+ case TSUITE_EVENT_MULTI_MOVE:
+ {
+ multi_move *t = v->data;
+ return t->timestamp;
+ }
+ case TSUITE_EVENT_KEY_DOWN:
+ {
+ key_down_key_up *t = v->data;
+ return t->timestamp;
+ }
+ case TSUITE_EVENT_KEY_UP:
+ {
+ key_down_key_up *t = v->data;
+ return t->timestamp;
+ }
+ case TSUITE_EVENT_KEY_DOWN_WITH_KEYCODE:
+ {
+ key_down_key_up_with_keycode *t = v->data;
+ return t->timestamp;
+ }
+ case TSUITE_EVENT_KEY_UP_WITH_KEYCODE:
+ {
+ key_down_key_up_with_keycode *t = v->data;
+ return t->timestamp;
+ }
+ case TSUITE_EVENT_TAKE_SHOT:
+ {
+ take_screenshot *t = v->data;
+ return t->timestamp;
+ }
+ default: /* All non-input events are not handeled */
+ return tm;
+ break;
+ }
+}
+
+static Lists_st *
+_free_events(Lists_st *st)
+{
+ Variant_st *v;
+ if (!st) goto end;
+ EINA_LIST_FREE(st->variant_list, v)
+ {
+ free(v->data);
+ free(v);
+ }
+
+ free(st); /* Allocated when reading data from EET file */
+end:
+ return NULL;
+}
+
+static const char *
+_variant_type_get(const void *data, Eina_Bool *unknow)
+{
+ const Variant_Type_st *type = data;
+ int i;
+
+ if (unknow)
+ *unknow = type->unknow;
+
+ for (i = 0; eet_mapping[i].name != NULL; ++i)
+ if (strcmp(type->type, eet_mapping[i].name) == 0)
+ return eet_mapping[i].name;
+
+ if (unknow)
+ *unknow = EINA_FALSE;
+
+ return type->type;
+} /* _variant_type_get */
+
+static Eina_Bool
+_variant_type_set(const char *type,
+ void *data,
+ Eina_Bool unknow)
+{
+ Variant_Type_st *vt = data;
+
+ vt->type = type;
+ vt->unknow = unknow;
+ return EINA_TRUE;
+} /* _variant_type_set */
+
+/* START Event struct descriptors */
+static Eet_Data_Descriptor *
+_take_screenshot_desc_make(void)
+{
+ Eet_Data_Descriptor_Class eddc;
+ Eet_Data_Descriptor *_d;
+ EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddc, take_screenshot);
+ _d = eet_data_descriptor_stream_new(&eddc);
+
+ EET_DATA_DESCRIPTOR_ADD_BASIC(_d, take_screenshot, "timestamp",
+ timestamp, EET_T_UINT);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(_d, take_screenshot, "n_evas",
+ n_evas, EET_T_INT);
+
+ return _d;
+}
+
+static Eet_Data_Descriptor *
+_mouse_in_mouse_out_desc_make(void)
+{
+ Eet_Data_Descriptor_Class eddc;
+ Eet_Data_Descriptor *_d;
+ EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddc, mouse_in_mouse_out);
+ _d = eet_data_descriptor_stream_new(&eddc);
+
+ EET_DATA_DESCRIPTOR_ADD_BASIC(_d, mouse_in_mouse_out, "timestamp",
+ timestamp, EET_T_UINT);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(_d, mouse_in_mouse_out, "n_evas",
+ n_evas, EET_T_INT);
+
+ return _d;
+}
+
+static Eet_Data_Descriptor *
+_mouse_down_mouse_up_desc_make(void)
+{
+ Eet_Data_Descriptor_Class eddc;
+ Eet_Data_Descriptor *_d;
+ EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddc, mouse_down_mouse_up);
+ _d = eet_data_descriptor_stream_new(&eddc);
+
+ EET_DATA_DESCRIPTOR_ADD_BASIC(_d, mouse_down_mouse_up, "b", b, EET_T_INT);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(_d, mouse_down_mouse_up, "flags",
+ flags, EET_T_INT);
+
+ EET_DATA_DESCRIPTOR_ADD_BASIC(_d, mouse_down_mouse_up, "timestamp",
+ timestamp, EET_T_UINT);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(_d, mouse_down_mouse_up, "n_evas",
+ n_evas, EET_T_INT);
+
+ return _d;
+}
+
+static Eet_Data_Descriptor *
+_mouse_move_desc_make(void)
+{
+ Eet_Data_Descriptor_Class eddc;
+ Eet_Data_Descriptor *_d;
+ EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddc, mouse_move);
+ _d = eet_data_descriptor_stream_new(&eddc);
+
+ EET_DATA_DESCRIPTOR_ADD_BASIC(_d, mouse_move, "x", x, EET_T_INT);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(_d, mouse_move, "y", y, EET_T_INT);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(_d, mouse_move, "timestamp",
+ timestamp, EET_T_UINT);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(_d, mouse_move, "n_evas",
+ n_evas, EET_T_INT);
+
+ return _d;
+}
+
+static Eet_Data_Descriptor *
+_mouse_wheel_desc_make(void)
+{
+ Eet_Data_Descriptor_Class eddc;
+ Eet_Data_Descriptor *_d;
+ EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddc, mouse_wheel);
+ _d = eet_data_descriptor_stream_new(&eddc);
+
+ EET_DATA_DESCRIPTOR_ADD_BASIC(_d, mouse_wheel, "direction",
+ direction, EET_T_INT);
+
+ EET_DATA_DESCRIPTOR_ADD_BASIC(_d, mouse_wheel, "z", z, EET_T_INT);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(_d, mouse_wheel, "timestamp",
+ timestamp, EET_T_UINT);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(_d, mouse_wheel, "n_evas",
+ n_evas, EET_T_INT);
+
+ return _d;
+}
+
+static Eet_Data_Descriptor *
+_key_down_key_up_desc_make(void)
+{
+ Eet_Data_Descriptor_Class eddc;
+ Eet_Data_Descriptor *_d;
+ EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddc, key_down_key_up);
+ _d = eet_data_descriptor_stream_new(&eddc);
+
+ EET_DATA_DESCRIPTOR_ADD_BASIC(_d, key_down_key_up, "timestamp",
+ timestamp, EET_T_UINT);
+
+ EET_DATA_DESCRIPTOR_ADD_BASIC(_d, key_down_key_up, "keyname",
+ keyname, EET_T_STRING);
+
+ EET_DATA_DESCRIPTOR_ADD_BASIC(_d, key_down_key_up, "key",
+ key, EET_T_STRING);
+
+ EET_DATA_DESCRIPTOR_ADD_BASIC(_d, key_down_key_up, "string",
+ string, EET_T_STRING);
+
+ EET_DATA_DESCRIPTOR_ADD_BASIC(_d, key_down_key_up, "compose",
+ compose, EET_T_STRING);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(_d, key_down_key_up, "n_evas",
+ n_evas, EET_T_INT);
+
+ return _d;
+}
+
+static Eet_Data_Descriptor *
+_key_down_key_up_with_keycode_desc_make(void)
+{
+ Eet_Data_Descriptor_Class eddc;
+ Eet_Data_Descriptor *_d;
+ EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddc, key_down_key_up_with_keycode);
+ _d = eet_data_descriptor_stream_new(&eddc);
+
+ EET_DATA_DESCRIPTOR_ADD_BASIC(_d, key_down_key_up_with_keycode, "timestamp",
+ timestamp, EET_T_UINT);
+
+ EET_DATA_DESCRIPTOR_ADD_BASIC(_d, key_down_key_up_with_keycode, "keyname",
+ keyname, EET_T_STRING);
+
+ EET_DATA_DESCRIPTOR_ADD_BASIC(_d, key_down_key_up_with_keycode, "key",
+ key, EET_T_STRING);
+
+ EET_DATA_DESCRIPTOR_ADD_BASIC(_d, key_down_key_up_with_keycode, "string",
+ string, EET_T_STRING);
+
+ EET_DATA_DESCRIPTOR_ADD_BASIC(_d, key_down_key_up_with_keycode, "compose",
+ compose, EET_T_STRING);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(_d, key_down_key_up_with_keycode, "n_evas",
+ n_evas, EET_T_INT);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(_d, key_down_key_up_with_keycode, "keycode",
+ keycode, EET_T_INT);
+
+ return _d;
+}
+
+static Eet_Data_Descriptor *
+_multi_event_desc_make(void)
+{
+ Eet_Data_Descriptor_Class eddc;
+ Eet_Data_Descriptor *_d;
+ EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddc, multi_event);
+ _d = eet_data_descriptor_stream_new(&eddc);
+
+ EET_DATA_DESCRIPTOR_ADD_BASIC(_d, multi_event, "d", d, EET_T_UINT);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(_d, multi_event, "b", b, EET_T_UINT);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(_d, multi_event, "x", x, EET_T_UINT);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(_d, multi_event, "y", y, EET_T_UINT);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(_d, multi_event, "rad", rad, EET_T_DOUBLE);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(_d, multi_event, "radx", radx, EET_T_DOUBLE);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(_d, multi_event, "rady", rady, EET_T_DOUBLE);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(_d, multi_event, "pres", pres, EET_T_DOUBLE);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(_d, multi_event, "ang", ang, EET_T_DOUBLE);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(_d, multi_event, "fx", fx, EET_T_DOUBLE);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(_d, multi_event, "fy", fy, EET_T_DOUBLE);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(_d, multi_event, "flags", flags, EET_T_INT);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(_d, multi_event, "timestamp",
+ timestamp, EET_T_UINT);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(_d, multi_event, "n_evas",
+ n_evas, EET_T_INT);
+
+ return _d;
+}
+
+static Eet_Data_Descriptor *
+_multi_move_desc_make(void)
+{
+ Eet_Data_Descriptor_Class eddc;
+ Eet_Data_Descriptor *_d;
+ EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddc, multi_move);
+ _d = eet_data_descriptor_stream_new(&eddc);
+
+ EET_DATA_DESCRIPTOR_ADD_BASIC(_d, multi_move, "d", d, EET_T_UINT);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(_d, multi_move, "x", x, EET_T_UINT);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(_d, multi_move, "y", y, EET_T_UINT);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(_d, multi_move, "rad", rad, EET_T_DOUBLE);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(_d, multi_move, "radx", radx, EET_T_DOUBLE);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(_d, multi_move, "rady", rady, EET_T_DOUBLE);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(_d, multi_move, "pres", pres, EET_T_DOUBLE);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(_d, multi_move, "ang", ang, EET_T_DOUBLE);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(_d, multi_move, "fx", fx, EET_T_DOUBLE);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(_d, multi_move, "fy", fy, EET_T_DOUBLE);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(_d, multi_move, "timestamp",
+ timestamp, EET_T_UINT);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(_d, multi_move, "n_evas",
+ n_evas, EET_T_INT);
+
+ return _d;
+}
+
+/* declaring types */
+static data_desc *
+_data_descriptors_init(void)
+{
+ if (_desc) /* Was allocated */
+ return _desc;
+
+ _desc = calloc(1, sizeof(data_desc));
+
+ Eet_Data_Descriptor_Class eddc;
+
+ EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Lists_st);
+ _desc->lists_descriptor = eet_data_descriptor_file_new(&eddc);
+
+ _desc->take_screenshot = _take_screenshot_desc_make();
+ _desc->mouse_in_mouse_out = _mouse_in_mouse_out_desc_make();
+ _desc->mouse_down_mouse_up = _mouse_down_mouse_up_desc_make();
+ _desc->mouse_move = _mouse_move_desc_make();
+ _desc->mouse_wheel = _mouse_wheel_desc_make();
+ _desc->multi_event = _multi_event_desc_make();
+ _desc->multi_move = _multi_move_desc_make();
+ _desc->key_down_key_up = _key_down_key_up_desc_make();
+ _desc->key_down_key_up_with_keycode = _key_down_key_up_with_keycode_desc_make();
+
+ /* for variant */
+ EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Variant_st);
+ _desc->variant_descriptor = eet_data_descriptor_file_new(&eddc);
+
+ eddc.version = EET_DATA_DESCRIPTOR_CLASS_VERSION;
+ eddc.func.type_get = _variant_type_get;
+ eddc.func.type_set = _variant_type_set;
+ _desc->variant_unified_descriptor = eet_data_descriptor_stream_new(&eddc);
+
+ EET_DATA_DESCRIPTOR_ADD_MAPPING(_desc->variant_unified_descriptor,
+ TSUITE_EVENT_MOUSE_IN_STR, _desc->mouse_in_mouse_out);
+
+ EET_DATA_DESCRIPTOR_ADD_MAPPING(_desc->variant_unified_descriptor,
+ TSUITE_EVENT_MOUSE_OUT_STR, _desc->mouse_in_mouse_out);
+
+ EET_DATA_DESCRIPTOR_ADD_MAPPING(_desc->variant_unified_descriptor,
+ TSUITE_EVENT_MOUSE_DOWN_STR, _desc->mouse_down_mouse_up);
+
+ EET_DATA_DESCRIPTOR_ADD_MAPPING(_desc->variant_unified_descriptor,
+ TSUITE_EVENT_MOUSE_UP_STR, _desc->mouse_down_mouse_up);
+
+ EET_DATA_DESCRIPTOR_ADD_MAPPING(_desc->variant_unified_descriptor,
+ TSUITE_EVENT_MOUSE_MOVE_STR, _desc->mouse_move);
+
+ EET_DATA_DESCRIPTOR_ADD_MAPPING(_desc->variant_unified_descriptor,
+ TSUITE_EVENT_MOUSE_WHEEL_STR, _desc->mouse_wheel);
+
+ EET_DATA_DESCRIPTOR_ADD_MAPPING(_desc->variant_unified_descriptor,
+ TSUITE_EVENT_MULTI_DOWN_STR, _desc->multi_event);
+
+ EET_DATA_DESCRIPTOR_ADD_MAPPING(_desc->variant_unified_descriptor,
+ TSUITE_EVENT_MULTI_UP_STR, _desc->multi_event);
+
+ EET_DATA_DESCRIPTOR_ADD_MAPPING(_desc->variant_unified_descriptor,
+ TSUITE_EVENT_MULTI_MOVE_STR, _desc->multi_move);
+
+ EET_DATA_DESCRIPTOR_ADD_MAPPING(_desc->variant_unified_descriptor,
+ TSUITE_EVENT_KEY_DOWN_STR, _desc->key_down_key_up);
+
+ EET_DATA_DESCRIPTOR_ADD_MAPPING(_desc->variant_unified_descriptor,
+ TSUITE_EVENT_KEY_UP_STR, _desc->key_down_key_up);
+
+ EET_DATA_DESCRIPTOR_ADD_MAPPING(_desc->variant_unified_descriptor,
+ TSUITE_EVENT_KEY_DOWN_WITH_KEYCODE_STR, _desc->key_down_key_up_with_keycode);
+
+ EET_DATA_DESCRIPTOR_ADD_MAPPING(_desc->variant_unified_descriptor,
+ TSUITE_EVENT_KEY_UP_WITH_KEYCODE_STR, _desc->key_down_key_up_with_keycode);
+
+ EET_DATA_DESCRIPTOR_ADD_MAPPING(_desc->variant_unified_descriptor,
+ TSUITE_EVENT_TAKE_SHOT_STR, _desc->take_screenshot);
+
+
+ EET_DATA_DESCRIPTOR_ADD_VARIANT(_desc->variant_descriptor,
+ Variant_st, "data", data, t, _desc->variant_unified_descriptor);
+
+ EET_DATA_DESCRIPTOR_ADD_BASIC(_desc->lists_descriptor,
+ Lists_st, "first_timestamp", first_timestamp, EET_T_UINT);
+ EET_DATA_DESCRIPTOR_ADD_LIST(_desc->lists_descriptor,
+ Lists_st, "variant_list", variant_list, _desc->variant_descriptor);
+
+ return _desc;
+}
+
+static void
+_data_descriptors_shutdown(void)
+{
+ if (_desc)
+ {
+ eet_data_descriptor_free(_desc->mouse_in_mouse_out);
+ eet_data_descriptor_free(_desc->mouse_down_mouse_up);
+ eet_data_descriptor_free(_desc->mouse_move);
+ eet_data_descriptor_free(_desc->mouse_wheel);
+ eet_data_descriptor_free(_desc->multi_event);
+ eet_data_descriptor_free(_desc->multi_move);
+ eet_data_descriptor_free(_desc->key_down_key_up);
+ eet_data_descriptor_free(_desc->key_down_key_up_with_keycode);
+ eet_data_descriptor_free(_desc->take_screenshot);
+ eet_data_descriptor_free(_desc->lists_descriptor);
+ eet_data_descriptor_free(_desc->variant_descriptor);
+ eet_data_descriptor_free(_desc->variant_unified_descriptor);
+
+ free(_desc);
+ _desc = NULL;
+ /* FIXME: Should probably only init and shutdown once */
+ }
+}
+
+EAPI Exactness_Unit *
+legacy_rec_file_read(const char *filename)
+{
+ Lists_st *vr_list;
+ Eina_List *itr;
+ Variant_st *v, *prev_v = NULL;
+ Exactness_Unit *unit = NULL;
+ Eet_File *fp = eet_open(filename, EET_FILE_MODE_READ);
+ if (!fp)
+ {
+ printf("Failed to open input file <%s>.\n", filename);
+ return NULL;
+ }
+
+ /* Read events list */
+ _data_descriptors_init();
+ vr_list = eet_data_read(fp, _desc->lists_descriptor, CACHE_FILE_ENTRY);
+ eet_close(fp);
+ _data_descriptors_shutdown();
+
+ unit = calloc(1, sizeof(*unit));
+
+ EINA_LIST_FOREACH(vr_list->variant_list, itr, v)
+ {
+ Exactness_Action *act = calloc(1, sizeof(*act));
+ Tsuite_Event_Type old_type = _event_mapping_type_get(v->t.type);
+ unsigned int vtm = _evt_time_get(0, v);
+ if (!vtm) continue;
+ switch (old_type)
+ {
+ case TSUITE_EVENT_MOUSE_IN:
+ {
+ mouse_in_mouse_out *d_i = v->data;
+ act->type = EXACTNESS_ACTION_MOUSE_IN;
+ act->n_evas = d_i->n_evas;
+ break;
+ }
+ case TSUITE_EVENT_MOUSE_OUT:
+ {
+ mouse_in_mouse_out *d_i = v->data;
+ act->type = EXACTNESS_ACTION_MOUSE_OUT;
+ act->n_evas = d_i->n_evas;
+ break;
+ }
+ case TSUITE_EVENT_MOUSE_DOWN:
+ case TSUITE_EVENT_MOUSE_UP:
+ {
+ mouse_down_mouse_up *d_i = v->data;
+ Exactness_Action_Multi_Event *d_o = calloc(1, sizeof(*d_o));
+ d_o->b = d_i->b;
+ d_o->flags = d_i->flags;
+ if (old_type == TSUITE_EVENT_MOUSE_DOWN)
+ act->type = EXACTNESS_ACTION_MULTI_DOWN;
+ else
+ act->type = EXACTNESS_ACTION_MULTI_UP;
+ act->n_evas = d_i->n_evas;
+ act->data = d_o;
+ break;
+ }
+ case TSUITE_EVENT_MOUSE_MOVE:
+ {
+ mouse_move *d_i = v->data;
+ Exactness_Action_Multi_Move *d_o = calloc(1, sizeof(*d_o));
+ d_o->x = d_i->x;
+ d_o->y = d_i->y;
+ act->type = EXACTNESS_ACTION_MULTI_MOVE;
+ act->n_evas = d_i->n_evas;
+ act->data = d_o;
+ break;
+ }
+ case TSUITE_EVENT_MOUSE_WHEEL:
+ {
+ mouse_wheel *d_i = v->data;
+ Exactness_Action_Mouse_Wheel *d_o = calloc(1, sizeof(*d_o));
+ d_o->direction = d_i->direction;
+ d_o->z = d_i->z;
+ act->type = EXACTNESS_ACTION_MOUSE_WHEEL;
+ act->n_evas = d_i->n_evas;
+ act->data = d_o;
+ break;
+ }
+ case TSUITE_EVENT_MULTI_DOWN:
+ case TSUITE_EVENT_MULTI_UP:
+ {
+ multi_event *d_i = v->data;
+ Exactness_Action_Multi_Event *d_o = calloc(1, sizeof(*d_o));
+ d_o->d = d_i->d;
+ d_o->b = d_i->b;
+ d_o->x = d_i->x;
+ d_o->y = d_i->y;
+ d_o->rad = d_i->rad;
+ d_o->radx = d_i->radx;
+ d_o->rady = d_i->rady;
+ d_o->pres = d_i->pres;
+ d_o->ang = d_i->ang;
+ d_o->fx = d_i->fx;
+ d_o->fy = d_i->fy;
+ d_o->flags = d_i->flags;
+ if (old_type == TSUITE_EVENT_MULTI_DOWN)
+ act->type = EXACTNESS_ACTION_MULTI_DOWN;
+ else
+ act->type = EXACTNESS_ACTION_MULTI_UP;
+ act->n_evas = d_i->n_evas;
+ act->data = d_o;
+ break;
+ }
+ case TSUITE_EVENT_MULTI_MOVE:
+ {
+ multi_move *d_i = v->data;
+ Exactness_Action_Multi_Move *d_o = calloc(1, sizeof(*d_o));
+ d_o->d = d_i->d;
+ d_o->x = d_i->x;
+ d_o->y = d_i->y;
+ d_o->rad = d_i->rad;
+ d_o->radx = d_i->radx;
+ d_o->rady = d_i->rady;
+ d_o->pres = d_i->pres;
+ d_o->ang = d_i->ang;
+ d_o->fx = d_i->fx;
+ d_o->fy = d_i->fy;
+ act->type = EXACTNESS_ACTION_MULTI_MOVE;
+ act->n_evas = d_i->n_evas;
+ act->data = d_o;
+ break;
+ }
+ case TSUITE_EVENT_KEY_DOWN:
+ case TSUITE_EVENT_KEY_UP:
+ {
+ key_down_key_up *d_i = v->data;
+ Exactness_Action_Key_Down_Up *d_o = calloc(1, sizeof(*d_o));
+ d_o->keyname = d_i->keyname;
+ d_o->key = d_i->key;
+ d_o->string = d_i->string;
+ d_o->compose = d_i->compose;
+ if (old_type == TSUITE_EVENT_KEY_DOWN)
+ act->type = EXACTNESS_ACTION_KEY_DOWN;
+ else
+ act->type = EXACTNESS_ACTION_KEY_UP;
+ act->n_evas = d_i->n_evas;
+ act->data = d_o;
+ break;
+ }
+ case TSUITE_EVENT_KEY_DOWN_WITH_KEYCODE:
+ case TSUITE_EVENT_KEY_UP_WITH_KEYCODE:
+ {
+ key_down_key_up_with_keycode *d_i = v->data;
+ Exactness_Action_Key_Down_Up *d_o = calloc(1, sizeof(*d_o));
+ d_o->keyname = d_i->keyname;
+ d_o->key = d_i->key;
+ d_o->string = d_i->string;
+ d_o->compose = d_i->compose;
+ d_o->keycode = d_i->keycode;
+ if (old_type == TSUITE_EVENT_KEY_DOWN_WITH_KEYCODE)
+ act->type = EXACTNESS_ACTION_KEY_DOWN;
+ else
+ act->type = EXACTNESS_ACTION_KEY_UP;
+ act->n_evas = d_i->n_evas;
+ act->data = d_o;
+ break;
+ }
+ case TSUITE_EVENT_TAKE_SHOT:
+ {
+ take_screenshot *d_i = v->data;
+ act->type = EXACTNESS_ACTION_TAKE_SHOT;
+ act->n_evas = d_i->n_evas;
+ break;
+ }
+ default: break;
+ }
+ if (!prev_v)
+ {
+ if (vr_list->first_timestamp)
+ act->delay_ms = _evt_time_get(0, v) - vr_list->first_timestamp;
+ else
+ act->delay_ms = 0;
+ }
+ else
+ {
+ if (vtm > _evt_time_get(0, prev_v))
+ act->delay_ms = vtm - _evt_time_get(0, prev_v);
+ else act->delay_ms = 0;
+ }
+ unit->actions = eina_list_append(unit->actions, act);
+ prev_v = v;
+ }
+#ifdef DEBUG_TSUITE
+ printf("%s number of actions in the scenario <%d>\n", __func__, eina_list_count(unit->actions));
+#endif
+ _free_events(vr_list);
+
+ return unit;
+}
+
diff --git a/src/lib/exactness/meson.build b/src/lib/exactness/meson.build
new file mode 100644
index 0000000000..82929b301d
--- /dev/null
+++ b/src/lib/exactness/meson.build
@@ -0,0 +1,31 @@
+exactness_pub_deps = [eina, evas]
+exactness_deps = []
+
+exactness_src = [
+ 'Exactness.h',
+ 'exactness_private.h',
+ 'legacy_file.c',
+ 'unit.c'
+]
+
+exactness_lib = library('exactness', exactness_src,
+ dependencies: [ eina, eet, evas ],
+ install: true,
+ version : meson.project_version()
+)
+
+exactness = declare_dependency(
+ include_directories: include_directories('.'),
+ link_with : exactness_lib,
+ dependencies: [ eina, evas, eet ],
+)
+
+exactness_include_dir = join_paths(dir_data, 'exactness', 'include')
+
+exactness_header_src = [
+'Exactness.h',
+]
+
+install_headers(exactness_header_src,
+ install_dir : dir_package_include
+)
diff --git a/src/lib/exactness/unit.c b/src/lib/exactness/unit.c
new file mode 100644
index 0000000000..51f3453332
--- /dev/null
+++ b/src/lib/exactness/unit.c
@@ -0,0 +1,424 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <Eet.h>
+
+#include "Exactness.h"
+#include "exactness_private.h"
+
+typedef struct _Dummy
+{
+} _Dummy;
+/*
+static Eet_Data_Descriptor *
+_mouse_in_out_desc_make(void)
+{
+ Eet_Data_Descriptor_Class eddc;
+ Eet_Data_Descriptor *_d;
+ EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddc, Exactness_Action_Mouse_In_Out);
+ _d = eet_data_descriptor_stream_new(&eddc);
+
+ EET_DATA_DESCRIPTOR_ADD_BASIC(_d, Exactness_Action_Mouse_In_Out, "n_evas", n_evas, EET_T_INT);
+
+ return _d;
+}
+*/
+
+static Eet_Data_Descriptor *
+_mouse_wheel_desc_make(void)
+{
+ Eet_Data_Descriptor_Class eddc;
+ Eet_Data_Descriptor *_d;
+ EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddc, Exactness_Action_Mouse_Wheel);
+ _d = eet_data_descriptor_stream_new(&eddc);
+
+ EET_DATA_DESCRIPTOR_ADD_BASIC(_d, Exactness_Action_Mouse_Wheel, "direction", direction, EET_T_INT);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(_d, Exactness_Action_Mouse_Wheel, "z", z, EET_T_INT);
+
+ return _d;
+}
+
+static Eet_Data_Descriptor *
+_key_down_up_desc_make(void)
+{
+ Eet_Data_Descriptor_Class eddc;
+ Eet_Data_Descriptor *_d;
+ EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddc, Exactness_Action_Key_Down_Up);
+ _d = eet_data_descriptor_stream_new(&eddc);
+
+ EET_DATA_DESCRIPTOR_ADD_BASIC(_d, Exactness_Action_Key_Down_Up, "keyname", keyname, EET_T_STRING);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(_d, Exactness_Action_Key_Down_Up, "key", key, EET_T_STRING);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(_d, Exactness_Action_Key_Down_Up, "string", string, EET_T_STRING);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(_d, Exactness_Action_Key_Down_Up, "compose", compose, EET_T_STRING);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(_d, Exactness_Action_Key_Down_Up, "keycode", keycode, EET_T_INT);
+
+ return _d;
+}
+
+static Eet_Data_Descriptor *
+_multi_event_desc_make(void)
+{
+ Eet_Data_Descriptor_Class eddc;
+ Eet_Data_Descriptor *_d;
+ EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddc, Exactness_Action_Multi_Event);
+ _d = eet_data_descriptor_stream_new(&eddc);
+
+ EET_DATA_DESCRIPTOR_ADD_BASIC(_d, Exactness_Action_Multi_Event, "d", d, EET_T_UINT);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(_d, Exactness_Action_Multi_Event, "b", b, EET_T_UINT);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(_d, Exactness_Action_Multi_Event, "x", x, EET_T_UINT);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(_d, Exactness_Action_Multi_Event, "y", y, EET_T_UINT);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(_d, Exactness_Action_Multi_Event, "rad", rad, EET_T_DOUBLE);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(_d, Exactness_Action_Multi_Event, "radx", radx, EET_T_DOUBLE);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(_d, Exactness_Action_Multi_Event, "rady", rady, EET_T_DOUBLE);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(_d, Exactness_Action_Multi_Event, "pres", pres, EET_T_DOUBLE);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(_d, Exactness_Action_Multi_Event, "ang", ang, EET_T_DOUBLE);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(_d, Exactness_Action_Multi_Event, "fx", fx, EET_T_DOUBLE);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(_d, Exactness_Action_Multi_Event, "fy", fy, EET_T_DOUBLE);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(_d, Exactness_Action_Multi_Event, "flags", flags, EET_T_INT);
+
+ return _d;
+}
+
+static Eet_Data_Descriptor *
+_multi_move_desc_make(void)
+{
+ Eet_Data_Descriptor_Class eddc;
+ Eet_Data_Descriptor *_d;
+ EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddc, Exactness_Action_Multi_Move);
+ _d = eet_data_descriptor_stream_new(&eddc);
+
+ EET_DATA_DESCRIPTOR_ADD_BASIC(_d, Exactness_Action_Multi_Move, "d", d, EET_T_UINT);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(_d, Exactness_Action_Multi_Move, "x", x, EET_T_UINT);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(_d, Exactness_Action_Multi_Move, "y", y, EET_T_UINT);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(_d, Exactness_Action_Multi_Move, "rad", rad, EET_T_DOUBLE);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(_d, Exactness_Action_Multi_Move, "radx", radx, EET_T_DOUBLE);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(_d, Exactness_Action_Multi_Move, "rady", rady, EET_T_DOUBLE);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(_d, Exactness_Action_Multi_Move, "pres", pres, EET_T_DOUBLE);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(_d, Exactness_Action_Multi_Move, "ang", ang, EET_T_DOUBLE);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(_d, Exactness_Action_Multi_Move, "fx", fx, EET_T_DOUBLE);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(_d, Exactness_Action_Multi_Move, "fy", fy, EET_T_DOUBLE);
+
+ return _d;
+}
+
+static Eet_Data_Descriptor *
+_efl_event_desc_make(void)
+{
+ Eet_Data_Descriptor_Class eddc;
+ Eet_Data_Descriptor *_d;
+ EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddc, Exactness_Action_Efl_Event);
+ _d = eet_data_descriptor_stream_new(&eddc);
+
+ EET_DATA_DESCRIPTOR_ADD_BASIC(_d, Exactness_Action_Efl_Event, "wdg_name", wdg_name, EET_T_STRING);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(_d, Exactness_Action_Efl_Event, "event_name", event_name, EET_T_STRING);
+
+ return _d;
+}
+
+static Eet_Data_Descriptor *
+_click_on_desc_make(void)
+{
+ Eet_Data_Descriptor_Class eddc;
+ Eet_Data_Descriptor *_d;
+ EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddc, Exactness_Action_Click_On);
+ _d = eet_data_descriptor_stream_new(&eddc);
+
+ EET_DATA_DESCRIPTOR_ADD_BASIC(_d, Exactness_Action_Click_On, "wdg_name", wdg_name, EET_T_STRING);
+
+ return _d;
+}
+
+static Eet_Data_Descriptor *
+_dummy_desc_make(void)
+{
+ Eet_Data_Descriptor_Class eddc;
+ Eet_Data_Descriptor *_d;
+ EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddc, _Dummy);
+ _d = eet_data_descriptor_stream_new(&eddc);
+
+ return _d;
+}
+
+/* !!! SAME ORDER AS Exactness_Action_Type */
+static const char *_mapping[] =
+{
+ "",
+ "exactness_action_mouse_in",
+ "exactness_action_mouse_out",
+ "exactness_action_mouse_wheel",
+ "exactness_action_multi_down",
+ "exactness_action_multi_up",
+ "exactness_action_multi_move",
+ "exactness_action_key_down",
+ "exactness_action_key_up",
+ "exactness_action_take_shot",
+ "exactness_action_efl_event",
+ "exactness_action_click_on",
+ "exactness_action_stabilize"
+};
+
+const char *
+_exactness_action_type_to_string_get(Exactness_Action_Type type)
+{
+ if (type <= EXACTNESS_ACTION_LAST) return _mapping[type];
+ return NULL;
+}
+
+static const char *
+_variant_type_get(const void *data, Eina_Bool *unknow)
+{
+ const Exactness_Action *act = data;
+
+ if (unknow) *unknow = EINA_FALSE;
+ if (act->type <= EXACTNESS_ACTION_LAST) return _mapping[act->type];
+
+ return NULL;
+}
+
+static Eina_Bool
+_variant_type_set(const char *type,
+ void *data,
+ Eina_Bool unknow EINA_UNUSED)
+{
+ int i;
+ Exactness_Action *act = data;
+ for (i = 0; i <= EXACTNESS_ACTION_LAST; i++)
+ {
+ if (!strcmp(_mapping[i], type)) act->type = i;
+ }
+ return EINA_TRUE;
+}
+
+static Eet_Data_Descriptor *
+_unit_desc_make(void)
+{
+ Eet_Data_Descriptor_Class eddc;
+ static Eet_Data_Descriptor *unit_d = NULL;
+ static Eet_Data_Descriptor *action_d = NULL, *action_variant_d = NULL;
+ static Eet_Data_Descriptor *objs_d = NULL;
+ static Eet_Data_Descriptor *obj_d = NULL;
+ if (!obj_d)
+ {
+ EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddc, Exactness_Object);
+ obj_d = eet_data_descriptor_stream_new(&eddc);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(obj_d, Exactness_Object, "kl_name", kl_name, EET_T_STRING);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(obj_d, Exactness_Object, "id", id, EET_T_ULONG_LONG);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(obj_d, Exactness_Object, "parent_id", parent_id, EET_T_ULONG_LONG);
+ /* Evas stuff */
+ EET_DATA_DESCRIPTOR_ADD_BASIC(obj_d, Exactness_Object, "x", x, EET_T_INT);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(obj_d, Exactness_Object, "y", y, EET_T_INT);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(obj_d, Exactness_Object, "w", w, EET_T_INT);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(obj_d, Exactness_Object, "h", h, EET_T_INT);
+
+ EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddc, Exactness_Objects);
+ objs_d = eet_data_descriptor_stream_new(&eddc);
+ EET_DATA_DESCRIPTOR_ADD_LIST(objs_d, Exactness_Objects, "objs", objs, obj_d);
+ }
+ if (!unit_d)
+ {
+ Eet_Data_Descriptor *code_d = NULL;
+ EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddc, Exactness_Source_Code);
+ code_d = eet_data_descriptor_stream_new(&eddc);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(code_d, Exactness_Source_Code, "language", language, EET_T_STRING);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(code_d, Exactness_Source_Code, "content", content, EET_T_STRING);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(code_d, Exactness_Source_Code, "command", command, EET_T_STRING);
+
+ EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddc, Exactness_Action);
+ action_d = eet_data_descriptor_stream_new(&eddc);
+
+ eddc.version = EET_DATA_DESCRIPTOR_CLASS_VERSION;
+ eddc.func.type_get = _variant_type_get;
+ eddc.func.type_set = _variant_type_set;
+ action_variant_d = eet_data_descriptor_stream_new(&eddc);
+
+ EET_DATA_DESCRIPTOR_ADD_MAPPING(action_variant_d,
+ _mapping[EXACTNESS_ACTION_MOUSE_IN], _dummy_desc_make());
+ EET_DATA_DESCRIPTOR_ADD_MAPPING(action_variant_d,
+ _mapping[EXACTNESS_ACTION_MOUSE_OUT], _dummy_desc_make());
+ EET_DATA_DESCRIPTOR_ADD_MAPPING(action_variant_d,
+ _mapping[EXACTNESS_ACTION_MOUSE_WHEEL], _mouse_wheel_desc_make());
+ EET_DATA_DESCRIPTOR_ADD_MAPPING(action_variant_d,
+ _mapping[EXACTNESS_ACTION_MULTI_DOWN], _multi_event_desc_make());
+ EET_DATA_DESCRIPTOR_ADD_MAPPING(action_variant_d,
+ _mapping[EXACTNESS_ACTION_MULTI_UP], _multi_event_desc_make());
+ EET_DATA_DESCRIPTOR_ADD_MAPPING(action_variant_d,
+ _mapping[EXACTNESS_ACTION_MULTI_MOVE], _multi_move_desc_make());
+ EET_DATA_DESCRIPTOR_ADD_MAPPING(action_variant_d,
+ _mapping[EXACTNESS_ACTION_KEY_DOWN], _key_down_up_desc_make());
+ EET_DATA_DESCRIPTOR_ADD_MAPPING(action_variant_d,
+ _mapping[EXACTNESS_ACTION_KEY_UP], _key_down_up_desc_make());
+ EET_DATA_DESCRIPTOR_ADD_MAPPING(action_variant_d,
+ _mapping[EXACTNESS_ACTION_TAKE_SHOT], _dummy_desc_make());
+ EET_DATA_DESCRIPTOR_ADD_MAPPING(action_variant_d,
+ _mapping[EXACTNESS_ACTION_EFL_EVENT], _efl_event_desc_make());
+ EET_DATA_DESCRIPTOR_ADD_MAPPING(action_variant_d,
+ _mapping[EXACTNESS_ACTION_CLICK_ON], _click_on_desc_make());
+ EET_DATA_DESCRIPTOR_ADD_MAPPING(action_variant_d,
+ _mapping[EXACTNESS_ACTION_STABILIZE], _dummy_desc_make());
+
+ EET_DATA_DESCRIPTOR_ADD_BASIC(action_d, Exactness_Action, "n_evas", n_evas, EET_T_UINT);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(action_d, Exactness_Action, "delay_ms", delay_ms, EET_T_UINT);
+ EET_DATA_DESCRIPTOR_ADD_VARIANT(action_d, Exactness_Action, "data", data, type, action_variant_d);
+
+ /* Exactness_Unit */
+ EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddc, Exactness_Unit);
+ unit_d = eet_data_descriptor_stream_new(&eddc);
+ EET_DATA_DESCRIPTOR_ADD_LIST(unit_d, Exactness_Unit, "actions", actions, action_d);
+ EET_DATA_DESCRIPTOR_ADD_LIST(unit_d, Exactness_Unit, "objs", objs, objs_d);
+ EET_DATA_DESCRIPTOR_ADD_LIST(unit_d, Exactness_Unit, "codes", codes, code_d);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(unit_d, Exactness_Unit, "fonts_path", fonts_path, EET_T_STRING);
+ EET_DATA_DESCRIPTOR_ADD_BASIC(unit_d, Exactness_Unit, "nb_shots", nb_shots, EET_T_UINT);
+ }
+
+ return unit_d;
+}
+/* END Event struct descriptors */
+
+EAPI Exactness_Unit *
+exactness_unit_file_read(const char *filename)
+{
+ int i;
+ Eina_List *itr, *itr2;
+ Exactness_Objects *e_objs;
+ Exactness_Object *e_obj, *e_parent;
+ Exactness_Unit *unit = NULL;
+ Eet_File *file;
+ eet_init();
+ file = eet_open(filename, EET_FILE_MODE_READ);
+ if (!file)
+ {
+ fprintf(stderr, "Impossible to extract EET from %s\n", filename);
+ return NULL;
+ }
+ unit = eet_data_read(file, _unit_desc_make(), "cache");
+ for (i = 0; i < unit->nb_shots; i++)
+ {
+ char entry[32];
+ Exactness_Image *ex_img = malloc(sizeof(*ex_img));
+ sprintf(entry, "images/%d", i + 1);
+ ex_img->pixels = eet_data_image_read(file, entry,
+ &ex_img->w, &ex_img->h, NULL,
+ NULL, NULL, NULL);
+ unit->imgs = eina_list_append(unit->imgs, ex_img);
+ }
+ EINA_LIST_FOREACH(unit->objs, itr, e_objs)
+ {
+ Eina_Hash *hash = eina_hash_pointer_new(NULL);
+ EINA_LIST_FOREACH(e_objs->objs, itr2, e_obj)
+ {
+ eina_hash_set(hash, &(e_obj->id), e_obj);
+ }
+ EINA_LIST_FOREACH(e_objs->objs, itr2, e_obj)
+ {
+ if (!e_obj->parent_id)
+ e_objs->main_objs = eina_list_append(e_objs->main_objs, e_obj);
+ else
+ {
+ e_parent = eina_hash_find(hash, &(e_obj->parent_id));
+ if (e_parent) e_parent->children = eina_list_append(e_parent->children, e_obj);
+ }
+ }
+ eina_hash_free(hash);
+ }
+ eet_close(file);
+ eet_shutdown();
+ return unit;
+}
+
+EAPI Eina_Bool
+exactness_unit_file_write(Exactness_Unit *unit, const char *filename)
+{
+ Eina_List *itr;
+ Exactness_Image *ex_img;
+ Eet_File *file;
+ int i = 1;
+ eet_init();
+ file = eet_open(filename, EET_FILE_MODE_WRITE);
+ eet_data_write(file, _unit_desc_make(), "cache", unit, EINA_TRUE);
+ EINA_LIST_FOREACH(unit->imgs, itr, ex_img)
+ {
+ char entry[32];
+ sprintf(entry, "images/%d", i++);
+ eet_data_image_write(file, entry,
+ ex_img->pixels, ex_img->w, ex_img->h, 0xFF,
+ 0, 100, EET_IMAGE_LOSSLESS);
+ }
+ eet_close(file);
+ eet_shutdown();
+ return EINA_TRUE;
+}
+
+EAPI Eina_Bool
+exactness_image_compare(Exactness_Image *img1, Exactness_Image *img2, Exactness_Image **imgO)
+{
+ unsigned int w, h;
+ int *pxs1, *pxs2, *pxsO = NULL;
+ unsigned int w1 = img1 ? img1->w : 0, h1 = img1 ? img1->h : 0;
+ unsigned int w2 = img2 ? img2->w : 0, h2 = img2 ? img2->h : 0;
+ unsigned int wO = MAX(w1, w2);
+ unsigned int hO = MAX(h1, h2);
+ Eina_Bool ret = EINA_FALSE;
+ if (imgO) *imgO = NULL;
+ if (!wO || !hO) return EINA_FALSE;
+
+ pxs1 = img1 ? img1->pixels : NULL;
+ pxs2 = img2 ? img2->pixels : NULL;
+ if (imgO) pxsO = malloc(wO * hO * 4);
+
+ for (w = 0; w < wO; w++)
+ {
+ for (h = 0; h < hO; h++)
+ {
+ Eina_Bool valid1 = img1 ? w < w1 && h < h1 : EINA_FALSE;
+ Eina_Bool valid2 = img2 ? w < w2 && h < h2 : EINA_FALSE;
+ int px1 = valid1 ? pxs1[h * w1 + w] : 0;
+ int px2 = valid2 ? pxs2[h * w2 + w] : 0;
+ int r1 = (px1 & 0x00FF0000) >> 16;
+ int r2 = (px2 & 0x00FF0000) >> 16;
+ int g1 = (px1 & 0x0000FF00) >> 8;
+ int g2 = (px2 & 0x0000FF00) >> 8;
+ int b1 = (px1 & 0x000000FF);
+ int b2 = (px2 & 0x000000FF);
+ int new_r, new_g, new_b;
+ if (valid1 || valid2)
+ {
+ if (px1 != px2)
+ {
+ new_r = 0xFF;
+ new_g = ((g1 + g2) >> 1) >> 2;
+ new_b = ((b1 + b2) >> 1) >> 2;
+ ret = EINA_TRUE;
+ }
+ else
+ {
+ new_r = (((r1 + r2) >> 1) >> 2) + 0xC0;
+ new_g = (((g1 + g2) >> 1) >> 2) + 0xC0;
+ new_b = (((b1 + b2) >> 1) >> 2) + 0xC0;
+ }
+ }
+ else
+ {
+ new_r = new_g = new_b = 0x0;
+ }
+ if (pxsO) pxsO[h * wO + w] = 0xFF000000 | new_r << 16 | new_g << 8 | new_b;
+ }
+ }
+ if (imgO)
+ {
+ Exactness_Image *imgR = calloc(1, sizeof(Exactness_Image));
+ *imgO = imgR;
+ imgR->w = wO;
+ imgR->h = hO;
+ imgR->pixels = pxsO;
+ }
+ return ret;
+}
+
+EAPI void exactness_image_free(Exactness_Image *img)
+{
+ if (!img) return;
+ free(img->pixels);
+ free(img);
+}
+