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-01-17 14:38:49 +0100
commit130178898f74f24cc5375561ddd246ab8f7f5e88 (patch)
treed6708faa81fc3d3818bf8cfc10c2ff5900478ba5
parent478863862a4e669e652d2e6ed9b7204b39503a08 (diff)
downloadefl-130178898f74f24cc5375561ddd246ab8f7f5e88.tar.gz
Exactness: code importation
Differential Revision: https://phab.enlightenment.org/D7590
-rw-r--r--src/bin/exactness/.gitignore5
-rw-r--r--src/bin/exactness/exactness.c671
-rw-r--r--src/bin/exactness/injector.c483
-rw-r--r--src/bin/exactness/inspect.c1652
-rw-r--r--src/bin/exactness/player.c1383
-rw-r--r--src/bin/exactness/player_entry.edc932
-rw-r--r--src/bin/exactness/recorder.c529
-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/unit.c424
11 files changed, 7233 insertions, 0 deletions
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..189b21a090
--- /dev/null
+++ b/src/bin/exactness/exactness.c
@@ -0,0 +1,671 @@
+#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"
+
+#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..3d98d97127
--- /dev/null
+++ b/src/bin/exactness/inspect.c
@@ -0,0 +1,1652 @@
+#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 "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/player.c b/src/bin/exactness/player.c
new file mode 100644
index 0000000000..8d192b0cf9
--- /dev/null
+++ b/src/bin/exactness/player.c
@@ -0,0 +1,1383 @@
+#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>
+
+#include <sys/wait.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_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);
+ dprintf(tmp_fd,
+ "<?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);
+ 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);
+ waitpid(ecore_exe_pid_get(exe), &status, 0);
+ }
+ }
+ 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..ada17d2033
--- /dev/null
+++ b/src/bin/exactness/recorder.c
@@ -0,0 +1,529 @@
+#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_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);
+ dprintf(tmp_fd,
+ "<?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);
+ 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/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);
+}
+