summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Zaoui <daniel.zaoui@yahoo.com>2018-12-24 22:51:52 +0200
committerStefan Schmidt <s.schmidt@samsung.com>2020-02-05 10:09:14 +0100
commit12cc2a93dd282c37547d500258162e87cdd05339 (patch)
tree08cd71eba501061cc83013b5c4b405c83c926f9b
parent0d2e378942a5a1d3dec27fea27b3a17b5a3389b5 (diff)
exactness: import code from external repo into efl.git
Exactness has been developed in a separate git repo for many years. This finally moves it over into efl. Having it in tree allows us for easier testing with our current main target elementary_test and integration into our CI system (patches for this are work in progress already). We are only importing the lib and binary for test execution, not the full set of test data. This is would be over 500MB and thus it will stay in a different repo and only made available during the actual testing. [The original patch was made by Daniel Zaoui. Over the course of review and testing it got extended with build fixes for API changes and mingw compilation support from Stefan Schmidt and Michael Blumenkrantz] Differential Revision: https://phab.enlightenment.org/D11285
-rw-r--r--meson.build1
-rw-r--r--src/bin/exactness/.gitignore5
-rw-r--r--src/bin/exactness/exactness.c675
-rw-r--r--src/bin/exactness/injector.c483
-rw-r--r--src/bin/exactness/inspect.c1653
-rw-r--r--src/bin/exactness/meson.build42
-rw-r--r--src/bin/exactness/player.c1393
-rw-r--r--src/bin/exactness/player_entry.edc932
-rw-r--r--src/bin/exactness/recorder.c531
-rw-r--r--src/lib/exactness/Exactness.h268
-rw-r--r--src/lib/exactness/exactness_private.h10
-rw-r--r--src/lib/exactness/legacy_file.c876
-rw-r--r--src/lib/exactness/meson.build31
-rw-r--r--src/lib/exactness/unit.c424
14 files changed, 7324 insertions, 0 deletions
diff --git a/meson.build b/meson.build
index 5ee96f0f09..fb77c43570 100644
--- a/meson.build
+++ b/meson.build
@@ -335,6 +335,7 @@ subprojects = [
335['elua' ,['elua'] , false, true, true, false, true, false, ['eina', 'luajit'], []], 335['elua' ,['elua'] , false, true, true, false, true, false, ['eina', 'luajit'], []],
336['ecore_wayland' ,['wl-deprecated'] , false, true, false, false, false, false, ['eina'], []], 336['ecore_wayland' ,['wl-deprecated'] , false, true, false, false, false, false, ['eina'], []],
337['ecore_drm' ,['drm-deprecated'] , false, true, false, false, false, false, ['eina'], []], 337['ecore_drm' ,['drm-deprecated'] , false, true, false, false, false, false, ['eina'], []],
338['exactness' ,[] , false, true, true, false, false, false, ['eina, evas, eet'], []],
338] 339]
339 340
340# We generate Efl_Config.h and config.h later, they will be available here 341# We generate Efl_Config.h and config.h later, they will be available here
diff --git a/src/bin/exactness/.gitignore b/src/bin/exactness/.gitignore
new file mode 100644
index 0000000000..2760101039
--- /dev/null
+++ b/src/bin/exactness/.gitignore
@@ -0,0 +1,5 @@
1/exactness
2/exactness_inject
3/exactness_inspect
4/exactness_play
5/exactness_record
diff --git a/src/bin/exactness/exactness.c b/src/bin/exactness/exactness.c
new file mode 100644
index 0000000000..06c6097cf5
--- /dev/null
+++ b/src/bin/exactness/exactness.c
@@ -0,0 +1,675 @@
1#ifdef HAVE_CONFIG_H
2# include <config.h>
3#endif
4
5#include <Ecore.h>
6#include <Ecore_Getopt.h>
7#include <Ecore_Evas.h>
8#include <Ecore_File.h>
9
10#include "exactness_private.h"
11
12#ifdef _WIN32
13# include <evil_private.h> /* mkdir */
14#endif
15
16#define SCHEDULER_CMD_SIZE 1024
17
18#define ORIG_SUBDIR "orig"
19#define CURRENT_SUBDIR "current"
20
21#define EXACTNESS_PATH_MAX 1024
22
23#define BUF_SIZE 1024
24
25typedef struct
26{
27 EINA_INLIST;
28 char *name;
29 const char *command;
30} List_Entry;
31
32typedef enum
33{
34 RUN_SIMULATION,
35 RUN_PLAY,
36 RUN_INIT
37} Run_Mode;
38
39static unsigned short _running_jobs = 0, _max_jobs = 1;
40static Eina_List *_base_dirs = NULL;
41static char *_dest_dir;
42static char *_wrap_command = NULL, *_fonts_dir = NULL;
43static int _verbose = 0;
44static Eina_Bool _scan_objs = EINA_FALSE, _disable_screenshots = EINA_FALSE, _stabilize_shots = EINA_FALSE;
45
46static Run_Mode _mode;
47static List_Entry *_next_test_to_run = NULL;
48static unsigned int _tests_executed = 0;
49
50static Eina_List *_errors;
51static Eina_List *_compare_errors;
52
53static Eina_Bool _job_consume();
54
55static void
56_printf(int verbose, const char *fmt, ...)
57{
58 va_list ap;
59 if (!_verbose || verbose > _verbose) return;
60
61 va_start(ap, fmt);
62 vprintf(fmt, ap);
63 va_end(ap);
64}
65
66static Exactness_Image *
67_image_load(const char *filename)
68{
69 int w, h;
70 Evas_Load_Error err;
71 Ecore_Evas *ee = ecore_evas_new(NULL, 0, 0, 100, 100, NULL);
72 Eo *e = ecore_evas_get(ee);
73
74 Eo *img = evas_object_image_add(e);
75 evas_object_image_file_set(img, filename, NULL);
76 err = evas_object_image_load_error_get(img);
77 if (err != EVAS_LOAD_ERROR_NONE)
78 {
79 fprintf(stderr, "could not load image '%s'. error string is \"%s\"\n",
80 filename, evas_load_error_str(err));
81 return NULL;
82 }
83
84 Exactness_Image *ex_img = malloc(sizeof(*ex_img));
85 int len;
86 evas_object_image_size_get(img, &w, &h);
87 ex_img->w = w;
88 ex_img->h = h;
89 len = w * h * 4;
90 ex_img->pixels = malloc(len);
91 memcpy(ex_img->pixels, evas_object_image_data_get(img, EINA_FALSE), len);
92
93 ecore_evas_free(ee);
94 return ex_img;
95}
96
97static void
98_image_save(Exactness_Image *ex_img, const char *output)
99{
100 Ecore_Evas *ee;
101 Eo *e, *img;
102 ee = ecore_evas_new(NULL, 0, 0, 100, 100, NULL);
103 e = ecore_evas_get(ee);
104 img = evas_object_image_add(e);
105 evas_object_image_size_set(img, ex_img->w, ex_img->h);
106 evas_object_image_data_set(img, ex_img->pixels);
107 evas_object_image_save(img, output, NULL, NULL);
108 ecore_evas_free(ee);
109}
110
111static Eina_Bool
112_file_compare(const char *orig_dir, const char *ent_name)
113{
114 Eina_Bool result = EINA_FALSE;
115 Exactness_Image *img1, *img2, *imgO = NULL;
116 char *filename1 = alloca(strlen(orig_dir) + strlen(ent_name) + 20);
117 char *filename2 = alloca(strlen(_dest_dir) + strlen(ent_name) + 20);
118 sprintf(filename1, "%s/%s", orig_dir, ent_name);
119 sprintf(filename2, "%s/%s/%s", _dest_dir, CURRENT_SUBDIR, ent_name);
120
121 img1 = _image_load(filename1);
122 img2 = _image_load(filename2);
123
124 if (exactness_image_compare(img1, img2, &imgO))
125 {
126 char *buf = alloca(strlen(_dest_dir) + strlen(ent_name));
127 sprintf(buf, "%s/%s/comp_%s", _dest_dir, CURRENT_SUBDIR, ent_name);
128 _image_save(imgO, buf);
129 _compare_errors = eina_list_append(_compare_errors, strdup(ent_name));
130 result = EINA_TRUE;
131 }
132 exactness_image_free(img1);
133 exactness_image_free(img2);
134 exactness_image_free(imgO);
135 return result;
136}
137
138static void
139_exu_imgs_unpack(const char *exu_path, const char *dir, const char *ent_name)
140{
141 Exactness_Unit *unit = exactness_unit_file_read(exu_path);
142 Exactness_Image *img;
143 Eina_List *itr;
144 Ecore_Evas *ee = ecore_evas_new(NULL, 0, 0, 100, 100, NULL);
145 Eo *e = ecore_evas_get(ee);
146 int n = 1;
147 if (!unit) return;
148 EINA_LIST_FOREACH(unit->imgs, itr, img)
149 {
150 Eo *o = evas_object_image_add(e);
151 char *filename = alloca(strlen(dir) + strlen(ent_name) + 20);
152 snprintf(filename, EXACTNESS_PATH_MAX, "%s/%s%c%.3d.png",
153 dir, ent_name, SHOT_DELIMITER, n++);
154 evas_object_image_size_set(o, img->w, img->h);
155 evas_object_image_data_set(o, img->pixels);
156 if (!evas_object_image_save(o, filename, NULL, NULL))
157 {
158 printf("Cannot save widget to <%s>\n", filename);
159 }
160 efl_del(o);
161 }
162 efl_del(e);
163 ecore_evas_free(ee);
164}
165
166static void
167_run_test_compare(const List_Entry *ent)
168{
169 char *path = alloca(EXACTNESS_PATH_MAX);
170 char *origdir = alloca(strlen(_dest_dir) + 20);
171 const char *base_dir;
172 Eina_List *itr;
173 int n = 1, nb_fails = 0;
174 printf("STATUS %s: COMPARE\n", ent->name);
175 EINA_LIST_FOREACH(_base_dirs, itr, base_dir)
176 {
177 sprintf(path, "%s/%s.exu", base_dir, ent->name);
178 if (ecore_file_exists(path))
179 {
180 char *currentdir;
181 sprintf(origdir, "%s/%s/%s", _dest_dir, CURRENT_SUBDIR, ORIG_SUBDIR);
182 mkdir(origdir, 0744);
183 _exu_imgs_unpack(path, origdir, ent->name);
184 sprintf(path, "%s/%s/%s.exu", _dest_dir, CURRENT_SUBDIR, ent->name);
185 currentdir = alloca(strlen(_dest_dir) + 20);
186 sprintf(currentdir, "%s/%s", _dest_dir, CURRENT_SUBDIR);
187 _exu_imgs_unpack(path, currentdir, ent->name);
188 goto found;
189 }
190 else
191 {
192 sprintf(path, "%s/%s.rec", base_dir, ent->name);
193 if (ecore_file_exists(path))
194 {
195 sprintf(origdir, "%s/%s", _dest_dir, ORIG_SUBDIR);
196 goto found;
197 }
198 }
199 }
200found:
201 do
202 {
203 sprintf(path, "%s/%s%c%.3d.png", origdir, ent->name, SHOT_DELIMITER, n);
204 if (ecore_file_exists(path))
205 {
206 sprintf(path, "%s%c%.3d.png", ent->name, SHOT_DELIMITER, n);
207 if (_file_compare(origdir, path)) nb_fails++;
208 }
209 else break;
210 n++;
211 } while (EINA_TRUE);
212 if (!nb_fails)
213 printf("STATUS %s: END - SUCCESS\n", ent->name);
214 else
215 printf("STATUS %s: END - FAIL (%d/%d)\n", ent->name, nb_fails, n - 1);
216}
217
218#define CONFIG "ELM_SCALE=1 ELM_FINGER_SIZE=10 "
219static Eina_Bool
220_run_command_prepare(const List_Entry *ent, char *buf)
221{
222 char scn_path[EXACTNESS_PATH_MAX];
223 Eina_Strbuf *sbuf;
224 const char *base_dir;
225 Eina_List *itr;
226 Eina_Bool is_exu;
227 EINA_LIST_FOREACH(_base_dirs, itr, base_dir)
228 {
229 is_exu = EINA_TRUE;
230 sprintf(scn_path, "%s/%s.exu", base_dir, ent->name);
231 if (ecore_file_exists(scn_path)) goto ok;
232 else
233 {
234 is_exu = EINA_FALSE;
235 sprintf(scn_path, "%s/%s.rec", base_dir, ent->name);
236 if (ecore_file_exists(scn_path)) goto ok;
237 }
238 }
239 fprintf(stderr, "Test %s not found in the provided base directories\n", ent->name);
240 return EINA_FALSE;
241ok:
242 sbuf = eina_strbuf_new();
243 printf("STATUS %s: START\n", ent->name);
244 eina_strbuf_append_printf(sbuf,
245 "%s exactness_play %s %s%s %s%.*s %s%s%s-t '%s' ",
246 _wrap_command ? _wrap_command : "",
247 _mode == RUN_SIMULATION ? "-s" : "",
248 _fonts_dir ? "-f " : "", _fonts_dir ? _fonts_dir : "",
249 _verbose ? "-" : "", _verbose, "vvvvvvvvvv",
250 _scan_objs ? "--scan-objects " : "",
251 _disable_screenshots ? "--disable-screenshots " : "",
252 _stabilize_shots ? "--stabilize-shots " : "",
253 scn_path
254 );
255 if (is_exu)
256 {
257 if (_mode == RUN_PLAY)
258 eina_strbuf_append_printf(sbuf, "-o '%s/%s/%s.exu' ", _dest_dir, CURRENT_SUBDIR, ent->name);
259 if (_mode == RUN_INIT)
260 eina_strbuf_append_printf(sbuf, "-o '%s' ", scn_path);
261 }
262 else
263 {
264 if (_mode == RUN_PLAY)
265 eina_strbuf_append_printf(sbuf, "-o '%s/%s' ", _dest_dir, CURRENT_SUBDIR);
266 if (_mode == RUN_INIT)
267 eina_strbuf_append_printf(sbuf, "-o '%s/%s' ", _dest_dir, ORIG_SUBDIR);
268 }
269 if (ent->command)
270 {
271 eina_strbuf_append(sbuf, "-- ");
272 eina_strbuf_append(sbuf, CONFIG);
273 eina_strbuf_append(sbuf, ent->command);
274 }
275 strncpy(buf, eina_strbuf_string_get(sbuf), SCHEDULER_CMD_SIZE-1);
276 eina_strbuf_free(sbuf);
277 _printf(1, "Command: %s\n", buf);
278 return EINA_TRUE;
279}
280
281static void
282_job_compare(void *data)
283{
284 _run_test_compare(data);
285
286 _running_jobs--;
287 _job_consume();
288 /* If all jobs are done. */
289 if (!_running_jobs) ecore_main_loop_quit();
290}
291
292static Eina_Bool
293_job_deleted_cb(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
294{
295 Ecore_Exe_Event_Del *msg = (Ecore_Exe_Event_Del *) event;
296 List_Entry *ent = ecore_exe_data_get(msg->exe);
297
298 if ((msg->exit_code != 0) || (msg->exit_signal != 0))
299 {
300 _errors = eina_list_append(_errors, ent);
301 }
302
303 if (_mode == RUN_PLAY)
304 {
305 ecore_job_add(_job_compare, ent);
306 }
307 else
308 {
309 _running_jobs--;
310 _job_consume();
311 if (!_running_jobs) ecore_main_loop_quit();
312 }
313
314 return ECORE_CALLBACK_RENEW;
315}
316
317static Eina_Bool
318_job_consume()
319{
320 static Ecore_Event_Handler *job_del_callback_handler = NULL;
321 char buf[SCHEDULER_CMD_SIZE];
322 List_Entry *ent = _next_test_to_run;
323
324 if (_running_jobs == _max_jobs) return EINA_FALSE;
325 if (!ent) return EINA_FALSE;
326
327 if (_run_command_prepare(ent, buf))
328 {
329 _running_jobs++;
330 _tests_executed++;
331
332 if (!job_del_callback_handler)
333 {
334 job_del_callback_handler = ecore_event_handler_add(ECORE_EXE_EVENT_DEL,
335 _job_deleted_cb, NULL);
336 }
337
338 if (!ecore_exe_pipe_run(buf, ECORE_EXE_TERM_WITH_PARENT, ent))
339 {
340 fprintf(stderr, "Failed executing test '%s'\n", ent->name);
341 }
342 }
343 _next_test_to_run = EINA_INLIST_CONTAINER_GET(
344 EINA_INLIST_GET(ent)->next, List_Entry);
345
346
347 return EINA_TRUE;
348}
349
350static void
351_scheduler_run()
352{
353 while (_job_consume());
354}
355
356static List_Entry *
357_list_file_load(const char *filename)
358{
359 List_Entry *ret = NULL;
360 char buf[BUF_SIZE] = "";
361 FILE *file;
362 file = fopen(filename, "r");
363 if (!file)
364 {
365 perror("Failed opening list file");
366 return NULL;
367 }
368
369 while (fgets(buf, BUF_SIZE, file))
370 {
371 /* Skip comment/empty lines. */
372 if ((*buf == '#') || (*buf == '\n') || (!*buf))
373 continue;
374
375 char *tmp;
376 List_Entry *cur = calloc(1, sizeof(*cur));
377 cur->name = strdup(buf);
378
379 /* Set the command to the second half and put a \0 in between. */
380 tmp = strchr(cur->name, ' ');
381 if (tmp)
382 {
383 *tmp = '\0';
384 cur->command = tmp + 1;
385 }
386 else
387 {
388 /* FIXME: error. */
389 cur->command = "";
390 }
391
392 /* Replace the newline char with a \0. */
393 tmp = strchr(cur->command, '\n');
394 if (tmp)
395 {
396 *tmp = '\0';
397 }
398
399 ret = EINA_INLIST_CONTAINER_GET(
400 eina_inlist_append(EINA_INLIST_GET(ret), EINA_INLIST_GET(cur)),
401 List_Entry);
402 }
403
404 return ret;
405}
406
407static void
408_list_file_free(List_Entry *list)
409{
410 while (list)
411 {
412 List_Entry *ent = list;
413 list = EINA_INLIST_CONTAINER_GET(EINA_INLIST_GET(list)->next,
414 List_Entry);
415
416 free(ent->name);
417 free(ent);
418 /* we don't free ent->command because it's allocated together. */
419 }
420}
421
422static int
423_errors_sort_cb(List_Entry *a, List_Entry *b)
424{
425 return strcmp(a->name, b->name);
426}
427
428static const Ecore_Getopt optdesc = {
429 "exactness",
430 "%prog [options] <-r|-p|-i|-s> <list file>",
431 PACKAGE_VERSION,
432 "(C) 2013 Enlightenment",
433 "BSD",
434 "A pixel perfect test suite for EFL based applications.",
435 0,
436 {
437 ECORE_GETOPT_APPEND('b', "base-dir", "The location of the exu/rec files.", ECORE_GETOPT_TYPE_STR),
438 ECORE_GETOPT_STORE_STR('o', "output", "The location of the images."),
439 ECORE_GETOPT_STORE_STR('w', "wrap", "Use a custom command to launch the tests (e.g valgrind)."),
440 ECORE_GETOPT_STORE_USHORT('j', "jobs", "The number of jobs to run in parallel."),
441 ECORE_GETOPT_STORE_TRUE('p', "play", "Run in play mode."),
442 ECORE_GETOPT_STORE_TRUE('i', "init", "Run in init mode."),
443 ECORE_GETOPT_STORE_TRUE('s', "simulation", "Run in simulation mode."),
444 ECORE_GETOPT_STORE_TRUE(0, "scan-objects", "Extract information of all the objects at every shot."),
445 ECORE_GETOPT_STORE_TRUE(0, "disable-screenshots", "Disable screenshots."),
446 ECORE_GETOPT_STORE_STR('f', "fonts-dir", "Specify a directory of the fonts that should be used."),
447 ECORE_GETOPT_STORE_TRUE(0, "stabilize-shots", "Wait for the frames to be stable before taking the shots."),
448 ECORE_GETOPT_COUNT('v', "verbose", "Turn verbose messages on."),
449
450 ECORE_GETOPT_LICENSE('L', "license"),
451 ECORE_GETOPT_COPYRIGHT('C', "copyright"),
452 ECORE_GETOPT_VERSION('V', "version"),
453 ECORE_GETOPT_HELP('h', "help"),
454 ECORE_GETOPT_SENTINEL
455 }
456};
457
458int
459main(int argc, char *argv[])
460{
461 int ret = 0;
462 List_Entry *test_list;
463 int args = 0;
464 const char *list_file;
465 Eina_List *itr;
466 const char *base_dir;
467 char tmp[EXACTNESS_PATH_MAX];
468 Eina_Bool mode_play = EINA_FALSE, mode_init = EINA_FALSE, mode_simulation = EINA_FALSE;
469 Eina_Bool want_quit = EINA_FALSE, scan_objs = EINA_FALSE;
470 Ecore_Getopt_Value values[] = {
471 ECORE_GETOPT_VALUE_LIST(_base_dirs),
472 ECORE_GETOPT_VALUE_STR(_dest_dir),
473 ECORE_GETOPT_VALUE_STR(_wrap_command),
474 ECORE_GETOPT_VALUE_USHORT(_max_jobs),
475 ECORE_GETOPT_VALUE_BOOL(mode_play),
476 ECORE_GETOPT_VALUE_BOOL(mode_init),
477 ECORE_GETOPT_VALUE_BOOL(mode_simulation),
478 ECORE_GETOPT_VALUE_BOOL(scan_objs),
479 ECORE_GETOPT_VALUE_BOOL(_disable_screenshots),
480 ECORE_GETOPT_VALUE_STR(_fonts_dir),
481 ECORE_GETOPT_VALUE_BOOL(_stabilize_shots),
482 ECORE_GETOPT_VALUE_INT(_verbose),
483
484 ECORE_GETOPT_VALUE_BOOL(want_quit),
485 ECORE_GETOPT_VALUE_BOOL(want_quit),
486 ECORE_GETOPT_VALUE_BOOL(want_quit),
487 ECORE_GETOPT_VALUE_BOOL(want_quit),
488 ECORE_GETOPT_VALUE_NONE
489 };
490
491 ecore_init();
492 ecore_evas_init();
493 evas_init();
494 mode_play = mode_init = mode_simulation = EINA_FALSE;
495 want_quit = EINA_FALSE;
496 _dest_dir = "./";
497 _scan_objs = scan_objs;
498
499 args = ecore_getopt_parse(&optdesc, values, argc, argv);
500 if (args < 0)
501 {
502 fprintf(stderr, "Failed parsing arguments.\n");
503 ret = 1;
504 goto end;
505 }
506 else if (want_quit)
507 {
508 ret = 1;
509 goto end;
510 }
511 else if (args == argc)
512 {
513 fprintf(stderr, "Expected test list as the last argument..\n");
514 ecore_getopt_help(stderr, &optdesc);
515 ret = 1;
516 goto end;
517 }
518 else if (mode_play + mode_init + mode_simulation != 1)
519 {
520 fprintf(stderr, "At least and only one of the running modes can be set.\n");
521 ecore_getopt_help(stderr, &optdesc);
522 ret = 1;
523 goto end;
524 }
525
526 if (!_base_dirs) _base_dirs = eina_list_append(NULL, "./recordings");
527
528 list_file = argv[args];
529
530 /* Load the list file and start iterating over the records. */
531 test_list = _list_file_load(list_file);
532 _next_test_to_run = test_list;
533
534 if (!test_list)
535 {
536 fprintf(stderr, "No matching tests found in '%s'\n", list_file);
537 ret = 1;
538 goto end;
539 }
540
541 /* Pre-run summary */
542 fprintf(stderr, "Running with settings:\n");
543 fprintf(stderr, "\tConcurrent jobs: %d\n", _max_jobs);
544 fprintf(stderr, "\tTest list: %s\n", list_file);
545 fprintf(stderr, "\tBase dirs:\n");
546 EINA_LIST_FOREACH(_base_dirs, itr, base_dir)
547 fprintf(stderr, "\t\t%s\n", base_dir);
548 fprintf(stderr, "\tDest dir: %s\n", _dest_dir);
549
550 if (mode_play)
551 {
552 _mode = RUN_PLAY;
553 if (snprintf(tmp, EXACTNESS_PATH_MAX, "%s/%s", _dest_dir, CURRENT_SUBDIR)
554 >= EXACTNESS_PATH_MAX)
555 {
556 fprintf(stderr, "Path too long: %s", tmp);
557 ret = 1;
558 goto end;
559 }
560 mkdir(tmp, 0744);
561 }
562 else if (mode_init)
563 {
564 _mode = RUN_INIT;
565 if (snprintf(tmp, EXACTNESS_PATH_MAX, "%s/%s", _dest_dir, ORIG_SUBDIR)
566 >= EXACTNESS_PATH_MAX)
567 {
568 fprintf(stderr, "Path too long: %s", tmp);
569 ret = 1;
570 goto end;
571 }
572 mkdir(tmp, 0744);
573 }
574 else if (mode_simulation)
575 {
576 _mode = RUN_SIMULATION;
577 }
578 _scheduler_run();
579
580
581 ecore_main_loop_begin();
582
583 /* Results */
584 printf("*******************************************************\n");
585 if (mode_play && EINA_FALSE)
586 {
587 List_Entry *list_itr;
588
589 EINA_INLIST_FOREACH(test_list, list_itr)
590 {
591 _run_test_compare(list_itr);
592 }
593 }
594
595 printf("Finished executing %u out of %u tests.\n",
596 _tests_executed,
597 eina_inlist_count(EINA_INLIST_GET(test_list)));
598
599 /* Sort the errors and the compare_errors. */
600 _errors = eina_list_sort(_errors, 0, (Eina_Compare_Cb) _errors_sort_cb);
601 _compare_errors = eina_list_sort(_compare_errors, 0, (Eina_Compare_Cb) strcmp);
602
603 if (_errors || _compare_errors)
604 {
605 FILE *report_file;
606 char report_filename[EXACTNESS_PATH_MAX] = "";
607 /* Generate the filename. */
608 snprintf(report_filename, EXACTNESS_PATH_MAX,
609 "%s/%s/errors.html",
610 _dest_dir, mode_init ? ORIG_SUBDIR : CURRENT_SUBDIR);
611 report_file = fopen(report_filename, "w+");
612 if (report_file)
613 {
614 printf("%s %p\n", report_filename, report_file);
615 fprintf(report_file,
616 "<?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\">"
617 "<html xmlns=\"http://www.w3.org/1999/xhtml\"><head><title>Exactness report</title></head><body>");
618
619 if (_errors)
620 {
621 fprintf(report_file,
622 "<h1>Tests that failed execution:</h1><ul>");
623 List_Entry *ent;
624 printf("List of tests that failed execution:\n");
625 EINA_LIST_FOREACH(_errors, itr, ent)
626 {
627 printf("\t* %s\n", ent->name);
628
629 fprintf(report_file, "<li>%s</li>", ent->name);
630 }
631 fprintf(report_file, "</ul>");
632 }
633
634 if (_compare_errors)
635 {
636 fprintf(report_file,
637 "<h1>Images that failed comparison: (Original, Current, Diff)</h1><ul>");
638 char *test_name;
639 printf("List of images that failed comparison:\n");
640 EINA_LIST_FREE(_compare_errors, test_name)
641 {
642 Eina_Bool is_from_exu;
643 char origpath[EXACTNESS_PATH_MAX];
644 snprintf(origpath, EXACTNESS_PATH_MAX, "%s/%s/orig/%s",
645 _dest_dir, CURRENT_SUBDIR, test_name);
646 is_from_exu = ecore_file_exists(origpath);
647 printf("\t* %s\n", test_name);
648
649 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>",
650 test_name, is_from_exu ? "" : "../",
651 test_name, test_name, test_name);
652 free(test_name);
653 }
654 fprintf(report_file, "</ul>");
655 }
656 fprintf(report_file,
657 "</body></html>");
658
659 printf("Report html: %s\n", report_filename);
660 ret = 1;
661 }
662 else
663 {
664 perror("Failed opening report file");
665 }
666 }
667
668 _list_file_free(test_list);
669end:
670 evas_shutdown();
671 ecore_evas_shutdown();
672 ecore_shutdown();
673
674 return ret;
675}
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 @@
1#ifdef HAVE_CONFIG_H
2# include <config.h>
3#endif
4
5#include <stdio.h>
6#include <stdlib.h>
7#include <getopt.h>
8#include <unistd.h>
9
10#ifndef EFL_EO_API_SUPPORT
11#define EFL_EO_API_SUPPORT
12#endif
13#include <Eina.h>
14#include <Eet.h>
15#include <Ecore.h>
16#include <Ecore_Getopt.h>
17#include <Elementary.h>
18
19#include <Exactness.h>
20
21#include "exactness_private.h"
22
23typedef struct
24{
25 Eina_Debug_Session *session;
26 int srcid;
27 void *buffer;
28 unsigned int size;
29} _Main_Loop_Info;
30
31#define WRAPPER_TO_XFER_MAIN_LOOP(foo) \
32static void \
33_intern_main_loop ## foo(void *data) \
34{ \
35 _Main_Loop_Info *info = data; \
36 _main_loop ## foo(info->session, info->srcid, info->buffer, info->size); \
37 free(info->buffer); \
38 free(info); \
39} \
40static Eina_Bool \
41foo(Eina_Debug_Session *session, int srcid, void *buffer, int size) \
42{ \
43 _Main_Loop_Info *info = calloc(1, sizeof(*info)); \
44 info->session = session; \
45 info->srcid = srcid; \
46 info->size = size; \
47 if (info->size) \
48 { \
49 info->buffer = malloc(info->size); \
50 memcpy(info->buffer, buffer, info->size); \
51 } \
52 ecore_main_loop_thread_safe_call_async(_intern_main_loop ## foo, info); \
53 return EINA_TRUE; \
54}
55
56#ifndef WORDS_BIGENDIAN
57#define SWAP_64(x) x
58#define SWAP_32(x) x
59#define SWAP_16(x) x
60#define SWAP_DBL(x) x
61#else
62#define SWAP_64(x) eina_swap64(x)
63#define SWAP_32(x) eina_swap32(x)
64#define SWAP_16(x) eina_swap16(x)
65#define SWAP_DBL(x) SWAP_64(x)
66#endif
67
68#define EXTRACT_INT(_buf) \
69({ \
70 int __i; \
71 memcpy(&__i, _buf, sizeof(int)); \
72 _buf += sizeof(int); \
73 SWAP_32(__i); \
74})
75
76#define STORE_INT(_buf, __i) \
77{ \
78 int __i2 = SWAP_32(__i); \
79 memcpy(_buf, &__i2, sizeof(int)); \
80 _buf += sizeof(int); \
81}
82
83#define STORE_DOUBLE(_buf, __d) \
84{ \
85 double __d2 = SWAP_DBL(__d); \
86 memcpy(_buf, &__d2, sizeof(double)); \
87 _buf += sizeof(double); \
88}
89
90#define STORE_STRING(_buf, __s) \
91{ \
92 int __len = (__s ? strlen(__s) : 0) + 1; \
93 if (__s) memcpy(_buf, __s, __len); \
94 else *_buf = '\0'; \
95 _buf += __len; \
96}
97
98static Eina_Stringshare *_src_filename = NULL;
99static Exactness_Unit *_src_unit = NULL;
100static int _verbose = 0;
101
102static Eina_Debug_Session *_session = NULL;
103static int _cid = -1, _pid = -1;
104static Eina_List *_cur_event_list = NULL;
105
106static int _all_apps_get_op = EINA_DEBUG_OPCODE_INVALID;
107static int _mouse_in_op = EINA_DEBUG_OPCODE_INVALID;
108static int _mouse_out_op = EINA_DEBUG_OPCODE_INVALID;
109static int _mouse_wheel_op = EINA_DEBUG_OPCODE_INVALID;
110static int _multi_down_op = EINA_DEBUG_OPCODE_INVALID;
111static int _multi_up_op = EINA_DEBUG_OPCODE_INVALID;
112static int _multi_move_op = EINA_DEBUG_OPCODE_INVALID;
113static int _key_down_op = EINA_DEBUG_OPCODE_INVALID;
114static int _key_up_op = EINA_DEBUG_OPCODE_INVALID;
115static int _take_shot_op = EINA_DEBUG_OPCODE_INVALID;
116static int _efl_event_op = EINA_DEBUG_OPCODE_INVALID;
117static int _click_on_op = EINA_DEBUG_OPCODE_INVALID;
118static int _stabilize_op = EINA_DEBUG_OPCODE_INVALID;
119static int _finish_op = EINA_DEBUG_OPCODE_INVALID;
120
121static Eina_Bool _all_apps_get_cb(Eina_Debug_Session *, int , void *, int);
122
123EINA_DEBUG_OPCODES_ARRAY_DEFINE(_debug_ops,
124 {"Daemon/Client/register_observer", &_all_apps_get_op, NULL},
125 {"Daemon/Client/added", NULL, &_all_apps_get_cb},
126 {"Exactness/Actions/Mouse In", &_mouse_in_op, NULL},
127 {"Exactness/Actions/Mouse Out", &_mouse_out_op, NULL},
128 {"Exactness/Actions/Mouse Wheel", &_mouse_wheel_op, NULL},
129 {"Exactness/Actions/Multi Down", &_multi_down_op, NULL},
130 {"Exactness/Actions/Multi Up", &_multi_up_op, NULL},
131 {"Exactness/Actions/Multi Move", &_multi_move_op, NULL},
132 {"Exactness/Actions/Key Down", &_key_down_op, NULL},
133 {"Exactness/Actions/Key Up", &_key_up_op, NULL},
134 {"Exactness/Actions/Take Shot", &_take_shot_op, NULL},
135 {"Exactness/Actions/EFL Event", &_efl_event_op, NULL},
136 {"Exactness/Actions/Click On", &_click_on_op, NULL},
137 {"Exactness/Actions/Stabilize", &_stabilize_op, NULL},
138 {"Exactness/Actions/Finish", &_finish_op, NULL},
139 {NULL, NULL, NULL}
140 );
141
142static void
143_printf(int verbose, const char *fmt, ...)
144{
145 va_list ap;
146 if (!_verbose || verbose > _verbose) return;
147
148 va_start(ap, fmt);
149 vprintf(fmt, ap);
150 va_end(ap);
151}
152
153static void
154_feed_event(Exactness_Action_Type type, unsigned int n_evas, void *data)
155{
156 switch (type)
157 {
158 case EXACTNESS_ACTION_MOUSE_IN:
159 {
160 _printf(1, "Mouse in\n");
161 _printf(2, "%s evas_event_feed_mouse_in n_evas=<%d>\n", __func__, n_evas);
162 eina_debug_session_send(_session, _cid, _mouse_in_op, &n_evas, sizeof(int));
163 break;
164 }
165 case EXACTNESS_ACTION_MOUSE_OUT:
166 {
167 _printf(1, "Mouse out\n");
168 _printf(2, "%s evas_event_feed_mouse_out n_evas=<%d>\n", __func__, n_evas);
169 eina_debug_session_send(_session, _cid, _mouse_out_op, &n_evas, sizeof(int));
170 break;
171 }
172 case EXACTNESS_ACTION_MOUSE_WHEEL:
173 {
174 Exactness_Action_Mouse_Wheel *t = data;
175 int len = 3*sizeof(int);
176 char *buf = malloc(len), *tmp = buf;
177 _printf(1, "Mouse wheel\n");
178 _printf(2, "%s evas_event_feed_mouse_wheel n_evas=<%d>\n", __func__, n_evas);
179 STORE_INT(tmp, n_evas);
180 STORE_INT(tmp, t->direction);
181 STORE_INT(tmp, t->z);
182 eina_debug_session_send(_session, _cid, _mouse_wheel_op, buf, len);
183 break;
184 }
185 case EXACTNESS_ACTION_MULTI_DOWN:
186 case EXACTNESS_ACTION_MULTI_UP:
187 {
188 Exactness_Action_Multi_Event *t = data;
189 int len = 5*sizeof(int)+7*sizeof(double)+sizeof(int);
190 char *buf = malloc(len), *tmp = buf;
191 _printf(2, "%s %s n_evas=<%d>\n", __func__,
192 type == EXACTNESS_ACTION_MULTI_DOWN ? "evas_event_feed_multi_down" :
193 "evas_event_feed_multi_up", n_evas);
194 STORE_INT(tmp, n_evas);
195 STORE_INT(tmp, t->d);
196 STORE_INT(tmp, t->b);
197 STORE_INT(tmp, t->x);
198 STORE_INT(tmp, t->y);
199 STORE_DOUBLE(tmp, t->rad);
200 STORE_DOUBLE(tmp, t->radx);
201 STORE_DOUBLE(tmp, t->rady);
202 STORE_DOUBLE(tmp, t->pres);
203 STORE_DOUBLE(tmp, t->ang);
204 STORE_DOUBLE(tmp, t->fx);
205 STORE_DOUBLE(tmp, t->fy);
206 STORE_INT(tmp, t->flags);
207 eina_debug_session_send(_session, _cid,
208 type == EXACTNESS_ACTION_MULTI_DOWN ? _multi_down_op : _multi_up_op,
209 buf, len);
210 break;
211 }
212 case EXACTNESS_ACTION_MULTI_MOVE:
213 {
214 Exactness_Action_Multi_Move *t = data;
215 int len = 4*sizeof(int)+7*sizeof(double);
216 char *buf = malloc(len), *tmp = buf;
217 _printf(2, "%s evas_event_feed_multi_move n_evas=<%d>\n", __func__, n_evas);
218 STORE_INT(tmp, n_evas);
219 STORE_INT(tmp, t->d);
220 STORE_INT(tmp, t->x);
221 STORE_INT(tmp, t->y);
222 STORE_DOUBLE(tmp, t->rad);
223 STORE_DOUBLE(tmp, t->radx);
224 STORE_DOUBLE(tmp, t->rady);
225 STORE_DOUBLE(tmp, t->pres);
226 STORE_DOUBLE(tmp, t->ang);
227 STORE_DOUBLE(tmp, t->fx);
228 STORE_DOUBLE(tmp, t->fy);
229 eina_debug_session_send(_session, _cid, _multi_move_op, buf, len);
230 break;
231 }
232 case EXACTNESS_ACTION_KEY_DOWN:
233 case EXACTNESS_ACTION_KEY_UP:
234 {
235 Exactness_Action_Key_Down_Up *t = data;
236 int len = 2*sizeof(int) + 4;
237 len += t->keyname ? strlen(t->keyname) : 0;
238 len += t->key ? strlen(t->key) : 0;
239 len += t->string ? strlen(t->string) : 0;
240 len += t->compose ? strlen(t->compose) : 0;
241 char *buf = malloc(len), *tmp = buf;
242 _printf(2, "%s %s n_evas=<%d>\n", __func__,
243 type == EXACTNESS_ACTION_KEY_DOWN ? "evas_event_feed_key_down " :
244 "evas_event_feed_key_up", n_evas);
245 STORE_INT(tmp, n_evas);
246 STORE_STRING(tmp, t->keyname);
247 STORE_STRING(tmp, t->key);
248 STORE_STRING(tmp, t->string);
249 STORE_STRING(tmp, t->compose);
250 STORE_INT(tmp, t->keycode);
251 eina_debug_session_send(_session, _cid,
252 type == EXACTNESS_ACTION_KEY_DOWN ? _key_down_op : _key_up_op,
253 buf, len);
254 break;
255 }
256 case EXACTNESS_ACTION_TAKE_SHOT:
257 {
258 _printf(2, "%s take shot n_evas=<%d>\n", __func__, n_evas);
259 eina_debug_session_send(_session, _cid, _take_shot_op, &n_evas, sizeof(int));
260 break;
261 }
262 case EXACTNESS_ACTION_EFL_EVENT:
263 {
264 Exactness_Action_Efl_Event *t = data;
265 int len = 0;
266 len += t->wdg_name ? strlen(t->wdg_name) : 0;
267 len += t->event_name ? strlen(t->event_name) : 0;
268 char *buf = malloc(len), *tmp = buf;
269 _printf(2, "%s %s\n", __func__, "EFL event");
270 STORE_STRING(tmp, t->wdg_name);
271 STORE_STRING(tmp, t->event_name);
272 eina_debug_session_send(_session, _cid, _efl_event_op, buf, len);
273 break;
274 }
275 case EXACTNESS_ACTION_CLICK_ON:
276 {
277 Exactness_Action_Click_On *t = data;
278 int len = 0;
279 len += t->wdg_name ? strlen(t->wdg_name) : 0;
280 char *buf = malloc(len), *tmp = buf;
281 _printf(2, "%s %s\n", __func__, "Click On");
282 STORE_STRING(tmp, t->wdg_name);
283 eina_debug_session_send(_session, _cid, _click_on_op, buf, len);
284 break;
285 }
286 case EXACTNESS_ACTION_STABILIZE:
287 {
288 _printf(2, "%s stabilize\n", __func__);
289 eina_debug_session_send(_session, _cid, _stabilize_op, NULL, 0);
290 break;
291 }
292 default: /* All non-input events are not handeled */
293 break;
294 }
295}
296
297static Eina_Bool
298_feed_event_timer_cb(void *data EINA_UNUSED)
299{
300 Exactness_Action *act = eina_list_data_get(_cur_event_list);
301 _feed_event(act->type, act->n_evas, act->data);
302
303 _cur_event_list = eina_list_next(_cur_event_list);
304
305 if (!_cur_event_list)
306 { /* Finished reading all events */
307 eina_debug_session_send(_session, _cid, _finish_op, NULL, 0);
308 ecore_main_loop_quit();
309 }
310 else
311 {
312 Exactness_Action *cur_act = eina_list_data_get(_cur_event_list);
313 ecore_timer_add(cur_act->delay_ms / 1000.0, _feed_event_timer_cb, NULL);
314 }
315 return ECORE_CALLBACK_CANCEL;
316}
317
318static Eina_Bool
319_src_open()
320{
321 double diff_time = 0; /* Time to wait before feeding the first event */
322
323 _printf(2, "<%s> Source file is <%s>\n", __func__, _src_filename);
324 if (!strcmp(_src_filename + strlen(_src_filename) - 4,".exu"))
325 {
326 _src_unit = exactness_unit_file_read(_src_filename);
327 }
328 else if (!strcmp(_src_filename + strlen(_src_filename) - 4,".rec"))
329 {
330 _src_unit = legacy_rec_file_read(_src_filename);
331 }
332 if (!_src_unit) return EINA_FALSE;
333 _cur_event_list = _src_unit->actions;
334 Exactness_Action *act = eina_list_data_get(_cur_event_list);
335
336 if (act->delay_ms)
337 {
338 _printf(2, " Waiting <%f>\n", diff_time);
339 ecore_timer_add(act->delay_ms / 1000.0, _feed_event_timer_cb, NULL);
340 }
341 else
342 {
343 _feed_event_timer_cb(NULL);
344 }
345 return EINA_TRUE;
346}
347
348static void
349_main_loop_all_apps_get_cb(Eina_Debug_Session *session EINA_UNUSED, int srcid EINA_UNUSED, void *buffer, int size EINA_UNUSED)
350{
351 char *buf = buffer;
352 int chosen_cid = -1;
353 if (_cid != -1) return;
354 while (size > 0)
355 {
356 int cid, pid, len;
357 cid = EXTRACT_INT(buf);
358 pid = EXTRACT_INT(buf);
359 if (_pid != -1)
360 {
361 if (_pid == pid)
362 {
363 _cid = cid;
364 _src_open();
365 return;
366 }
367 }
368 else
369 {
370 if (!strcmp(buf, "exactness_play"))
371 {
372 if (chosen_cid != -1)
373 {
374 fprintf(stderr, "Need to specify a PID - too much choice\n");
375 return;
376 }
377 chosen_cid = cid;
378 }
379 }
380 len = strlen(buf) + 1;
381 buf += len;
382 size -= (2 * sizeof(int) + len);
383 }
384 if (chosen_cid != -1)
385 {
386 _cid = chosen_cid;
387 _src_open();
388 }
389}
390
391WRAPPER_TO_XFER_MAIN_LOOP(_all_apps_get_cb)
392
393static void
394_ops_ready_cb(void *data EINA_UNUSED, Eina_Bool status)
395{
396 static Eina_Bool on = EINA_FALSE;
397 if (status)
398 {
399 if (!on)
400 {
401 eina_debug_session_send(_session, 0, _all_apps_get_op, NULL, 0);
402 }
403 on = EINA_TRUE;
404 }
405}
406
407static const Ecore_Getopt optdesc = {
408 "exactness_inject",
409 "%prog [options] <-v|-p|-t|-h> command",
410 PACKAGE_VERSION,
411 "(C) 2018 Enlightenment",
412 "BSD",
413 "A scenario events injector for EFL based applications.",
414 1,
415 {
416 ECORE_GETOPT_STORE_STR('t', "test", "Test to run on the given application"),
417 ECORE_GETOPT_STORE_INT('p', "pid", "PID of the application to connect to"),
418 ECORE_GETOPT_STORE_INT('r', "remote-port", "Port to connect remotely to the daemon. Local connection if not specified"),
419 ECORE_GETOPT_COUNT('v', "verbose", "Turn verbose messages on."),
420
421 ECORE_GETOPT_LICENSE('L', "license"),
422 ECORE_GETOPT_COPYRIGHT('C', "copyright"),
423 ECORE_GETOPT_VERSION('V', "version"),
424 ECORE_GETOPT_HELP('h', "help"),
425 ECORE_GETOPT_SENTINEL
426 }
427};
428
429int main(int argc, char **argv)
430{
431 int opt_args = 0, real__ = 1, port = -1;
432 char *src = NULL;
433 Eina_Value *ret__;
434 Eina_Bool want_quit = EINA_FALSE;
435
436 Ecore_Getopt_Value values[] = {
437 ECORE_GETOPT_VALUE_STR(src),
438 ECORE_GETOPT_VALUE_INT(_pid),
439 ECORE_GETOPT_VALUE_INT(port),
440 ECORE_GETOPT_VALUE_INT(_verbose),
441
442 ECORE_GETOPT_VALUE_BOOL(want_quit),
443 ECORE_GETOPT_VALUE_BOOL(want_quit),
444 ECORE_GETOPT_VALUE_BOOL(want_quit),
445 ECORE_GETOPT_VALUE_BOOL(want_quit),
446 ECORE_GETOPT_VALUE_NONE
447 };
448
449 eina_init();
450 eet_init();
451 ecore_init();
452
453 opt_args = ecore_getopt_parse(&optdesc, values, argc, argv);
454 if (opt_args < 0)
455 {
456 fprintf(stderr, "Failed parsing arguments.\n");
457 goto end;
458 }
459 if (want_quit) goto end;
460
461 if (!src)
462 {
463 fprintf(stderr, "no test file specified\n");
464 goto end;
465 }
466 _src_filename = eina_stringshare_add(src);
467
468 if (port == -1)
469 _session = eina_debug_local_connect(EINA_TRUE);
470 else
471 _session = eina_debug_remote_connect(port);
472 eina_debug_opcodes_register(_session, _debug_ops(), _ops_ready_cb, NULL);
473
474 elm_init(argc, argv);
475 ret__ = efl_loop_begin(efl_main_loop_get());
476 real__ = efl_loop_exit_code_process(ret__);
477 elm_shutdown();
478end:
479 eet_shutdown();
480 eina_shutdown();
481 return real__;
482}
483
diff --git a/src/bin/exactness/inspect.c b/src/bin/exactness/inspect.c
new file mode 100644
index 0000000000..54f6627f22
--- /dev/null
+++ b/src/bin/exactness/inspect.c
@@ -0,0 +1,1653 @@
1#ifdef HAVE_CONFIG_H
2# include <config.h>
3#endif
4
5#ifndef EFL_BETA_API_SUPPORT
6#define EFL_BETA_API_SUPPORT
7#endif
8#ifndef EFL_EO_API_SUPPORT
9#define EFL_EO_API_SUPPORT
10#endif
11#include <Ecore.h>
12#include <Ecore_Getopt.h>
13#include <Ecore_Evas.h>
14#include <Elementary.h>
15#include <Exactness.h>
16#include <Efl_Ui.h>
17
18#include "exactness_private.h"
19
20#define LDIFF(x) "<b><color=#F0F>"#x"</color></b>"
21#define RDIFF(x) "<b><color=#0FF>"#x"</color></b>"
22
23typedef enum
24{
25 EX_FONTS_DIR,
26 EX_SCENARIO,
27 EX_IMAGE,
28 EX_OBJ_INFO
29} _Data_Type;
30
31typedef struct
32{
33 void *p1;
34 void *p2;
35 _Data_Type dt;
36} _Compare_Item_Data;
37
38typedef struct
39{
40 void *ex_parent;
41 Eo *gl_item;
42} _Item_Info;
43
44static Eo *_main_box = NULL;
45static Eina_List *_gls = NULL;
46static Eina_List *_units = NULL;
47static Eo *_comp_selected_item = NULL;
48
49static Elm_Genlist_Item_Class *_grp_itc = NULL, *_scn_itc = NULL, *_img_itc = NULL;
50static Elm_Genlist_Item_Class *_objs_itc = NULL, *_obj_itc = NULL;
51
52static Eina_Hash *_item_infos_hash = NULL;
53
54static Eina_Bool _show_only_diffs = EINA_FALSE;
55static Eina_List *_comp_vvs = NULL;
56
57static Eina_List *_modified_units = NULL;
58
59static const char *
60_action_name_get(Exactness_Action *act)
61{
62 if (!act) return NULL;
63 switch(act->type)
64 {
65 case EXACTNESS_ACTION_MOUSE_IN: return "Mouse In";
66 case EXACTNESS_ACTION_MOUSE_OUT: return "Mouse Out";
67 case EXACTNESS_ACTION_MOUSE_WHEEL: return "Mouse Wheel";
68 case EXACTNESS_ACTION_MULTI_DOWN: return "Multi Down";
69 case EXACTNESS_ACTION_MULTI_UP: return "Multi Up";
70 case EXACTNESS_ACTION_MULTI_MOVE: return "Multi Move";
71 case EXACTNESS_ACTION_KEY_DOWN: return "Key Down";
72 case EXACTNESS_ACTION_KEY_UP: return "Key Up";
73 case EXACTNESS_ACTION_TAKE_SHOT: return "Take shot";
74 case EXACTNESS_ACTION_EFL_EVENT: return "EFL Event";
75 case EXACTNESS_ACTION_CLICK_ON: return "Click On";
76 case EXACTNESS_ACTION_STABILIZE: return "Stabilize";
77 default: return NULL;
78 }
79}
80
81static int
82_event_struct_len_get(Exactness_Action_Type type)
83{
84 switch(type)
85 {
86 case EXACTNESS_ACTION_MOUSE_WHEEL:
87 return sizeof(Exactness_Action_Mouse_Wheel);
88 case EXACTNESS_ACTION_MULTI_DOWN:
89 case EXACTNESS_ACTION_MULTI_UP:
90 return sizeof(Exactness_Action_Multi_Event);
91 case EXACTNESS_ACTION_MULTI_MOVE:
92 return sizeof(Exactness_Action_Multi_Move);
93 case EXACTNESS_ACTION_KEY_DOWN:
94 case EXACTNESS_ACTION_KEY_UP:
95 return sizeof(Exactness_Action_Key_Down_Up);
96 case EXACTNESS_ACTION_EFL_EVENT:
97 return sizeof(Exactness_Action_Efl_Event);
98 case EXACTNESS_ACTION_CLICK_ON:
99 return sizeof(Exactness_Action_Click_On);
100 default: return 0;
101 }
102}
103
104static void
105_action_specific_info_get(const Exactness_Action *act, char output[1024])
106{
107 switch(act->type)
108 {
109 case EXACTNESS_ACTION_MOUSE_WHEEL:
110 {
111 Exactness_Action_Mouse_Wheel *t = act->data;
112 sprintf(output, "Direction %d Z %d", t->direction, t->z);
113 break;
114 }
115 case EXACTNESS_ACTION_MULTI_UP: case EXACTNESS_ACTION_MULTI_DOWN:
116 {
117 Exactness_Action_Multi_Event *t = act->data;
118 if (!t->d)
119 sprintf(output, "Button %d Flags %d", t->b, t->flags);
120 else
121 sprintf(output, "D %d X %d Y %d Rad %f RadX %f RadY %f Pres %f Ang %f FX %f FY %f Flags %d",
122 t->d, t->x, t->y, t->rad, t->radx, t->rady, t->pres, t->ang, t->fx, t->fy, t->flags);
123 break;
124 }
125 case EXACTNESS_ACTION_MULTI_MOVE:
126 {
127 Exactness_Action_Multi_Move *t = act->data;
128 if (!t->d)
129 sprintf(output, "X %d Y %d", t->x, t->y);
130 else
131 sprintf(output, "D %d X %d Y %d Rad %f RadX %f RadY %f Pres %f Ang %f FX %f FY %f",
132 t->d, t->x, t->y, t->rad, t->radx, t->rady, t->pres, t->ang, t->fx, t->fy);
133 break;
134 }
135 case EXACTNESS_ACTION_KEY_UP: case EXACTNESS_ACTION_KEY_DOWN:
136 {
137 Exactness_Action_Key_Down_Up *t = act->data;
138 sprintf(output, "Keyname %s Key %s String %s Compose %s Keycode %d",
139 t->keyname, t->key, t->string, t->compose, t->keycode);
140 break;
141 }
142 case EXACTNESS_ACTION_EFL_EVENT:
143 {
144 Exactness_Action_Efl_Event *t = act->data;
145 sprintf(output, "Widget %s Event %s", t->wdg_name, t->event_name);
146 break;
147 }
148 case EXACTNESS_ACTION_CLICK_ON:
149 {
150 Exactness_Action_Click_On *t = act->data;
151 sprintf(output, "Widget %s", t->wdg_name);
152 break;
153 }
154 default:
155 {
156 output[0] = '\0';
157 break;
158 }
159 }
160}
161
162static Eina_Bool
163_is_hook_duplicate(const Exactness_Action *cur_act, const Exactness_Action *prev_act)
164{
165 if (!prev_act) return EINA_FALSE;
166 if (cur_act->type == prev_act->type)
167 {
168 int len = _event_struct_len_get(cur_act->type);
169 return (!len || !memcmp(cur_act->data, prev_act->data, len));
170 }
171 return EINA_FALSE;
172}
173
174static Eina_Bool
175_are_scenario_entries_different(Exactness_Action *act1, Exactness_Action *act2)
176{
177 if (!act1 ^ !act2) return EINA_TRUE;
178 if (act1->type != act2->type) return EINA_TRUE;
179 switch(act1->type)
180 {
181 case EXACTNESS_ACTION_MOUSE_WHEEL:
182 return !!memcmp(act1->data, act2->data, sizeof(Exactness_Action_Mouse_Wheel));
183 case EXACTNESS_ACTION_MULTI_DOWN: case EXACTNESS_ACTION_MULTI_UP:
184 return !!memcmp(act1->data, act2->data, sizeof(Exactness_Action_Multi_Event));
185 case EXACTNESS_ACTION_MULTI_MOVE:
186 return !!memcmp(act1->data, act2->data, sizeof(Exactness_Action_Multi_Move));
187 case EXACTNESS_ACTION_KEY_UP: case EXACTNESS_ACTION_KEY_DOWN:
188 return !!memcmp(act1->data, act2->data, sizeof(Exactness_Action_Key_Down_Up));
189 case EXACTNESS_ACTION_EFL_EVENT:
190 {
191 Exactness_Action_Efl_Event *e1 = act1->data;
192 Exactness_Action_Efl_Event *e2 = act2->data;
193 return (!!strcmp(e1->wdg_name, e2->wdg_name) ||
194 !!strcmp(e1->event_name, e2->event_name));
195 }
196 case EXACTNESS_ACTION_CLICK_ON:
197 {
198 Exactness_Action_Click_On *e1 = act1->data;
199 Exactness_Action_Click_On *e2 = act2->data;
200 return (!!strcmp(e1->wdg_name, e2->wdg_name));
201 }
202 default:
203 return EINA_FALSE;
204 }
205 return EINA_FALSE;
206}
207
208static Eina_Bool
209_are_images_different(Exactness_Image *e_img1, Exactness_Image *e_img2)
210{
211 unsigned int w, h;
212 int *pxs1 = NULL;
213 int *pxs2 = NULL;
214 if (!e_img1 ^ !e_img2) return EINA_TRUE;
215 if (e_img1->w != e_img2->w) return EINA_TRUE;
216 if (e_img1->h != e_img2->h) return EINA_TRUE;
217 pxs1 = e_img1->pixels;
218 pxs2 = e_img2->pixels;
219 for (w = 0; w < e_img1->w; w++)
220 {
221 for (h = 0; h < e_img1->h; h++)
222 {
223 if (pxs1[h * e_img1->w + w] != pxs2[h * e_img1->w + w])
224 return EINA_TRUE;
225 }
226 }
227 return EINA_FALSE;
228}
229
230static Eina_Bool
231_are_objs_different(Exactness_Object *e_obj1, Exactness_Object *e_obj2, Eina_Bool check_objs)
232{
233 if (!e_obj1 ^ !e_obj2) return EINA_TRUE;
234 Eina_List *itr1 = e_obj1->children;
235 Eina_List *itr2 = e_obj2->children;
236 if (check_objs &&
237 (strcmp(e_obj1->kl_name, e_obj2->kl_name) ||
238 e_obj1->x != e_obj2->x || e_obj1->y != e_obj2->y ||
239 e_obj1->w != e_obj2->w || e_obj1->h != e_obj2->h)) return EINA_TRUE;
240 while (itr1 || itr2)
241 {
242 if ((!itr1) ^ (!itr2)) return EINA_TRUE;
243 e_obj1 = eina_list_data_get(itr1);
244 e_obj2 = eina_list_data_get(itr2);
245
246 if (_are_objs_different(e_obj1, e_obj2, EINA_TRUE)) return EINA_TRUE;
247
248 itr1 = eina_list_next(itr1);
249 itr2 = eina_list_next(itr2);
250 }
251 return EINA_FALSE;
252}
253
254static Eina_Bool
255_are_objs_trees_different(Exactness_Objects *e_objs1, Exactness_Objects *e_objs2)
256{
257 if (!e_objs1 ^ !e_objs2) return EINA_TRUE;
258 Eina_List *itr1 = e_objs1->objs;
259 Eina_List *itr2 = e_objs2->objs;
260 Exactness_Object *e_obj1, *e_obj2;
261 while (itr1 || itr2)
262 {
263 if ((!itr1) ^ (!itr2)) return EINA_TRUE;
264 e_obj1 = eina_list_data_get(itr1);
265 e_obj2 = eina_list_data_get(itr2);
266
267 if (_are_objs_different(e_obj1, e_obj2, EINA_TRUE)) return EINA_TRUE;
268
269 itr1 = eina_list_next(itr1);
270 itr2 = eina_list_next(itr2);
271 }
272 return EINA_FALSE;
273}
274
275static void
276_win_del(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info EINA_UNUSED)
277{
278 efl_exit(0); /* exit the program's main loop that runs in elm_run() */
279}
280
281static void
282_gui_win_create()
283{
284 Eo *win, *bg;
285
286 elm_policy_set(ELM_POLICY_QUIT, ELM_POLICY_QUIT_LAST_WINDOW_CLOSED);
287 win = elm_win_add(NULL, "Window", ELM_WIN_BASIC);
288 evas_object_smart_callback_add(win, "delete,request", _win_del, NULL);
289 elm_win_maximized_set(win, EINA_TRUE);
290 elm_win_autodel_set(win, EINA_TRUE);
291 elm_win_title_set(win, "Exactness Inspector");
292 efl_gfx_entity_size_set(win, EINA_SIZE2D(1000, 800));
293
294 bg = elm_bg_add(win);
295 evas_object_size_hint_weight_set(bg, 1.000000, 1.000000);
296 efl_gfx_entity_visible_set(bg, EINA_TRUE);
297 elm_win_resize_object_add(win, bg);
298
299 _main_box = elm_box_add(win);
300 elm_box_horizontal_set(_main_box, EINA_TRUE);
301 elm_box_homogeneous_set(_main_box, EINA_TRUE);
302 evas_object_size_hint_weight_set(_main_box, 1.000000, 1.000000);
303 efl_gfx_entity_visible_set(_main_box, EINA_TRUE);
304 elm_win_resize_object_add(win, _main_box);
305
306 efl_gfx_entity_visible_set(win, EINA_TRUE);
307}
308
309static char *
310_grp_text_get(void *data, Evas_Object *gl, const char *part EINA_UNUSED)
311{
312 char buf[256];
313 const char *str = NULL;
314 Eina_Bool compare = !!efl_key_data_get(gl, "_exactness_gl_compare");
315 _Data_Type dt = (_Data_Type) data;
316 switch (dt)
317 {
318 case EX_FONTS_DIR:
319 {
320 char buf2[256];
321 if (!compare)
322 {
323 Exactness_Unit *unit = efl_key_data_get(gl, "unit");
324 sprintf(buf2, "Fonts directory: %s", unit->fonts_path?unit->fonts_path:"None");
325 }
326 else
327 {
328 Eo *gl1 = eina_list_nth(_gls, 0);
329 Eo *gl2 = eina_list_nth(_gls, 1);
330 Exactness_Unit *unit1 = efl_key_data_get(gl1, "unit");
331 Exactness_Unit *unit2 = efl_key_data_get(gl2, "unit");
332 if (!!unit1->fonts_path ^ !!unit2->fonts_path)
333 sprintf(buf2, "Fonts directory comparison: XXXXX");
334 else if (!strcmp(unit1->fonts_path, unit2->fonts_path))
335 sprintf(buf2, "Fonts directory comparison: %s", unit1->fonts_path);
336 else
337 sprintf(buf2, "Fonts directory comparison: "LDIFF(%s)"/"RDIFF(%s),
338 unit1->fonts_path, unit2->fonts_path);
339 }
340 return strdup(buf2);
341 }
342 case EX_SCENARIO: { str = "Scenario"; break; }
343 case EX_IMAGE: { str = "Images"; break; }
344 case EX_OBJ_INFO: { str = "Objects"; break; }
345 default: { str = "Unknown"; break; }
346 }
347 sprintf(buf, "%s%s", str, compare ? " comparison" : "");
348 if (dt == EX_FONTS_DIR) eina_stringshare_del(str);
349 return strdup(buf);
350}
351
352static char *
353_scn_text_get(void *data, Evas_Object *gl, const char *part EINA_UNUSED)
354{
355 Eina_Strbuf *buf = eina_strbuf_new();
356 char *ret = NULL;
357 Eina_Bool compare = !!efl_key_data_get(gl, "_exactness_gl_compare");
358 if (compare)
359 {
360 _Compare_Item_Data *vv = data;
361 Exactness_Action *a1 = vv->p1;
362 Exactness_Action *a2 = vv->p2;
363
364 if (!a1 ^ !a2) return strdup("XXXXX");
365
366 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);
367 else eina_strbuf_append_printf(buf, "+%.3f: ", a1->delay_ms / 1000.0);
368
369 if (a1->type != a2->type)
370 eina_strbuf_append_printf(buf, "["LDIFF(%s)"/"RDIFF(%s)"] - XXXXXX", _action_name_get(a1), _action_name_get(a2));
371 else
372 {
373 char params1[1024];
374 char params2[2024];
375 _action_specific_info_get(a1, params1);
376 _action_specific_info_get(a2, params2);
377
378 eina_strbuf_append_printf(buf, "%s", _action_name_get(a1));
379 if (*params1 || *params2)
380 {
381 if (strcmp(params1, params2))
382 eina_strbuf_append_printf(buf, " - ["LDIFF(%s)"/"RDIFF(%s)"]", params1, params2);
383 else
384 eina_strbuf_append_printf(buf, " - %s", params1);
385 }
386 }
387 }
388 else
389 {
390 Exactness_Action *act = data;
391 char specific_output[1024];
392 if (act)
393 {
394 eina_strbuf_append_printf(buf, "+%.3f: ", act->delay_ms / 1000.0);
395 eina_strbuf_append_printf(buf, "%s", _action_name_get(act));
396 _action_specific_info_get(act, specific_output);
397 if (*specific_output) eina_strbuf_append_printf(buf, " - %s", specific_output);
398 }
399 else
400 eina_strbuf_append(buf, "XXXXX");
401 }
402
403 ret = eina_strbuf_string_steal(buf);
404 eina_strbuf_free(buf);
405 return ret;
406}
407
408static int
409_unit_shot_no_get(Exactness_Unit *unit, Exactness_Action *act_ref)
410{
411 Eina_List *itr;
412 Exactness_Action *act;
413 int ret = 0;
414 if (!unit) return -1;
415 EINA_LIST_FOREACH(unit->actions, itr, act)
416 {
417 if (act->type == EXACTNESS_ACTION_TAKE_SHOT)
418 {
419 if (act == act_ref) return ret;
420 ret++;
421 }
422 }
423 return -1;
424}
425
426static void
427_goto_shot(void *data EINA_UNUSED, Evas_Object *bt, void *event_info EINA_UNUSED)
428{
429 Eo *gl = efl_key_data_get(bt, "gl");
430 Eina_Bool compare = !!efl_key_data_get(gl, "_exactness_gl_compare");
431 if (compare)
432 {
433 _Compare_Item_Data *vv;
434 Eina_List *itr;
435 Eo *gl1 = eina_list_nth(_gls, 0);
436 Eo *gl2 = eina_list_nth(_gls, 1);
437 Exactness_Unit *unit1 = efl_key_data_get(gl1, "unit");
438 Exactness_Unit *unit2 = efl_key_data_get(gl2, "unit");
439 int shot1_no = (intptr_t)efl_key_data_get(bt, "shot1_no");
440 int shot2_no = (intptr_t)efl_key_data_get(bt, "shot2_no");
441 Exactness_Image *ex_img1 = shot1_no != -1 ? eina_list_nth(unit1->imgs, shot1_no) : NULL;
442 Exactness_Image *ex_img2 = shot2_no != -1 ? eina_list_nth(unit2->imgs, shot2_no) : NULL;
443 EINA_LIST_FOREACH(_comp_vvs, itr, vv)
444 {
445 if (vv->p1 == ex_img1 && vv->p2 == ex_img2)
446 {
447 _Item_Info *ii = eina_hash_find(_item_infos_hash, &vv);
448 if (ii && ii->gl_item)
449 elm_genlist_item_show(ii->gl_item, ELM_GENLIST_ITEM_SCROLLTO_MIDDLE);
450 }
451 }
452 }
453 else
454 {
455 Exactness_Unit *unit = efl_key_data_get(gl, "unit");
456 int shot_no = (intptr_t)efl_key_data_get(bt, "shot_no");
457 Exactness_Image *ex_img = shot_no != -1 ? eina_list_nth(unit->imgs, shot_no) : NULL;
458 _Item_Info *ii = eina_hash_find(_item_infos_hash, &ex_img);
459 if (ii && ii->gl_item)
460 elm_genlist_item_show(ii->gl_item, ELM_GENLIST_ITEM_SCROLLTO_MIDDLE);
461 }
462}
463
464static Evas_Object *
465_scn_content_get(void *data, Evas_Object *gl, const char *part)
466{
467 Eina_Bool compare = !!efl_key_data_get(gl, "_exactness_gl_compare");
468 if (compare)
469 {
470 if (!strcmp(part, "elm.swallow.end"))
471 {
472 _Compare_Item_Data *vv = data;
473 Exactness_Action *v1 = vv->p1;
474 Exactness_Action *v2 = vv->p2;
475 if (v1 && v2 && v1->type == EXACTNESS_ACTION_TAKE_SHOT &&
476 v2->type == EXACTNESS_ACTION_TAKE_SHOT)
477 {
478 Eo *gl1 = eina_list_nth(_gls, 0);
479 Eo *gl2 = eina_list_nth(_gls, 1);
480 Exactness_Unit *unit1 = efl_key_data_get(gl1, "unit");
481 Exactness_Unit *unit2 = efl_key_data_get(gl2, "unit");
482 int shot1_no = _unit_shot_no_get(unit1, v1);
483 int shot2_no = _unit_shot_no_get(unit2, v2);
484 Exactness_Image *ex_img1 = shot1_no != -1 ? eina_list_nth(unit1->imgs, shot1_no) : NULL;
485 Exactness_Image *ex_img2 = shot2_no != -1 ? eina_list_nth(unit2->imgs, shot2_no) : NULL;
486 Exactness_Image *ex_imgO = NULL;
487 exactness_image_compare(ex_img1, ex_img2, &ex_imgO);
488
489 if (ex_imgO)
490 {
491 Eo *bt, *ic, *evas_img;
492
493 bt = elm_button_add(gl);
494 evas_object_size_hint_weight_set(bt, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
495 evas_object_size_hint_align_set(bt, EVAS_HINT_FILL, EVAS_HINT_FILL);
496 evas_object_show(bt);
497 efl_key_data_set(bt, "gl", gl);
498 efl_key_data_set(bt, "shot1_no", (void *)(intptr_t)shot1_no);
499 efl_key_data_set(bt, "shot2_no", (void *)(intptr_t)shot2_no);
500 evas_object_smart_callback_add(bt, "clicked", _goto_shot, NULL);
501
502 ic = elm_icon_add(bt);
503 evas_img = elm_image_object_get(ic);
504 evas_object_image_size_set(evas_img, ex_imgO->w, ex_imgO->h);
505 evas_object_image_data_set(evas_img, ex_imgO->pixels);
506 evas_object_show(ic);
507 elm_object_part_content_set(bt, "icon", ic);
508 return bt;
509 }
510 }
511 }
512 }
513 else
514 {
515 if (!strcmp(part, "elm.swallow.end"))
516 {
517 Exactness_Action *v = data;
518 Exactness_Unit *unit = efl_key_data_get(gl, "unit");
519 int shot_no = _unit_shot_no_get(unit, v);
520 Exactness_Image *ex_img = shot_no != -1 ? eina_list_nth(unit->imgs, shot_no) : NULL;
521
522 if (ex_img)
523 {
524 Eo *bt, *ic, *evas_img;
525
526 bt = elm_button_add(gl);
527 evas_object_size_hint_weight_set(bt, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
528 evas_object_size_hint_align_set(bt, EVAS_HINT_FILL, EVAS_HINT_FILL);
529 evas_object_show(bt);
530 efl_key_data_set(bt, "gl", gl);
531 efl_key_data_set(bt, "shot_no", (void *)(intptr_t)shot_no);
532 evas_object_smart_callback_add(bt, "clicked", _goto_shot, NULL);
533
534 ic = elm_icon_add(bt);
535 evas_img = elm_image_object_get(ic);
536 evas_object_image_size_set(evas_img, ex_img->w, ex_img->h);
537 evas_object_image_data_set(evas_img, ex_img->pixels);
538 evas_object_show(ic);
539 elm_object_part_content_set(bt, "icon", ic);
540
541 return bt;
542 }
543 }
544 }
545 return NULL;
546}
547
548static Evas_Object *
549_img_content_get(void *data, Evas_Object *gl, const char *part)
550{
551 if (strcmp(part, "elm.swallow.content")) return NULL;
552 Eo *img = elm_image_add(gl);
553 Eo *evas_img = elm_image_object_get(img);
554 Eina_Bool compare = !!efl_key_data_get(gl, "_exactness_gl_compare");
555 if (compare)
556 {
557 _Compare_Item_Data *vv = data;
558 Exactness_Image *ex_img1 = vv->p1;
559 Exactness_Image *ex_img2 = vv->p2;
560 Exactness_Image *ex_imgO = NULL;
561 exactness_image_compare(ex_img1, ex_img2, &ex_imgO);
562
563 evas_object_image_size_set(evas_img, ex_imgO->w, ex_imgO->h);
564 evas_object_image_data_set(evas_img, ex_imgO->pixels);
565 evas_object_size_hint_min_set(img, ELM_SCALE_SIZE(300), ELM_SCALE_SIZE(300));
566 }
567 else
568 {
569 if (!data)
570 {
571 efl_del(img);
572 return NULL;
573 }
574 Exactness_Image *ex_img = data;
575 evas_object_image_size_set(evas_img, ex_img->w, ex_img->h);
576 evas_object_image_data_set(evas_img, ex_img->pixels);
577 evas_object_size_hint_min_set(img, ELM_SCALE_SIZE(300), ELM_SCALE_SIZE(300));
578 }
579 return img;
580}
581
582static char *
583_objs_text_get(void *data EINA_UNUSED, Evas_Object *obj EINA_UNUSED, const char *part EINA_UNUSED)
584{
585 return strdup("Shot");
586}
587
588static char *
589_obj_text_get(void *data, Evas_Object *gl, const char *part EINA_UNUSED)
590{
591 Eina_Strbuf *buf = eina_strbuf_new();
592 char *ret = NULL;
593 Eina_Bool compare = !!efl_key_data_get(gl, "_exactness_gl_compare");
594 if (compare)
595 {
596 _Compare_Item_Data *vv = data;
597 Exactness_Object *e_obj1 = vv->p1;
598 Exactness_Object *e_obj2 = vv->p2;
599 if ((!e_obj1 ^ !e_obj2) || strcmp(e_obj1->kl_name, e_obj2->kl_name))
600 eina_strbuf_append_printf(buf, "("LDIFF(%s)"/"RDIFF(%s)")",
601 e_obj1 ? e_obj1->kl_name : "XXXXX",
602 e_obj2 ? e_obj2->kl_name : "XXXXX");
603 else
604 eina_strbuf_append_printf(buf, "%s", e_obj1->kl_name);
605
606 eina_strbuf_append(buf, " x = ");
607 if ((!e_obj1 ^ !e_obj2) || e_obj1->x != e_obj2->x)
608 eina_strbuf_append_printf(buf, LDIFF(%d)"/"RDIFF(%d),
609 e_obj1 ? e_obj1->x : -1,
610 e_obj2 ? e_obj2->x : -1);
611 else
612 eina_strbuf_append_printf(buf, "%d", e_obj1->x);
613
614 eina_strbuf_append(buf, " y = ");
615 if ((!e_obj1 ^ !e_obj2) || e_obj1->y != e_obj2->y)
616 eina_strbuf_append_printf(buf, LDIFF(%d)"/"RDIFF(%d),
617 e_obj1 ? e_obj1->y : -1,
618 e_obj2 ? e_obj2->y : -1);
619 else
620 eina_strbuf_append_printf(buf, "%d", e_obj1->y);
621
622 eina_strbuf_append(buf, " w = ");
623 if ((!e_obj1 ^ !e_obj2) || e_obj1->w != e_obj2->w)
624 eina_strbuf_append_printf(buf, LDIFF(%d)"/"RDIFF(%d),
625 e_obj1 ? e_obj1->w : -1,
626 e_obj2 ? e_obj2->w : -1);
627 else
628 eina_strbuf_append_printf(buf, "%d", e_obj1->w);
629
630 eina_strbuf_append(buf, " h = ");
631 if ((!e_obj1 ^ !e_obj2) || e_obj1->h != e_obj2->h)
632 eina_strbuf_append_printf(buf, LDIFF(%d)"/"RDIFF(%d),
633 e_obj1 ? e_obj1->h : -1,
634 e_obj2 ? e_obj2->h : -1);
635 else
636 eina_strbuf_append_printf(buf, "%d", e_obj1->h);
637
638 if (e_obj1 && e_obj2 && _are_objs_different(e_obj1, e_obj2, EINA_FALSE))
639 eina_strbuf_append(buf, " - DIFF INSIDE");
640 }
641 else
642 {
643 Exactness_Object *e_obj = data;
644 eina_strbuf_append_printf(buf,
645 "%s: x = %d y = %d w = %d h = %d",
646 e_obj->kl_name,
647 e_obj->x, e_obj->y, e_obj->w, e_obj->h);
648 }
649
650 ret = eina_strbuf_string_steal(buf);
651 eina_strbuf_free(buf);
652 return ret;
653}
654
655static void
656_itc_init()
657{
658 if (!_grp_itc)
659 {
660 _grp_itc = elm_genlist_item_class_new();
661 _grp_itc->item_style = "group_index";
662 _grp_itc->func.text_get = _grp_text_get;
663 }
664
665 if (!_scn_itc)
666 {
667 _scn_itc = elm_genlist_item_class_new();
668 _scn_itc->item_style = "default_style";
669 _scn_itc->func.text_get = _scn_text_get;
670 _scn_itc->func.content_get = _scn_content_get;
671 }
672
673 if (!_img_itc)
674 {
675 _img_itc = elm_genlist_item_class_new();
676 _img_itc->item_style = "full";
677 _img_itc->func.content_get = _img_content_get;
678 }
679
680 if (!_objs_itc)
681 {
682 _objs_itc = elm_genlist_item_class_new();
683 _objs_itc->item_style = "default_style";
684 _objs_itc->func.text_get = _objs_text_get;
685 }
686
687 if (!_obj_itc)
688 {
689 _obj_itc = elm_genlist_item_class_new();
690 _obj_itc->item_style = "default_style";
691 _obj_itc->func.text_get = _obj_text_get;
692 }
693}
694
695static void
696_comp_gl_dragged_cb(Evas_Object *obj, void *data EINA_UNUSED)
697{
698 int x = 0, y = 0;
699 Eo *gl;
700 Eina_List *itr;
701 elm_interface_scrollable_content_pos_get(obj, &x, &y);
702 EINA_LIST_FOREACH(_gls, itr, gl)
703 {
704 if (gl != obj)
705 elm_interface_scrollable_content_pos_set(gl, x, y, EINA_FALSE);
706 }
707}
708
709static void
710_obj_item_realize(Exactness_Object *ex_obj)
711{
712 _Item_Info *ii = eina_hash_find(_item_infos_hash, &ex_obj);
713 if (!ii) return;
714 if (ii->gl_item) return;
715 _obj_item_realize(ii->ex_parent);
716 _Item_Info *iip = eina_hash_find(_item_infos_hash, &(ii->ex_parent));
717 if (iip->gl_item) elm_genlist_item_expanded_set(iip->gl_item, EINA_TRUE);
718}
719
720static void
721_gl_expand_request_cb(void *data EINA_UNUSED, Evas_Object *gl, void *event_info)
722{
723 Elm_Object_Item *glit = event_info;
724 Eina_Bool compare = !!efl_key_data_get(gl, "_exactness_gl_compare");
725 if (compare)
726 {
727 const Elm_Genlist_Item_Class *itc = elm_genlist_item_item_class_get(glit);
728 if (itc == _objs_itc)
729 {
730 _Compare_Item_Data *vv = elm_object_item_data_get(glit);
731 _Item_Info *ii = eina_hash_find(_item_infos_hash, &(vv->p1));
732 if (ii) elm_genlist_item_expanded_set(ii->gl_item, EINA_TRUE);
733 ii = eina_hash_find(_item_infos_hash, &(vv->p2));
734 if (ii) elm_genlist_item_expanded_set(ii->gl_item, EINA_TRUE);
735 }
736 else if (itc == _obj_itc)
737 {
738 _Compare_Item_Data *vv = elm_object_item_data_get(glit);
739 _Item_Info *ii = eina_hash_find(_item_infos_hash, &(vv->p1));
740 if (!ii || !ii->gl_item) _obj_item_realize(vv->p1);
741 if (!ii) ii = eina_hash_find(_item_infos_hash, &(vv->p1));
742 if (ii && ii->gl_item) elm_genlist_item_expanded_set(ii->gl_item, EINA_TRUE);
743
744 ii = eina_hash_find(_item_infos_hash, &(vv->p2));
745 if (!ii || !ii->gl_item) _obj_item_realize(vv->p2);
746 if (!ii) ii = eina_hash_find(_item_infos_hash, &(vv->p2));
747 if (ii && ii->gl_item) elm_genlist_item_expanded_set(ii->gl_item, EINA_TRUE);
748 }
749 }
750 elm_genlist_item_expanded_set(glit, EINA_TRUE);
751}
752
753static void
754_gl_contract_request_cb(void *data EINA_UNUSED, Evas_Object *gl EINA_UNUSED, void *event_info)
755{
756 Elm_Object_Item *glit = event_info;
757 Eina_Bool compare = !!efl_key_data_get(gl, "_exactness_gl_compare");
758 if (compare)
759 {
760 const Elm_Genlist_Item_Class *itc = elm_genlist_item_item_class_get(glit);
761 if (itc == _objs_itc)
762 {
763 _Compare_Item_Data *vv = elm_object_item_data_get(glit);
764 _Item_Info *ii = eina_hash_find(_item_infos_hash, &(vv->p1));
765 if (ii) elm_genlist_item_expanded_set(ii->gl_item, EINA_FALSE);
766 ii = eina_hash_find(_item_infos_hash, &(vv->p2));
767 if (ii) elm_genlist_item_expanded_set(ii->gl_item, EINA_FALSE);
768 }
769 else if (itc == _obj_itc)
770 {
771 _Compare_Item_Data *vv = elm_object_item_data_get(glit);
772 _Item_Info *ii = eina_hash_find(_item_infos_hash, &(vv->p1));
773 if (ii && ii->gl_item) elm_genlist_item_expanded_set(ii->gl_item, EINA_FALSE);
774
775 ii = eina_hash_find(_item_infos_hash, &(vv->p2));
776 if (ii && ii->gl_item) elm_genlist_item_expanded_set(ii->gl_item, EINA_FALSE);
777 }
778 }
779 elm_genlist_item_expanded_set(glit, EINA_FALSE);
780}
781
782static void
783_gl_expanded_cb(void *_data EINA_UNUSED, Evas_Object *gl EINA_UNUSED, void *event_info)
784{
785 Elm_Object_Item *glit = event_info;
786 const Elm_Genlist_Item_Class *itc = elm_genlist_item_item_class_get(glit);
787 Eina_Bool compare = !!efl_key_data_get(gl, "_exactness_gl_compare");
788 if (itc == _objs_itc)
789 {
790 if (compare)
791 {
792 _Compare_Item_Data *vv = elm_object_item_data_get(glit);
793 Exactness_Objects *e_objs1 = vv->p1;
794 Exactness_Objects *e_objs2 = vv->p2;
795 Eina_List *itr1 = e_objs1->main_objs, *itr2 = e_objs2->main_objs;
796
797 while (itr1 || itr2)
798 {
799 Exactness_Object *e_obj1 = eina_list_data_get(itr1);
800 Exactness_Object *e_obj2 = eina_list_data_get(itr2);
801 vv = calloc(1, sizeof(*vv));
802 vv->p1 = e_obj1;
803 vv->p2 = e_obj2;
804 vv->dt = EX_OBJ_INFO;
805 elm_genlist_item_append(gl, _obj_itc, vv, glit,
806 e_obj1->children || e_obj2->children ? ELM_GENLIST_ITEM_TREE : ELM_GENLIST_ITEM_NONE,
807 NULL, NULL);
808 itr1 = eina_list_next(itr1);
809 itr2 = eina_list_next(itr2);
810 }
811 }
812 else
813 {
814 Exactness_Objects *e_objs = elm_object_item_data_get(glit);
815 Eina_List *itr;
816 Exactness_Object *e_obj;
817 EINA_LIST_FOREACH(e_objs->main_objs, itr, e_obj)
818 {
819 _Item_Info *ii = eina_hash_find(_item_infos_hash, &e_obj);
820 if (!ii)
821 {
822 ii = calloc(1, sizeof(*ii));
823 eina_hash_set(_item_infos_hash, &e_obj, ii);
824 }
825 ii->ex_parent = e_objs;
826 ii->gl_item = elm_genlist_item_append(gl, _obj_itc, e_obj, glit,
827 e_obj->children ? ELM_GENLIST_ITEM_TREE : ELM_GENLIST_ITEM_NONE,
828 NULL, NULL);
829 efl_wref_add(ii->gl_item, &(ii->gl_item));
830 }
831 }
832 }
833 else if (itc == _obj_itc)
834 {
835 if (compare)
836 {
837 _Compare_Item_Data *vv = elm_object_item_data_get(glit);
838 Exactness_Object *e_obj1 = vv->p1;
839 Exactness_Object *e_obj2 = vv->p2;
840 Eina_List *itr1 = e_obj1->children, *itr2 = e_obj2->children;
841
842 while (itr1 || itr2)
843 {
844 e_obj1 = eina_list_data_get(itr1);
845 e_obj2 = eina_list_data_get(itr2);
846 vv = calloc(1, sizeof(*vv));
847 vv->p1 = e_obj1;
848 vv->p2 = e_obj2;
849 vv->dt = EX_OBJ_INFO;
850 elm_genlist_item_append(gl, _obj_itc, vv, glit,
851 (e_obj1 && e_obj1->children) || (e_obj2 && e_obj2->children) ?
852 ELM_GENLIST_ITEM_TREE : ELM_GENLIST_ITEM_NONE,
853 NULL, NULL);
854 itr1 = eina_list_next(itr1);
855 itr2 = eina_list_next(itr2);
856 }
857 }
858 else
859 {
860 Exactness_Object *e_obj = elm_object_item_data_get(glit), *e_obj2;
861 Eina_List *itr;
862
863 EINA_LIST_FOREACH(e_obj->children, itr, e_obj2)
864 {
865 _Item_Info *ii = eina_hash_find(_item_infos_hash, &e_obj2);
866 if (!ii)
867 {
868 ii = calloc(1, sizeof(*ii));
869 eina_hash_set(_item_infos_hash, &e_obj2, ii);
870 }
871 ii->ex_parent = e_obj;
872 ii->gl_item = elm_genlist_item_append(gl, _obj_itc, e_obj2, glit,
873 e_obj2->children ? ELM_GENLIST_ITEM_TREE : ELM_GENLIST_ITEM_NONE,
874 NULL, NULL);
875 efl_wref_add(ii->gl_item, &(ii->gl_item));
876 }
877 }
878 }
879}
880
881static void
882_gl_contracted_cb(void *data EINA_UNUSED, Evas_Object *gl EINA_UNUSED, void *event_info)
883{
884 Elm_Object_Item *glit = event_info;
885 elm_genlist_item_subitems_clear(glit);
886}
887
888static void
889_comp_gl_selected_cb(void *data EINA_UNUSED, Evas_Object *gl EINA_UNUSED, void *event_info)
890{
891 _comp_selected_item = event_info;
892 _Compare_Item_Data *vv = elm_object_item_data_get(_comp_selected_item);
893 if (vv->p1)
894 {
895 _Item_Info *ii = eina_hash_find(_item_infos_hash, &(vv->p1));
896 if (!ii || !ii->gl_item) _obj_item_realize(vv->p1);
897 elm_genlist_item_selected_set(ii->gl_item, EINA_TRUE);
898 }
899
900 if (vv->p2)
901 {
902 _Item_Info *ii = eina_hash_find(_item_infos_hash, &(vv->p2));
903 if (!ii || !ii->gl_item) _obj_item_realize(vv->p2);
904 elm_genlist_item_selected_set(ii->gl_item, EINA_TRUE);
905 }
906}
907
908static void
909_scn_item_remove(void *data, Evas_Object *menu EINA_UNUSED, void *item EINA_UNUSED)
910{
911 Eo *glit = data;
912 Exactness_Unit *unit = efl_key_data_get(efl_parent_get(glit), "unit");
913 Exactness_Action *act = elm_object_item_data_get(glit);
914 unit->actions = eina_list_remove(unit->actions, act);
915 if (!eina_list_data_find(_modified_units, unit))
916 _modified_units = eina_list_append(_modified_units, unit);
917 efl_del(glit);
918}
919
920static void
921_gl_clicked_right_cb(void *data, Evas_Object *gl, void *event_info)
922{
923 int x = 0, y = 0;
924 Eo *win = data, *menu;
925 Elm_Object_Item *glit = event_info;
926
927 if (elm_genlist_item_item_class_get(glit) == _scn_itc)
928 {
929 elm_genlist_item_selected_set(glit, EINA_TRUE);
930 evas_pointer_canvas_xy_get(evas_object_evas_get(gl), &x, &y);
931
932 menu = elm_menu_add(win);
933 elm_menu_move(menu, x, y);
934 elm_menu_item_add(menu, NULL, NULL, "Remove", _scn_item_remove, glit);
935 efl_gfx_entity_visible_set(menu, EINA_TRUE);
936 }
937}
938
939static void
940_gl_img_show(void *data, Evas_Object *obj, void *event_info EINA_UNUSED)
941{
942 static Eo *_img_win = NULL;
943 Exactness_Image *ex_img = data;
944 if (_img_win) efl_del(_img_win);
945 _img_win = efl_add(EFL_UI_WIN_CLASS, elm_win_get(obj),
946 efl_ui_win_type_set(efl_added, EFL_UI_WIN_TYPE_DIALOG_BASIC),
947 efl_ui_win_autodel_set(efl_added, EINA_TRUE));
948 efl_wref_add(_img_win, &_img_win);
949
950 Evas_Object *image = elm_image_add(_img_win);
951 Eo *evas_img = elm_image_object_get(image);
952 evas_object_image_size_set(evas_img, ex_img->w, ex_img->h);
953 evas_object_image_data_set(evas_img, ex_img->pixels);
954 efl_content_set(_img_win, image);
955
956 efl_gfx_entity_size_set(_img_win, EINA_SIZE2D(550, 500));
957}
958
959static void
960_gui_unit_display(Exactness_Unit *unit1, Exactness_Unit *unit2)
961{
962 Eina_List *itr1, *itr2;
963 Eo *gl1, *gl2 = NULL, *glc = NULL;
964
965 gl1 = elm_genlist_add(_main_box);
966 elm_genlist_homogeneous_set(gl1, EINA_TRUE);
967 evas_object_size_hint_weight_set(gl1, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
968 evas_object_size_hint_align_set(gl1, EVAS_HINT_FILL, EVAS_HINT_FILL);
969 efl_gfx_entity_visible_set(gl1, EINA_TRUE);
970 _gls = eina_list_append(_gls, gl1);
971 elm_box_pack_end(_main_box, gl1);
972
973 efl_key_data_set(gl1, "unit", unit1);
974 evas_object_smart_callback_add(gl1, "expand,request", _gl_expand_request_cb, NULL);
975 evas_object_smart_callback_add(gl1, "contract,request", _gl_contract_request_cb, NULL);
976 evas_object_smart_callback_add(gl1, "expanded", _gl_expanded_cb, NULL);
977 evas_object_smart_callback_add(gl1, "contracted", _gl_contracted_cb, NULL);
978 if (!unit2)
979 evas_object_smart_callback_add(gl1, "clicked,right", _gl_clicked_right_cb, elm_win_get(_main_box));
980
981 if (unit2)
982 {
983 glc = elm_genlist_add(_main_box);
984 elm_genlist_homogeneous_set(glc, EINA_TRUE);
985 evas_object_size_hint_weight_set(glc, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
986 evas_object_size_hint_align_set(glc, EVAS_HINT_FILL, EVAS_HINT_FILL);
987 efl_gfx_entity_visible_set(glc, EINA_TRUE);
988 elm_box_pack_end(_main_box, glc);
989
990 evas_object_smart_callback_add(glc, "expand,request", _gl_expand_request_cb, NULL);
991 evas_object_smart_callback_add(glc, "contract,request", _gl_contract_request_cb, NULL);
992 evas_object_smart_callback_add(glc, "expanded", _gl_expanded_cb, NULL);
993 evas_object_smart_callback_add(glc, "contracted", _gl_contracted_cb, NULL);
994
995 efl_key_data_set(glc, "_exactness_gl_compare", glc);
996 elm_interface_scrollable_scroll_down_cb_set(glc, _comp_gl_dragged_cb);
997 elm_interface_scrollable_scroll_up_cb_set(glc, _comp_gl_dragged_cb);
998 evas_object_smart_callback_add(glc, "selected", _comp_gl_selected_cb, NULL);
999
1000 gl2 = elm_genlist_add(_main_box);
1001 elm_genlist_homogeneous_set(gl2, EINA_TRUE);
1002 evas_object_size_hint_weight_set(gl2, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
1003 evas_object_size_hint_align_set(gl2, EVAS_HINT_FILL, EVAS_HINT_FILL);
1004 efl_gfx_entity_visible_set(gl2, EINA_TRUE);
1005 _gls = eina_list_append(_gls, gl2);
1006 elm_box_pack_end(_main_box, gl2);
1007
1008 efl_key_data_set(gl2, "unit", unit2);
1009 evas_object_smart_callback_add(gl2, "expand,request", _gl_expand_request_cb, NULL);
1010 evas_object_smart_callback_add(gl2, "contract,request", _gl_contract_request_cb, NULL);
1011 evas_object_smart_callback_add(gl2, "expanded", _gl_expanded_cb, NULL);
1012 evas_object_smart_callback_add(gl2, "contracted", _gl_contracted_cb, NULL);
1013 }
1014 _itc_init();
1015
1016 if (unit1->fonts_path || (unit2 && unit2->fonts_path))
1017 {
1018 if (!_show_only_diffs || !unit1 || !unit2 ||
1019 !unit1->fonts_path || !unit2->fonts_path ||
1020 strcmp(unit1->fonts_path, unit2->fonts_path))
1021 {
1022 elm_genlist_item_append(gl1, _grp_itc, (void *)EX_FONTS_DIR, NULL, ELM_GENLIST_ITEM_GROUP, NULL, NULL);
1023 elm_genlist_item_append(gl2, _grp_itc, (void *)EX_FONTS_DIR, NULL, ELM_GENLIST_ITEM_GROUP, NULL, NULL);
1024 elm_genlist_item_append(glc, _grp_itc, (void *)EX_FONTS_DIR, NULL, ELM_GENLIST_ITEM_GROUP, NULL, NULL);
1025 }
1026 }
1027 itr1 = unit1 ? unit1->actions : NULL;
1028 itr2 = unit2 ? unit2->actions : NULL;
1029
1030 if (itr1 || itr2)
1031 {
1032 elm_genlist_item_append(gl1, _grp_itc, (void *)EX_SCENARIO, NULL, ELM_GENLIST_ITEM_GROUP, NULL, NULL);
1033 elm_genlist_item_append(gl2, _grp_itc, (void *)EX_SCENARIO, NULL, ELM_GENLIST_ITEM_GROUP, NULL, NULL);
1034 elm_genlist_item_append(glc, _grp_itc, (void *)EX_SCENARIO, NULL, ELM_GENLIST_ITEM_GROUP, NULL, NULL);
1035 }
1036 while (itr1 || itr2)
1037 {
1038 Exactness_Action *v1 = itr1 ? eina_list_data_get(itr1) : NULL;
1039 Exactness_Action *v2 = itr2 ? eina_list_data_get(itr2) : NULL;
1040 if (!_show_only_diffs || _are_scenario_entries_different(v1, v2))
1041 {
1042 _Item_Info *ii = calloc(1, sizeof(*ii));
1043 eina_hash_set(_item_infos_hash, &v1, ii);
1044 ii->gl_item = elm_genlist_item_append(gl1, _scn_itc, v1, NULL, ELM_GENLIST_ITEM_NONE, NULL, NULL);
1045 if (unit2)
1046 {
1047 _Compare_Item_Data *vv = calloc(1, sizeof(*vv));
1048 vv->p1 = v1;
1049 vv->p2 = v2;
1050 vv->dt = EX_SCENARIO;
1051 ii = calloc(1, sizeof(*ii));
1052 eina_hash_set(_item_infos_hash, &v2, ii);
1053 ii->gl_item = elm_genlist_item_append(gl2, _scn_itc, v2, NULL, ELM_GENLIST_ITEM_NONE, NULL, NULL);
1054 elm_genlist_item_append(glc, _scn_itc, vv, NULL, ELM_GENLIST_ITEM_NONE, NULL, NULL);
1055 }
1056 }
1057 if (itr1) itr1 = eina_list_next(itr1);
1058 if (itr2) itr2 = eina_list_next(itr2);
1059 }
1060
1061 itr1 = unit1 ? unit1->imgs : NULL;
1062 itr2 = unit2 ? unit2->imgs : NULL;
1063
1064 if (itr1 || itr2)
1065 {
1066 elm_genlist_item_append(gl1, _grp_itc, (void *)EX_IMAGE, NULL, ELM_GENLIST_ITEM_GROUP, NULL, NULL);
1067 elm_genlist_item_append(gl2, _grp_itc, (void *)EX_IMAGE, NULL, ELM_GENLIST_ITEM_GROUP, NULL, NULL);
1068 elm_genlist_item_append(glc, _grp_itc, (void *)EX_IMAGE, NULL, ELM_GENLIST_ITEM_GROUP, NULL, NULL);
1069 }
1070 while (itr1 || itr2)
1071 {
1072 Exactness_Image *img1 = itr1 ? eina_list_data_get(itr1) : NULL;
1073 Exactness_Image *img2 = itr2 ? eina_list_data_get(itr2) : NULL;
1074 if (!_show_only_diffs || _are_images_different(img1, img2))
1075 {
1076 _Item_Info *ii = calloc(1, sizeof(*ii));
1077 eina_hash_set(_item_infos_hash, &img1, ii);
1078 ii->gl_item = elm_genlist_item_append(gl1, _img_itc, img1, NULL, ELM_GENLIST_ITEM_NONE, _gl_img_show, img1);
1079 if (unit2)
1080 {
1081 _Compare_Item_Data *vv = calloc(1, sizeof(*vv));
1082 vv->p1 = img1;
1083 vv->p2 = img2;
1084 vv->dt = EX_IMAGE;
1085 ii = calloc(1, sizeof(*ii));
1086 eina_hash_set(_item_infos_hash, &img2, ii);
1087 ii->gl_item = elm_genlist_item_append(gl2, _img_itc, img2, NULL, ELM_GENLIST_ITEM_NONE, NULL, NULL);
1088 /* This item info is needed to go to images from scenario shot entry */
1089 ii = calloc(1, sizeof(*ii));
1090 eina_hash_set(_item_infos_hash, &vv, ii);
1091 ii->gl_item = elm_genlist_item_append(glc, _img_itc, vv, NULL, ELM_GENLIST_ITEM_NONE, NULL, NULL);
1092 _comp_vvs = eina_list_append(_comp_vvs, vv);
1093 }
1094 }
1095 if (itr1) itr1 = eina_list_next(itr1);
1096 if (itr2) itr2 = eina_list_next(itr2);
1097 }
1098
1099 itr1 = unit1 ? unit1->objs : NULL;
1100 itr2 = unit2 ? unit2->objs : NULL;
1101
1102 if (itr1 || itr2)
1103 {
1104 elm_genlist_item_append(gl1, _grp_itc, (void *)EX_OBJ_INFO, NULL, ELM_GENLIST_ITEM_GROUP, NULL, NULL);
1105 elm_genlist_item_append(gl2, _grp_itc, (void *)EX_OBJ_INFO, NULL, ELM_GENLIST_ITEM_GROUP, NULL, NULL);
1106 elm_genlist_item_append(glc, _grp_itc, (void *)EX_OBJ_INFO, NULL, ELM_GENLIST_ITEM_GROUP, NULL, NULL);
1107 }
1108 while (itr1 || itr2)
1109 {
1110 Exactness_Objects *objs1 = itr1 ? eina_list_data_get(itr1) : NULL;
1111 Exactness_Objects *objs2 = itr2 ? eina_list_data_get(itr2) : NULL;
1112 if (!_show_only_diffs || _are_objs_trees_different(objs1, objs2))
1113 {
1114 _Item_Info *ii = calloc(1, sizeof(*ii));
1115 eina_hash_set(_item_infos_hash, &objs1, ii);
1116 ii->gl_item = elm_genlist_item_append(gl1, _objs_itc, objs1, NULL,
1117 ELM_GENLIST_ITEM_TREE, NULL, NULL);
1118 efl_wref_add(ii->gl_item, &(ii->gl_item));
1119 if (unit2)
1120 {
1121 _Compare_Item_Data *vv = calloc(1, sizeof(*vv));
1122 vv->p1 = objs1;
1123 vv->p2 = objs2;
1124 vv->dt = EX_OBJ_INFO;
1125 ii = calloc(1, sizeof(*ii));
1126 eina_hash_set(_item_infos_hash, &objs2, ii);
1127 ii->gl_item = elm_genlist_item_append(gl2, _objs_itc, objs2, NULL,
1128 ELM_GENLIST_ITEM_TREE, NULL, NULL);
1129 efl_wref_add(ii->gl_item, &(ii->gl_item));
1130 elm_genlist_item_append(glc, _objs_itc, vv, NULL, ELM_GENLIST_ITEM_TREE, NULL, NULL);
1131 }
1132 }
1133 if (itr1) itr1 = eina_list_next(itr1);
1134 if (itr2) itr2 = eina_list_next(itr2);
1135 }
1136}
1137
1138static void
1139_diff_result_print(Exactness_Unit *unit1, Exactness_Unit *unit2)
1140{
1141 Eina_List *itr1, *itr2;
1142
1143 int nb_scenario = 0, nb_diff_scenario = 0;
1144 int nb_image = 0, nb_diff_image = 0;
1145 int nb_objtree= 0, nb_diff_objtree = 0;
1146
1147 itr1 = unit1 ? unit1->actions : NULL;
1148 itr2 = unit2 ? unit2->actions : NULL;
1149
1150 while (itr1 || itr2)
1151 {
1152 Exactness_Action *v1 = itr1 ? eina_list_data_get(itr1) : NULL;
1153 Exactness_Action *v2 = itr2 ? eina_list_data_get(itr2) : NULL;
1154
1155 nb_scenario++;
1156 if (_are_scenario_entries_different(v1, v2))
1157 nb_diff_scenario++;
1158
1159 if (itr1) itr1 = eina_list_next(itr1);
1160 if (itr2) itr2 = eina_list_next(itr2);
1161 }
1162
1163 itr1 = unit1 ? unit1->imgs : NULL;
1164 itr2 = unit2 ? unit2->imgs : NULL;
1165
1166 while (itr1 || itr2)
1167 {
1168 Exactness_Image *img1 = itr1 ? eina_list_data_get(itr1) : NULL;
1169 Exactness_Image *img2 = itr2 ? eina_list_data_get(itr2) : NULL;
1170
1171 nb_image++;
1172 if (_are_images_different(img1, img2))
1173 nb_diff_image++;
1174
1175 if (itr1) itr1 = eina_list_next(itr1);
1176 if (itr2) itr2 = eina_list_next(itr2);
1177 }
1178
1179 itr1 = unit1 ? unit1->objs : NULL;
1180 itr2 = unit2 ? unit2->objs : NULL;
1181
1182 while (itr1 || itr2)
1183 {
1184 Exactness_Objects *objs1 = itr1 ? eina_list_data_get(itr1) : NULL;
1185 Exactness_Objects *objs2 = itr2 ? eina_list_data_get(itr2) : NULL;
1186
1187 nb_objtree++;
1188 if (_are_objs_trees_different(objs1, objs2))
1189 nb_diff_objtree++;
1190
1191 if (itr1) itr1 = eina_list_next(itr1);
1192 if (itr2) itr2 = eina_list_next(itr2);
1193 }
1194
1195 printf("%s\nscenario (%d/%d)\nimage (%d/%d)\nobjs_tree (%d/%d)\n",
1196 nb_diff_scenario || nb_diff_image || nb_diff_objtree ?
1197 "Failure" : "Success",
1198 nb_scenario - nb_diff_scenario, nb_scenario,
1199 nb_image - nb_diff_image, nb_image,
1200 nb_objtree - nb_diff_objtree, nb_objtree);
1201}
1202
1203static Exactness_Image *
1204_image_read(const char *filename)
1205{
1206 int w, h;
1207 Evas_Load_Error err;
1208 Ecore_Evas *ee = ecore_evas_new(NULL, 0, 0, 100, 100, NULL);
1209
1210 /* the canvas pointer, de facto */
1211 Eo *e = ecore_evas_get(ee);
1212
1213 Eo *img = evas_object_image_add(e);
1214 evas_object_image_file_set(img, filename, NULL);
1215 err = evas_object_image_load_error_get(img);
1216 if (err != EVAS_LOAD_ERROR_NONE)
1217 {
1218 fprintf(stderr, "could not load image '%s'. error string is \"%s\"\n",
1219 filename, evas_load_error_str(err));
1220 return NULL;
1221 }
1222
1223 Exactness_Image *ex_img = malloc(sizeof(*ex_img));
1224 int len;
1225 evas_object_image_size_get(img, &w, &h);
1226 ex_img->w = w;
1227 ex_img->h = h;
1228 len = w * h * 4;
1229 ex_img->pixels = malloc(len);
1230 memcpy(ex_img->pixels, evas_object_image_data_get(img, EINA_FALSE), len);
1231
1232 ecore_evas_free(ee);
1233 return ex_img;
1234}
1235
1236static const Ecore_Getopt optdesc = {
1237 "exactness_inspect",
1238 "%prog [options] [<rec file> | <file1 file2>]",
1239 NULL,
1240 "(C) 2016 Enlightenment",
1241 "BSD",
1242 "Inspector for Exactness",
1243 0,
1244 {
1245 ECORE_GETOPT_STORE_USHORT('d', "delay", "Delay the given recording by a given time (in milliseconds)."),
1246 ECORE_GETOPT_STORE_TRUE('c', "clean", "Clean the given recording from wrong actions."),
1247 ECORE_GETOPT_STORE_TRUE('l', "list", "List the actions of the given recording."),
1248 ECORE_GETOPT_STORE_TRUE('C', "compare", "Compare given files (images files or objects eet files)."),
1249 ECORE_GETOPT_STORE_TRUE(0, "show-only-diffs", "Show only differences during comparison."),
1250 ECORE_GETOPT_STORE_TRUE(0, "stabilize", "Stabilize after the given shot number in --shot."),
1251 ECORE_GETOPT_STORE_TRUE(0, "pack", "Pack the given input files (scenario and images) into the given output."),
1252 ECORE_GETOPT_STORE_STR('o', "output", "Output."),
1253 ECORE_GETOPT_STORE_USHORT('s', "shot", "Select a specific shot (1 = 1st shot...)."),
1254
1255 ECORE_GETOPT_LICENSE('L', "license"),
1256 ECORE_GETOPT_COPYRIGHT('C', "copyright"),
1257 ECORE_GETOPT_VERSION('V', "version"),
1258 ECORE_GETOPT_HELP('h', "help"),
1259 ECORE_GETOPT_SENTINEL
1260 }
1261};
1262
1263int
1264main(int argc, char *argv[])
1265{
1266 Eina_List *units_filenames = NULL;
1267 const char *ext = NULL;
1268 char *output = NULL;
1269 Exactness_Unit *unit = NULL;
1270 int ret = 1, args = 0;
1271 unsigned short delay = 0, shot = 0;
1272 Eina_Bool write_file = EINA_FALSE;
1273 Eina_Bool want_quit, clean = EINA_FALSE, list_get = EINA_FALSE, compare_files = EINA_FALSE;
1274 Eina_Bool stabilize = EINA_FALSE, show_only_diffs = EINA_FALSE, gui_needed = EINA_TRUE;
1275 Eina_Bool pack = EINA_FALSE;
1276
1277 Ecore_Getopt_Value values[] = {
1278 ECORE_GETOPT_VALUE_USHORT(delay),
1279 ECORE_GETOPT_VALUE_BOOL(clean),
1280 ECORE_GETOPT_VALUE_BOOL(list_get),
1281 ECORE_GETOPT_VALUE_BOOL(compare_files),
1282 ECORE_GETOPT_VALUE_BOOL(show_only_diffs),
1283 ECORE_GETOPT_VALUE_BOOL(stabilize),
1284 ECORE_GETOPT_VALUE_BOOL(pack),
1285 ECORE_GETOPT_VALUE_STR(output),
1286 ECORE_GETOPT_VALUE_USHORT(shot),
1287
1288 ECORE_GETOPT_VALUE_BOOL(want_quit),
1289 ECORE_GETOPT_VALUE_BOOL(want_quit),
1290 ECORE_GETOPT_VALUE_BOOL(want_quit),
1291 ECORE_GETOPT_VALUE_BOOL(want_quit),
1292 ECORE_GETOPT_VALUE_NONE
1293 };
1294
1295 ecore_evas_init();
1296 ecore_init();
1297 eet_init();
1298 elm_init(0, NULL);
1299 want_quit = EINA_FALSE;
1300
1301 args = ecore_getopt_parse(&optdesc, values, argc, argv);
1302 if (args < 0)
1303 {
1304 fprintf(stderr, "Failed parsing arguments.\n");
1305 goto end;
1306 }
1307 if (want_quit)
1308 {
1309 goto end;
1310 }
1311 if ((clean || delay || shot || list_get || stabilize || pack) && args == argc)
1312 {
1313 fprintf(stderr, "Expected scenario (.rec/.exu) as the last argument.\n");
1314 ecore_getopt_help(stderr, &optdesc);
1315 goto end;
1316 }
1317 if (shot && (!delay && !stabilize))
1318 {
1319 fprintf(stderr, "shot option can only be used with delay or stabilize option.\n");
1320 goto end;
1321 }
1322 if (delay && !shot)
1323 {
1324 fprintf(stderr, "delay option can only be used with shot option.\n");
1325 goto end;
1326 }
1327 if (stabilize && !shot)
1328 {
1329 fprintf(stderr, "stabilize option can only be used with shot option.\n");
1330 goto end;
1331 }
1332 if (compare_files && argc - args < 2)
1333 {
1334 fprintf(stderr, "Expected at least two files to compare as last arguments.\n");
1335 ecore_getopt_help(stderr, &optdesc);
1336 goto end;
1337 }
1338 if (show_only_diffs && !compare_files)
1339 {
1340 fprintf(stderr, "--show-only-diffs is available with --compare only\n");
1341 goto end;
1342 }
1343 if (show_only_diffs && output)
1344 {
1345 fprintf(stderr, "--show-only-diffs works in GUI only\n");
1346 goto end;
1347 }
1348 _show_only_diffs = show_only_diffs;
1349
1350 if (clean || delay || list_get || stabilize || pack)
1351 {
1352 int arg;
1353 Eina_List *images = NULL;
1354 gui_needed = EINA_FALSE;
1355 for (arg = args; arg < argc; arg++)
1356 {
1357 const char *src_file = argv[arg];
1358 ext = strrchr(src_file, '.');
1359 if (!ext)
1360 {
1361 fprintf(stderr, "Extension required\n");
1362 goto end;
1363 }
1364 if (!strcmp(ext, ".exu"))
1365 {
1366 if (!unit) unit = exactness_unit_file_read(src_file);
1367 else
1368 {
1369 fprintf(stderr, "%s - scenario already provided\n", src_file);
1370 goto end;
1371 }
1372 }
1373 else if (!strcmp(ext, ".rec"))
1374 {
1375 if (!unit) unit = legacy_rec_file_read(src_file);
1376 else
1377 {
1378 fprintf(stderr, "%s - scenario already provided\n", src_file);
1379 goto end;
1380 }
1381 }
1382 else if (!strcmp(ext, ".png"))
1383 {
1384 Exactness_Image *ex_img = _image_read(src_file);
1385 if (!ex_img)
1386 {
1387 fprintf(stderr, "Issue while reading %s\n", src_file);
1388 goto end;
1389 }
1390 images = eina_list_append(images, ex_img);
1391 }
1392 else
1393 {
1394 fprintf(stderr, "Correct extension (.exu/.rec/.png) required\n");
1395 goto end;
1396 }
1397 }
1398 if (unit)
1399 {
1400 Exactness_Image *ex_img;
1401 EINA_LIST_FREE(images, ex_img)
1402 {
1403 unit->imgs = eina_list_append(unit->imgs, ex_img);
1404 unit->nb_shots++;
1405 }
1406 }
1407 }
1408 else
1409 {
1410 int arg;
1411 if (output) gui_needed = EINA_FALSE;
1412 for (arg = args; arg < argc; arg++)
1413 {
1414 ext = strrchr(argv[arg], '.');
1415 if (!ext)
1416 {
1417 fprintf(stderr, "Extension required\n");
1418 goto end;
1419 }
1420 if (!strcmp(ext, ".exu"))
1421 {
1422 Exactness_Unit *ex_unit = exactness_unit_file_read(argv[arg]);
1423 units_filenames = eina_list_append(units_filenames, argv[arg]);
1424 _units = eina_list_append(_units, ex_unit);
1425 }
1426 else if (!strcmp(ext, ".rec"))
1427 {
1428 Exactness_Unit *ex_unit = legacy_rec_file_read(argv[arg]);
1429 if (!ex_unit)
1430 {
1431 fprintf(stderr, "Issue while reading %s\n", argv[arg]);
1432 goto end;
1433 }
1434 _units = eina_list_append(_units, ex_unit);
1435 }
1436 else if (!strcmp(ext, ".png"))
1437 {
1438 Exactness_Unit *ex_unit = calloc(1, sizeof(*ex_unit));
1439 Exactness_Image *ex_img = _image_read(argv[arg]);
1440 if (!ex_img)
1441 {
1442 fprintf(stderr, "Issue while reading %s\n", argv[arg]);
1443 goto end;
1444 }
1445 ex_unit->imgs = eina_list_append(ex_unit->imgs, ex_img);
1446 ex_unit->nb_shots++;
1447 _units = eina_list_append(_units, ex_unit);
1448 }
1449 }
1450 }
1451
1452 if (clean)
1453 {
1454 Exactness_Action *act;
1455 Eina_List *itr, *itr2;
1456 EINA_LIST_FOREACH_SAFE(unit->actions, itr, itr2, act)
1457 {
1458 Exactness_Action *prev_act = eina_list_data_get(eina_list_prev(itr));
1459 if (_is_hook_duplicate(act, prev_act))
1460 {
1461 prev_act->delay_ms += act->delay_ms;
1462 unit->actions = eina_list_remove_list(unit->actions, itr);
1463 }
1464 }
1465 EINA_LIST_REVERSE_FOREACH_SAFE(unit->actions, itr, itr2, act)
1466 {
1467 if (act->type == EXACTNESS_ACTION_TAKE_SHOT) break;
1468 unit->actions = eina_list_remove(unit->actions, act);
1469 }
1470 write_file = EINA_TRUE;
1471 }
1472
1473 if (delay || stabilize)
1474 {
1475 Exactness_Action *act;
1476 Eina_List *itr;
1477 unsigned int cur_shot = 0;
1478 EINA_LIST_FOREACH(unit->actions, itr, act)
1479 {
1480 if (act->type == EXACTNESS_ACTION_TAKE_SHOT)
1481 {
1482 cur_shot++;
1483 if (cur_shot == shot)
1484 {
1485 if (delay) act->delay_ms = delay;
1486 if (stabilize)
1487 {
1488 Exactness_Action *s_act = malloc(sizeof(*s_act));
1489 s_act->type = EXACTNESS_ACTION_STABILIZE;
1490 s_act->delay_ms = act->delay_ms;
1491 s_act->n_evas = act->n_evas;
1492 s_act->data = NULL;
1493 act->delay_ms = 0; /* Shot right after stabilization */
1494 unit->actions = eina_list_prepend_relative(unit->actions, s_act, act);
1495 }
1496 write_file = EINA_TRUE;
1497 break;
1498 }
1499 }
1500 }
1501 }
1502
1503 if (pack) write_file = EINA_TRUE;
1504
1505 if (list_get)
1506 {
1507 Exactness_Action *act;
1508 Eina_List *itr;
1509 if (unit->fonts_path) printf("Fonts dir: %s\n", unit->fonts_path);
1510 EINA_LIST_FOREACH(unit->actions, itr, act)
1511 {
1512 char specific_output[1024];
1513 printf("+%.3f: %s", act->delay_ms / 1000.0, _action_name_get(act));
1514 _action_specific_info_get(act, specific_output);
1515 if (*specific_output) printf(" - %s", specific_output);
1516 printf("\n");
1517 }
1518 }
1519
1520 if (compare_files && output)
1521 {
1522 const char *out_ext = strrchr(output, '.');
1523 Exactness_Unit *unit1 = NULL, *unit2 = NULL, *unitO = NULL;
1524 int nb_diffs = 0;
1525 Eina_List *itr1, *itr2;
1526 EINA_LIST_FOREACH(_units, itr1, unit)
1527 {
1528 if (!unit1) unit1 = unit;
1529 else if (!unit2) unit2 = unit;
1530 else
1531 {
1532 fprintf(stderr, "Too much files to compare (only 2).\n");
1533 goto end;
1534 }
1535 }
1536
1537 if (!strcmp(out_ext, ".png"))
1538 {
1539 if (unit1->nb_shots != 1 || unit2->nb_shots != 1)
1540 {
1541 fprintf(stderr, "Comparison output can be png only if the number of shots to compare is 1.\n");
1542 goto end;
1543 }
1544 }
1545
1546 itr1 = unit1 ? unit1->imgs : NULL;
1547 itr2 = unit2 ? unit2->imgs : NULL;
1548
1549 while (itr1 || itr2)
1550 {
1551 Exactness_Image *ex_img1 = itr1 ? eina_list_data_get(itr1) : NULL;
1552 Exactness_Image *ex_img2 = itr2 ? eina_list_data_get(itr2) : NULL;
1553 Exactness_Image *ex_imgO = NULL;
1554 Eina_Bool has_diff = exactness_image_compare(ex_img1, ex_img2, &ex_imgO);
1555 if (has_diff || !strcmp(out_ext, ".exu"))
1556 {
1557 if (has_diff) nb_diffs++;
1558 if (!unitO) unitO = calloc(1, sizeof(*unitO));
1559 unitO->imgs = eina_list_append(unitO->imgs, ex_imgO);
1560 unitO->nb_shots++;
1561 }
1562 itr1 = eina_list_next(itr1);
1563 itr2 = eina_list_next(itr2);
1564 }
1565 if (!strcmp(out_ext, ".png"))
1566 {
1567 Ecore_Evas *ee;
1568 Eo *e, *img;
1569 if (unitO->nb_shots == 1)
1570 {
1571 Exactness_Image *ex_imgO = eina_list_data_get(unitO->imgs);
1572 ee = ecore_evas_new(NULL, 0, 0, 100, 100, NULL);
1573 e = ecore_evas_get(ee);
1574 img = evas_object_image_add(e);
1575 evas_object_image_size_set(img, ex_imgO->w, ex_imgO->h);
1576 evas_object_image_data_set(img, ex_imgO->pixels);
1577 evas_object_image_save(img, output, NULL, NULL);
1578 ecore_evas_free(ee);
1579 goto end;
1580 }
1581 ret = 0;
1582 }
1583 else if (!strcmp(out_ext, ".exu"))
1584 {
1585 _diff_result_print(unit1, unit2);
1586 if (nb_diffs) exactness_unit_file_write(unitO, output);
1587 else ret = 0;
1588 }
1589 else
1590 {
1591 fprintf(stderr, "Correct output extension (.exu/.png) required\n");
1592 }
1593 goto end;
1594 }
1595
1596 ret = 0;
1597 if (write_file)
1598 {
1599 if (!output)
1600 {
1601 fprintf(stderr, "An output file is required to write the modifications.\n");
1602 }
1603 else
1604 {
1605 const char *out_ext = strrchr(output, '.');
1606 if (!out_ext || strcmp(out_ext, ".exu"))
1607 {
1608 fprintf(stderr, "Only exu extension is supported as output.\n");
1609 goto end;
1610 }
1611 exactness_unit_file_write(unit, output);
1612 }
1613 goto end;
1614 }
1615
1616 if (gui_needed)
1617 {
1618 Eina_List *itr;
1619 Exactness_Unit *unit1 = NULL, *unit2 = NULL;
1620 Eina_Bool need_compare = compare_files && eina_list_count(_units) == 2;
1621 _item_infos_hash = eina_hash_pointer_new(NULL);
1622 _gui_win_create();
1623 EINA_LIST_FOREACH(_units, itr, unit)
1624 {
1625 if (need_compare)
1626 {
1627 if (!unit1) unit1 = unit;
1628 else unit2 = unit;
1629 }
1630 else _gui_unit_display(unit, NULL);
1631 }
1632 if (need_compare) _gui_unit_display(unit1, unit2);
1633 elm_run();
1634 EINA_LIST_FREE(_modified_units, unit)
1635 {
1636 int i = 0;
1637 EINA_LIST_FOREACH(_units, itr, unit2)
1638 {
1639 if (unit2 == unit) break;
1640 i++;
1641 }
1642 exactness_unit_file_write(unit, eina_list_nth(units_filenames, i));
1643 }
1644 }
1645
1646end:
1647 elm_shutdown();
1648 eet_shutdown();
1649 ecore_shutdown();
1650 ecore_evas_shutdown();
1651
1652 return ret;
1653}
diff --git a/src/bin/exactness/meson.build b/src/bin/exactness/meson.build
new file mode 100644
index 0000000000..6303e3fffe
--- /dev/null
+++ b/src/bin/exactness/meson.build
@@ -0,0 +1,42 @@
1exactness_bin = executable('exactness',
2 [ 'exactness.c' ],
3 dependencies: [ ecore, ecore_evas, ecore_file, exactness ],
4 install: true,
5 )
6
7exactness_inject_bin = executable('exactness_inject',
8 [ 'injector.c' ],
9 dependencies: [ elementary, exactness ],
10 install: true,
11 )
12
13exactness_inspect_bin = executable('exactness_inspect',
14 [ 'inspect.c' ],
15 dependencies: [ elementary, exactness ],
16 install: true,
17 )
18
19edjs = custom_target('player_entry',
20 input : 'player_entry.edc',
21 output : 'player_entry.edj',
22 install : true,
23 install_dir : 'share/exactness',
24 command : edje_cc_exe + [
25 '-id', join_paths(meson.source_root(), 'data', 'elementary', 'themes', 'img'),
26 '-sd', join_paths(meson.source_root(), 'data', 'elementary', 'themes', 'snd'),
27 '@INPUT@', '@OUTPUT@'],
28 depends : edje_cc)
29
30exactness_play_bin = executable('exactness_play',
31 [ 'player.c', edjs ],
32 dependencies: [ elementary, exactness ],
33 c_args: '-DDATA_DIR="'+join_paths(dir_data, 'exactness')+'"',
34 install: true,
35 )
36
37exactness_record_bin = executable('exactness_record',
38 [ 'recorder.c' ],
39 dependencies: [ elementary, exactness ],
40 install: true,
41 )
42
diff --git a/src/bin/exactness/player.c b/src/bin/exactness/player.c
new file mode 100644
index 0000000000..a2700f4653
--- /dev/null
+++ b/src/bin/exactness/player.c
@@ -0,0 +1,1393 @@
1#ifdef HAVE_CONFIG_H
2# include <config.h>
3#endif
4
5#define _POSIX_
6#include <limits.h>
7#include <stdio.h>
8#include <stdlib.h>
9#include <getopt.h>
10#include <unistd.h>
11
12#ifdef HAVE_FORK
13# ifdef HAVE_SYS_WAIT_H
14# include <sys/wait.h>
15# endif
16# ifdef HAVE_SYS_TYPES_H
17# include <sys/types.h>
18# endif
19# ifdef HAVE_SYS_SYSINFO_H
20# include <sys/sysinfo.h>
21# endif
22#endif
23
24#ifndef EFL_EO_API_SUPPORT
25#define EFL_EO_API_SUPPORT
26#endif
27#include <Eina.h>
28#include <Eo.h>
29#include <Evas.h>
30#include <Ecore.h>
31#include <Ecore_Getopt.h>
32#include <Ecore_File.h>
33#include <Ecore_Con.h>
34#include <Elementary.h>
35#include <Exactness.h>
36
37#include "exactness_private.h"
38
39#define PATH_ 1024
40#define IMAGE_FILENAME_EXT ".png"
41#define PAUSE_KEY_STR "F2"
42
43typedef struct
44{
45 Eina_Debug_Session *session;
46 int srcid;
47 void *buffer;
48 unsigned int size;
49} _Main_Loop_Info;
50
51#define WRAPPER_TO_XFER_MAIN_LOOP(foo) \
52static void \
53_intern_main_loop ## foo(void *data) \
54{ \
55 _Main_Loop_Info *info = data; \
56 _main_loop ## foo(info->session, info->srcid, info->buffer, info->size); \
57 free(info->buffer); \
58 free(info); \
59} \
60static Eina_Bool \
61foo(Eina_Debug_Session *session, int srcid, void *buffer, int size) \
62{ \
63 _Main_Loop_Info *info = calloc(1, sizeof(*info)); \
64 info->session = session; \
65 info->srcid = srcid; \
66 info->size = size; \
67 if (info->size) \
68 { \
69 info->buffer = malloc(info->size); \
70 memcpy(info->buffer, buffer, info->size); \
71 } \
72 ecore_main_loop_thread_safe_call_async(_intern_main_loop ## foo, info); \
73 return EINA_TRUE; \
74}
75
76#ifndef WORDS_BIGENDIAN
77#define SWAP_64(x) x
78#define SWAP_32(x) x
79#define SWAP_16(x) x
80#define SWAP_DBL(x) x
81#else
82#define SWAP_64(x) eina_swap64(x)
83#define SWAP_32(x) eina_swap32(x)
84#define SWAP_16(x) eina_swap16(x)
85#define SWAP_DBL(x) SWAP_64(x)
86#endif
87
88#define EXTRACT_INT(_buf) \
89({ \
90 int __i; \
91 memcpy(&__i, _buf, sizeof(int)); \
92 _buf += sizeof(int); \
93 SWAP_32(__i); \
94})
95
96#define EXTRACT_DOUBLE(_buf) \
97({ \
98 double __d; \
99 memcpy(&__d, _buf, sizeof(double)); \
100 _buf += sizeof(double); \
101 SWAP_DBL(__d); \
102})
103
104#define EXTRACT_STRING(_buf) \
105({ \
106 char *__s = _buf ? strdup(_buf) : NULL; \
107 int __len = (__s ? strlen(__s) : 0) + 1; \
108 _buf += __len; \
109 __s; \
110})
111
112#define STORE_INT(_buf, __i) \
113({ \
114 int __si = SWAP_32(__i); \
115 memcpy(_buf, &__si, sizeof(int)); \
116 _buf += sizeof(int); \
117})
118
119typedef enum
120{
121 FTYPE_UNKNOWN,
122 FTYPE_DIR,
123 FTYPE_REC = FTYPE_DIR,
124 FTYPE_EXU,
125 FTYPE_REMOTE
126} File_Type;
127
128static File_Type _dest_type = FTYPE_UNKNOWN;
129static Eina_Stringshare *_dest = NULL;
130static Exactness_Unit *_dest_unit = NULL;
131
132static File_Type _src_type = FTYPE_UNKNOWN;
133static Eina_Stringshare *_src_filename = NULL;
134static Exactness_Unit *_src_unit = NULL;
135
136static const char *_test_name = NULL;
137static int _verbose = 0;
138
139static Evas *(*_evas_new)(void) = NULL;
140static Eina_List *_evas_list = NULL;
141
142static Eina_List *_cur_event_list = NULL;
143
144static int _cur_shot_id = 0;
145static Eina_Bool _shot_needed = EINA_FALSE;
146static Eina_Bool _scan_objects = EINA_FALSE, _disable_shots = EINA_FALSE, _stabilize_shots = EINA_FALSE;
147
148static Eina_Debug_Session *_last_debug_session = NULL;
149static int _last_debug_src_cid = 0;
150static int _take_shot_op = EINA_DEBUG_OPCODE_INVALID;
151
152static Eina_Bool _stabilization_timer_cb(void *);
153static double _speed = 1.0;
154
155static Eina_Bool _exit_required = EINA_FALSE;
156static Eina_Bool _pause_request = EINA_FALSE;
157static Eina_Bool _playing_status = EINA_FALSE;
158
159static void
160_printf(int verbose, const char *fmt, ...)
161{
162 va_list ap;
163 if (!_verbose || verbose > _verbose) return;
164
165 va_start(ap, fmt);
166 vprintf(fmt, ap);
167 va_end(ap);
168}
169
170static Exactness_Image *
171_snapshot_shot_get(Evas *e)
172{
173 Exactness_Image *ex_img;
174 Evas_Object *snapshot;
175 void *pixels;
176 int w, h, nb_bytes;
177
178 if (!e) return NULL;
179
180 evas_output_size_get(e, &w, &h);
181 if ((w < 1) || (h < 1)) return NULL;
182
183 snapshot = efl_key_data_get(e, "_snapshot");
184 if (!snapshot)
185 {
186 snapshot = evas_object_image_filled_add(e);
187 if (snapshot)
188 {
189 evas_object_image_snapshot_set(snapshot, EINA_TRUE);
190 evas_object_geometry_set(snapshot, 0, 0, w, h);
191 efl_gfx_entity_visible_set(snapshot, EINA_TRUE);
192 efl_key_data_set(e, "_snapshot", snapshot);
193 }
194 return NULL;
195 }
196
197 pixels = evas_object_image_data_get(snapshot, EINA_FALSE);
198 if (!pixels) return NULL;
199
200 ex_img = malloc(sizeof(*ex_img));
201 nb_bytes = w * h * 4;
202 ex_img->w = w;
203 ex_img->h = h;
204 ex_img->pixels = malloc(nb_bytes);
205 memcpy(ex_img->pixels, pixels, nb_bytes);
206 return ex_img;
207}
208
209static void
210_evas_render_post_cb(void *data EINA_UNUSED, const Efl_Event *event)
211{
212 if (_shot_needed)
213 {
214 Evas_Event_Render_Post *post = event->info;
215 void *e_data = efl_key_data_get(event->object, "_shot");
216
217 // Nothing was updated, so let's not bother sending nothingness
218 if (post && !post->updated_area) return;
219 Exactness_Image *ex_shot = efl_key_data_get(event->object, "_last_shot");
220 if (!ex_shot) ex_shot = _snapshot_shot_get(event->object);
221 if (!ex_shot) return;
222
223 efl_key_data_set(event->object, "_last_shot", NULL);
224
225 if (e_data)
226 {
227 if (_dest_type == FTYPE_DIR)
228 {
229 char *filename = e_data;
230 Eo *o = evas_object_image_add(event->object);
231 evas_object_image_size_set(o, ex_shot->w, ex_shot->h);
232 evas_object_image_data_set(o, ex_shot->pixels);
233 _printf(1, "Shot taken (%s).\n", filename);
234 if (!evas_object_image_save(o, filename, NULL, NULL))
235 {
236 printf("Cannot save widget to <%s>\n", filename);
237 }
238 free(filename);
239 }
240 else if (_dest_type == FTYPE_EXU)
241 {
242 Exactness_Image *ex_img = e_data;
243 memcpy(ex_img, ex_shot, sizeof(Exactness_Image));
244 ex_shot->pixels = NULL;
245 _printf(1, "Shot taken (in %s).\n", _dest);
246 }
247 else if (_dest_type == FTYPE_REMOTE)
248 {
249 int len = sizeof(int) + sizeof(int) + ex_shot->w * ex_shot->h * 4;
250 char *buf = alloca(len);
251 char *tmp = buf;
252 STORE_INT(tmp, ex_shot->w);
253 STORE_INT(tmp, ex_shot->h);
254 memcpy(tmp, ex_shot->pixels, ex_shot->w * ex_shot->h * 4);
255 eina_debug_session_send(_last_debug_session, _last_debug_src_cid, _take_shot_op, buf, len);
256 }
257 }
258 exactness_image_free(ex_shot);
259 efl_key_data_set(event->object, "_shot", NULL);
260 evas_object_del(efl_key_data_get(event->object, "_snapshot"));
261 efl_key_data_set(event->object, "_snapshot", NULL);
262 /* This part is needed when the shot is needed at the end of the scenario.
263 * As it is async, we need to wait for the shot termination. */
264 _shot_needed = EINA_FALSE;
265 if (_exit_required) ecore_main_loop_quit();
266 }
267}
268
269static void
270_shot_do(Evas *e)
271{
272 void *e_data = NULL;
273 if (!e) return;
274
275 if (!_disable_shots)
276 {
277 if (_dest_type == FTYPE_DIR)
278 {
279 int dir_name_len;
280 char *filename;
281
282 dir_name_len = strlen(_dest) + 1; /* includes space of a '/' */
283 filename = malloc(strlen(_test_name) + strlen(IMAGE_FILENAME_EXT) +
284 dir_name_len + 8); /* also space for serial */
285
286 sprintf(filename, "%s/%s%c%03d%s", _dest, _test_name,
287 SHOT_DELIMITER, _cur_shot_id, IMAGE_FILENAME_EXT);
288 e_data = filename;
289 }
290 else if (_dest_type == FTYPE_EXU)
291 {
292 Exactness_Image *ex_img = malloc(sizeof(*ex_img));
293 _dest_unit->imgs = eina_list_append(_dest_unit->imgs, ex_img);
294 _dest_unit->nb_shots++;
295 e_data = ex_img;
296 }
297 else if (_dest_type == FTYPE_REMOTE)
298 {
299 e_data = e;
300 }
301 }
302 efl_key_data_set(e, "_shot", e_data);
303 _shot_needed = EINA_TRUE;
304 Efl_Event ev;
305 ev.info = NULL;
306 ev.object = e;
307 _evas_render_post_cb(NULL, &ev);
308
309 if (_scan_objects && _dest_type == FTYPE_EXU)
310 {
311 Eina_Iterator *iter;
312 Eo *obj;
313 Exactness_Objects *e_objs = calloc(1, sizeof(*e_objs));
314 iter = eo_objects_iterator_new();
315 EINA_ITERATOR_FOREACH(iter, obj)
316 {
317 if (!efl_isa(obj, EFL_CANVAS_OBJECT_CLASS) &&
318 !efl_isa(obj, EFL_CANVAS_SCENE_INTERFACE)) continue;
319 Exactness_Object *e_obj = calloc(1, sizeof(*e_obj));
320 Eo *parent = efl_parent_get(obj);
321 e_obj->id = (long long) obj;
322 if (efl_isa(parent, EFL_CANVAS_OBJECT_CLASS) ||
323 efl_isa(parent, EFL_CANVAS_SCENE_INTERFACE))
324 {
325 e_obj->parent_id = (long long) efl_parent_get(obj);
326 }
327 else
328 {
329 e_obj->parent_id = 0;
330 }
331 e_obj->kl_name = eina_stringshare_add(efl_class_name_get(obj));
332 if (efl_isa(obj, EFL_CANVAS_OBJECT_CLASS))
333 {
334 Eina_Size2D sz = efl_gfx_entity_size_get(obj);
335 e_obj->w = sz.w;
336 e_obj->h = sz.h;
337 Eina_Position2D pos = efl_gfx_entity_position_get(obj);
338 e_obj->x = pos.x;
339 e_obj->y = pos.y;
340 }
341 e_objs->objs = eina_list_append(e_objs->objs, e_obj);
342 }
343 eina_iterator_free(iter);
344 _dest_unit->objs = eina_list_append(_dest_unit->objs, e_objs);
345 }
346}
347
348static void
349_feed_event(Exactness_Action_Type type, unsigned int n_evas, void *data)
350{
351 static Evas_Object *rect = NULL;
352 static unsigned int rect_evas;
353
354 Eo *e = eina_list_nth(_evas_list, n_evas);
355
356 if (rect && rect_evas != n_evas)
357 {
358 efl_del(rect);
359 rect = NULL;
360 }
361 if (_verbose && !rect)
362 {
363 rect = evas_object_rectangle_add(e);
364 evas_object_repeat_events_set(rect, EINA_TRUE);
365 evas_object_color_set(rect, 255, 0, 0, 255);
366 evas_object_resize(rect, 15, 15);
367 evas_object_layer_set(rect, 100);
368 evas_object_show(rect);
369 rect_evas = n_evas;
370 }
371
372 switch (type)
373 {
374 case EXACTNESS_ACTION_MOUSE_IN:
375 {
376 _printf(1, "Mouse in\n");
377 _printf(2, "%s evas_event_feed_mouse_in n_evas=<%d>\n", __func__, n_evas);
378 if (e) evas_event_feed_mouse_in(e, time(NULL), NULL);
379 break;
380 }
381 case EXACTNESS_ACTION_MOUSE_OUT:
382 {
383 _printf(1, "Mouse out\n");
384 _printf(2, "%s evas_event_feed_mouse_out n_evas=<%d>\n", __func__, n_evas);
385 if (e) evas_event_feed_mouse_out(e, time(NULL), NULL);
386 break;
387 }
388 case EXACTNESS_ACTION_MOUSE_WHEEL:
389 {
390 Exactness_Action_Mouse_Wheel *t = data;
391 _printf(1, "Mouse wheel\n");
392 _printf(2, "%s evas_event_feed_mouse_wheel n_evas=<%d>\n", __func__, n_evas);
393 if (e) evas_event_feed_mouse_wheel(e, t->direction, t->z, time(NULL), NULL);
394
395 break;
396 }
397 case EXACTNESS_ACTION_MULTI_DOWN:
398 {
399 Exactness_Action_Multi_Event *t = data;
400 _printf(2, "%s evas_event_feed_multi_down n_evas=<%d>\n", __func__, n_evas);
401 if (!t->d)
402 {
403 if (e) evas_event_feed_mouse_down(e, t->b, t->flags, time(NULL), NULL);
404 if (rect) evas_object_color_set(rect, 255, 255, 0, 255);
405 }
406 else
407 {
408 if (e) evas_event_feed_multi_down(e,
409 t->d, t->x, t->y, t->rad,
410 t->radx, t->rady, t->pres, t->ang, t->fx, t->fy,
411 t->flags, time(NULL), NULL);
412 }
413
414 break;
415 }
416 case EXACTNESS_ACTION_MULTI_UP:
417 {
418 Exactness_Action_Multi_Event *t = data;
419 _printf(2, "%s evas_event_feed_multi_up n_evas=<%d>\n", __func__, n_evas);
420 if (!t->d)
421 {
422 if (e) evas_event_feed_mouse_up(e, t->b, t->flags, time(NULL), NULL);
423 if (rect) evas_object_color_set(rect, 255, 0, 0, 255);
424 }
425 else
426 {
427 if (e) evas_event_feed_multi_up(e,
428 t->d, t->x, t->y, t->rad,
429 t->radx, t->rady, t->pres, t->ang, t->fx, t->fy,
430 t->flags, time(NULL), NULL);
431 }
432
433 break;
434 }
435 case EXACTNESS_ACTION_MULTI_MOVE:
436 {
437 Exactness_Action_Multi_Move *t = data;
438 _printf(2, "%s evas_event_feed_multi_move n_evas=<%d>\n", __func__, n_evas);
439 if (!t->d)
440 {
441 if (e) evas_event_feed_mouse_move(e, t->x, t->y, time(NULL), NULL);
442 if (rect)
443 {
444 evas_object_move(rect, t->x, t->y);
445 evas_object_color_set(rect, 255, 0, 0, 255);
446 }
447 }
448 else
449 {
450 if (e) evas_event_feed_multi_move(e,
451 t->d, t->x, t->y, t->rad,
452 t->radx, t->rady, t->pres, t->ang, t->fx, t->fy,
453 time(NULL), NULL);
454 }
455
456 break;
457 }
458 case EXACTNESS_ACTION_KEY_DOWN:
459 {
460 Exactness_Action_Key_Down_Up *t = data;
461 _printf(2, "%s evas_event_feed_key_down n_evas=<%d>\n", __func__, n_evas);
462 if (e)
463 evas_event_feed_key_down_with_keycode(e,
464 t->keyname, t->key, t->string,
465 t->compose, time(NULL), NULL, t->keycode);
466 break;
467 }
468 case EXACTNESS_ACTION_KEY_UP:
469 {
470 Exactness_Action_Key_Down_Up *t = data;
471 _printf(2, "%s evas_event_feed_key_up n_evas=<%d>\n", __func__, n_evas);
472 if (e) evas_event_feed_key_up_with_keycode(e,
473 t->keyname, t->key, t->string,
474 t->compose, time(NULL), NULL, t->keycode);
475
476 break;
477 }
478 case EXACTNESS_ACTION_TAKE_SHOT:
479 {
480 _printf(2, "%s take shot n_evas=<%d>\n", __func__, n_evas);
481 if (rect) evas_object_color_set(rect, 0, 0, 255, 255);
482 _cur_shot_id++;
483 if (_dest_type != FTYPE_UNKNOWN && e) _shot_do(e);
484 break;
485 }
486 case EXACTNESS_ACTION_EFL_EVENT:
487 {
488 Exactness_Action_Efl_Event *t = data;
489 Eina_Bool found = EINA_FALSE;
490 Eina_List *itr;
491 EINA_LIST_FOREACH(_evas_list, itr, e)
492 {
493 Eo *o = efl_name_find(e, t->wdg_name);
494 if (o)
495 {
496 _printf(2, "%s EFL event invoke %s on %s\n",
497 __func__, t->event_name, t->wdg_name);
498 Efl_Event_Description d;
499 found = EINA_TRUE;
500 memset(&d, 0, sizeof(d));
501 d.name = t->event_name;
502 d.legacy_is = EINA_TRUE;
503 efl_event_callback_legacy_call(o, &d, NULL);
504#if 0
505 /* Remove when events stuff work well */
506 Eina_Size2D sz = efl_gfx_size_get(o);
507 Eina_Position2D pos = efl_gfx_position_get(o);
508 if (!strcmp(t->event_name, "clicked") ||
509 !strcmp(t->event_name, "clicked,double"))
510 {
511 int x = pos.x + (sz.w / 2);
512 int y = pos.y + (sz.h / 2);
513 evas_event_feed_mouse_move(e, x, y, time(NULL), NULL);
514 evas_event_feed_mouse_down(e, 0, EVAS_BUTTON_NONE, time(NULL), NULL);
515 evas_event_feed_mouse_up(e, 0, EVAS_BUTTON_NONE, time(NULL), NULL);
516 if (rect)
517 {
518 evas_object_move(rect, x, y);
519 evas_object_color_set(rect, 255, 0, 0, 255);
520 }
521 if (!strcmp(t->event_name, "clicked,double"))
522 {
523 evas_event_feed_mouse_down(e, 0, EVAS_BUTTON_DOUBLE_CLICK,
524 time(NULL), NULL);
525 evas_event_feed_mouse_up(e, 0, EVAS_BUTTON_DOUBLE_CLICK,
526 time(NULL), NULL);
527 }
528 }
529#endif
530 }
531 }
532 if (!found) fprintf(stderr, "Failed finding %s.\n", t->wdg_name);
533 break;
534 }
535 case EXACTNESS_ACTION_CLICK_ON:
536 {
537 Exactness_Action_Click_On *t = data;
538 Eina_List *itr;
539 Eo *o;
540 n_evas = 0;
541 EINA_LIST_FOREACH(_evas_list, itr, e)
542 {
543 o = efl_name_find(e, t->wdg_name);
544 if (o) goto wdg_found;
545 n_evas++;
546 }
547 o = NULL;
548wdg_found:
549 if (o)
550 {
551 Eina_Size2D sz = efl_gfx_entity_size_get(o);
552 Eina_Position2D pos = efl_gfx_entity_position_get(o);
553 int x = pos.x + (sz.w / 2);
554 int y = pos.y + (sz.h / 2);
555 Exactness_Action_Multi_Move *d_move = calloc(1, sizeof(*d_move));
556 Exactness_Action_Multi_Event *d_event = calloc(1, sizeof(*d_event));
557 Exactness_Action *act, *prev_act = eina_list_data_get(_cur_event_list);
558
559 _printf(2, "%s click on %s\n", __func__, t->wdg_name);
560 act = calloc(1, sizeof(*act));
561 act->type = EXACTNESS_ACTION_MULTI_MOVE;
562 act->delay_ms = 100;
563 act->n_evas = n_evas;
564 act->data = d_move;
565 d_move->x = x;
566 d_move->y = y;
567 _cur_event_list = eina_list_append_relative(_cur_event_list,
568 act, prev_act);
569 prev_act = act;
570
571 act = calloc(1, sizeof(*act));
572 act->type = EXACTNESS_ACTION_MULTI_DOWN;
573 act->delay_ms = 100;
574 act->n_evas = n_evas;
575 act->data = d_event;
576 d_event->b = 1;
577 _cur_event_list = eina_list_append_relative(_cur_event_list,
578 act, prev_act);
579 prev_act = act;
580
581 act = calloc(1, sizeof(*act));
582 act->type = EXACTNESS_ACTION_MULTI_UP;
583 act->delay_ms = 100;
584 act->n_evas = n_evas;
585 d_event = calloc(1, sizeof(*d_event));
586 act->data = d_event;
587 d_event->b = 1;
588 _cur_event_list = eina_list_append_relative(_cur_event_list,
589 act, prev_act);
590 }
591 else fprintf(stderr, "Failed finding %s.\n", t->wdg_name);
592 break;
593 }
594 case EXACTNESS_ACTION_STABILIZE:
595 {
596 _printf(2, "%s stabilize\n", __func__);
597 if (rect) evas_object_color_set(rect, 255, 165, 0, 255);
598 ecore_timer_add(0.1, _stabilization_timer_cb, NULL);
599 break;
600 }
601 default: /* All non-input events are not handeled */
602 break;
603 }
604}
605
606static Eina_Bool
607_feed_event_timer_cb(void *data EINA_UNUSED)
608{
609 if (_pause_request) return ECORE_CALLBACK_CANCEL;
610 Exactness_Action *act = eina_list_data_get(_cur_event_list);
611 if (act) _feed_event(act->type, act->n_evas, act->data);
612
613 _cur_event_list = eina_list_next(_cur_event_list);
614 if (!_cur_event_list)
615 { /* Finished reading all events */
616 _exit_required = EINA_TRUE;
617 if (!_shot_needed) ecore_main_loop_quit();
618 }
619 else
620 {
621 if (act->type != EXACTNESS_ACTION_STABILIZE)
622 {
623 act = eina_list_data_get(_cur_event_list);
624 _printf(2, " %s timer_time=<%f>\n", __func__, act->delay_ms / 1000.0);
625 ecore_timer_add(act->delay_ms / 1000.0, _feed_event_timer_cb, NULL);
626 }
627 }
628 return ECORE_CALLBACK_CANCEL;
629}
630
631static Eina_Bool
632_stabilization_timer_cb(void *data EINA_UNUSED)
633{
634 Eina_List *itr;
635 Evas *e;
636#define STAB_MAX 5
637 static int need_more = STAB_MAX;
638 _printf(2, "Not stable yet!\n");
639 EINA_LIST_FOREACH(_evas_list, itr, e)
640 {
641 if (!e) continue;
642 Exactness_Image *last_img = efl_key_data_get(e, "_last_stab_shot");
643 Exactness_Image *cur_img = _snapshot_shot_get(e);
644 if (!last_img || exactness_image_compare(last_img, cur_img, NULL)) need_more = STAB_MAX;
645 exactness_image_free(last_img);
646 efl_key_data_set(e, "_last_stab_shot", cur_img);
647 }
648 EINA_LIST_FOREACH(_evas_list, itr, e)
649 {
650 if (!need_more)
651 {
652 evas_object_del(efl_key_data_get(e, "_snapshot"));
653 efl_key_data_set(e, "_snapshot", NULL);
654 }
655 }
656 if (!need_more)
657 {
658 _playing_status = EINA_FALSE;
659 if (_src_type != FTYPE_REMOTE && !_pause_request)
660 {
661 Exactness_Action *act = eina_list_data_get(_cur_event_list);
662 _printf(2, " %s timer_time=<%f>\n", __func__, act->delay_ms / 1000.0);
663 ecore_timer_add(act->delay_ms / 1000.0, _feed_event_timer_cb, NULL);
664 }
665 need_more = STAB_MAX;
666 return ECORE_CALLBACK_CANCEL;
667 }
668 need_more--;
669 return ECORE_CALLBACK_RENEW;
670}
671
672static void
673_main_loop_mouse_in_cb(Eina_Debug_Session *session EINA_UNUSED, int srcid EINA_UNUSED, void *buffer, int size EINA_UNUSED)
674{
675 char *buf = buffer;
676 int n_evas = EXTRACT_INT(buf);
677 _feed_event(EXACTNESS_ACTION_MOUSE_IN, n_evas, NULL);
678}
679
680static void
681_main_loop_mouse_out_cb(Eina_Debug_Session *session EINA_UNUSED, int srcid EINA_UNUSED, void *buffer, int size EINA_UNUSED)
682{
683 char *buf = buffer;
684 int n_evas = EXTRACT_INT(buf);
685 _feed_event(EXACTNESS_ACTION_MOUSE_OUT, n_evas, NULL);
686}
687
688static void
689_main_loop_mouse_wheel_cb(Eina_Debug_Session *session EINA_UNUSED, int srcid EINA_UNUSED, void *buffer, int size EINA_UNUSED)
690{
691 char *buf = buffer;
692 Exactness_Action_Mouse_Wheel t;
693 int n_evas = EXTRACT_INT(buf);
694 t.direction = EXTRACT_INT(buf);
695 t.z = EXTRACT_INT(buf);
696 _feed_event(EXACTNESS_ACTION_MOUSE_WHEEL, n_evas, &t);
697}
698
699static void
700_main_loop_multi_down_cb(Eina_Debug_Session *session EINA_UNUSED, int srcid EINA_UNUSED, void *buffer, int size EINA_UNUSED)
701{
702 char *buf = buffer;
703 Exactness_Action_Multi_Event t;
704 int n_evas = EXTRACT_INT(buf);
705 t.d = EXTRACT_INT(buf);
706 t.b = EXTRACT_INT(buf);
707 t.x = EXTRACT_INT(buf);
708 t.y = EXTRACT_INT(buf);
709 t.rad = EXTRACT_DOUBLE(buf);
710 t.radx = EXTRACT_DOUBLE(buf);
711 t.rady = EXTRACT_DOUBLE(buf);
712 t.pres = EXTRACT_DOUBLE(buf);
713 t.ang = EXTRACT_DOUBLE(buf);
714 t.fx = EXTRACT_DOUBLE(buf);
715 t.fy = EXTRACT_DOUBLE(buf);
716 t.flags = EXTRACT_INT(buf);
717 _feed_event(EXACTNESS_ACTION_MULTI_DOWN, n_evas, &t);
718}
719
720static void
721_main_loop_multi_up_cb(Eina_Debug_Session *session EINA_UNUSED, int srcid EINA_UNUSED, void *buffer, int size EINA_UNUSED)
722{
723 char *buf = buffer;
724 Exactness_Action_Multi_Event t;
725 int n_evas = EXTRACT_INT(buf);
726 t.d = EXTRACT_INT(buf);
727 t.b = EXTRACT_INT(buf);
728 t.x = EXTRACT_INT(buf);
729 t.y = EXTRACT_INT(buf);
730 t.rad = EXTRACT_DOUBLE(buf);
731 t.radx = EXTRACT_DOUBLE(buf);
732 t.rady = EXTRACT_DOUBLE(buf);
733 t.pres = EXTRACT_DOUBLE(buf);
734 t.ang = EXTRACT_DOUBLE(buf);
735 t.fx = EXTRACT_DOUBLE(buf);
736 t.fy = EXTRACT_DOUBLE(buf);
737 t.flags = EXTRACT_INT(buf);
738 _feed_event(EXACTNESS_ACTION_MULTI_UP, n_evas, &t);
739}
740
741static void
742_main_loop_multi_move_cb(Eina_Debug_Session *session EINA_UNUSED, int srcid EINA_UNUSED, void *buffer, int size EINA_UNUSED)
743{
744 char *buf = buffer;
745 Exactness_Action_Multi_Move t;
746 int n_evas = EXTRACT_INT(buf);
747 t.d = EXTRACT_INT(buf);
748 t.x = EXTRACT_INT(buf);
749 t.y = EXTRACT_INT(buf);
750 t.rad = EXTRACT_DOUBLE(buf);
751 t.radx = EXTRACT_DOUBLE(buf);
752 t.rady = EXTRACT_DOUBLE(buf);
753 t.pres = EXTRACT_DOUBLE(buf);
754 t.ang = EXTRACT_DOUBLE(buf);
755 t.fx = EXTRACT_DOUBLE(buf);
756 t.fy = EXTRACT_DOUBLE(buf);
757 _feed_event(EXACTNESS_ACTION_MULTI_MOVE, n_evas, &t);
758}
759
760static void
761_main_loop_key_down_cb(Eina_Debug_Session *session EINA_UNUSED, int srcid EINA_UNUSED, void *buffer, int size EINA_UNUSED)
762{
763 char *buf = buffer;
764 Exactness_Action_Key_Down_Up t;
765 int n_evas = EXTRACT_INT(buf);
766 t.keyname = EXTRACT_STRING(buf);
767 t.key = EXTRACT_STRING(buf);
768 t.string = EXTRACT_STRING(buf);
769 t.compose = EXTRACT_STRING(buf);
770 t.keycode = EXTRACT_INT(buf);
771 _feed_event(EXACTNESS_ACTION_KEY_DOWN, n_evas, &t);
772}
773
774static void
775_main_loop_key_up_cb(Eina_Debug_Session *session EINA_UNUSED, int srcid EINA_UNUSED, void *buffer, int size EINA_UNUSED)
776{
777 char *buf = buffer;
778 Exactness_Action_Key_Down_Up t;
779 int n_evas = EXTRACT_INT(buf);
780 t.keyname = EXTRACT_STRING(buf);
781 t.key = EXTRACT_STRING(buf);
782 t.string = EXTRACT_STRING(buf);
783 t.compose = EXTRACT_STRING(buf);
784 t.keycode = EXTRACT_INT(buf);
785 _feed_event(EXACTNESS_ACTION_KEY_UP, n_evas, &t);
786}
787
788static void
789_main_loop_take_shot_cb(Eina_Debug_Session *session, int srcid, void *buffer, int size EINA_UNUSED)
790{
791 char *buf = buffer;
792 int n_evas = EXTRACT_INT(buf);
793 _feed_event(EXACTNESS_ACTION_TAKE_SHOT, n_evas, NULL);
794 _last_debug_session = session;
795 _last_debug_src_cid = srcid;
796}
797
798static void
799_main_loop_efl_event_cb(Eina_Debug_Session *session EINA_UNUSED, int srcid EINA_UNUSED, void *buffer, int size EINA_UNUSED)
800{
801 char *buf = buffer;
802 Exactness_Action_Efl_Event t;
803 t.wdg_name = EXTRACT_STRING(buf);
804 t.event_name = EXTRACT_STRING(buf);
805 _feed_event(EXACTNESS_ACTION_EFL_EVENT, 0, &t);
806}
807
808static void
809_main_loop_click_on_cb(Eina_Debug_Session *session EINA_UNUSED, int srcid EINA_UNUSED, void *buffer, int size EINA_UNUSED)
810{
811 char *buf = buffer;
812 Exactness_Action_Click_On t;
813 t.wdg_name = EXTRACT_STRING(buf);
814 _feed_event(EXACTNESS_ACTION_CLICK_ON, 0, &t);
815}
816
817static void
818_main_loop_stabilize_cb(Eina_Debug_Session *session EINA_UNUSED, int srcid EINA_UNUSED, void *buffer EINA_UNUSED, int size EINA_UNUSED)
819{
820 _feed_event(EXACTNESS_ACTION_STABILIZE, 0, NULL);
821}
822
823static void
824_main_loop_finish_cb(Eina_Debug_Session *session EINA_UNUSED, int srcid EINA_UNUSED, void *buffer EINA_UNUSED, int size EINA_UNUSED)
825{
826 ecore_main_loop_quit();
827}
828
829WRAPPER_TO_XFER_MAIN_LOOP(_mouse_in_cb)
830WRAPPER_TO_XFER_MAIN_LOOP(_mouse_out_cb)
831WRAPPER_TO_XFER_MAIN_LOOP(_mouse_wheel_cb)
832WRAPPER_TO_XFER_MAIN_LOOP(_multi_down_cb)
833WRAPPER_TO_XFER_MAIN_LOOP(_multi_up_cb)
834WRAPPER_TO_XFER_MAIN_LOOP(_multi_move_cb)
835WRAPPER_TO_XFER_MAIN_LOOP(_key_down_cb)
836WRAPPER_TO_XFER_MAIN_LOOP(_key_up_cb)
837WRAPPER_TO_XFER_MAIN_LOOP(_take_shot_cb)
838WRAPPER_TO_XFER_MAIN_LOOP(_efl_event_cb)
839WRAPPER_TO_XFER_MAIN_LOOP(_click_on_cb)
840WRAPPER_TO_XFER_MAIN_LOOP(_stabilize_cb)
841WRAPPER_TO_XFER_MAIN_LOOP(_finish_cb)
842
843EINA_DEBUG_OPCODES_ARRAY_DEFINE(_debug_ops,
844 {"Exactness/Actions/Mouse In", NULL, &_mouse_in_cb},
845 {"Exactness/Actions/Mouse Out", NULL, &_mouse_out_cb},
846 {"Exactness/Actions/Mouse Wheel", NULL, &_mouse_wheel_cb},
847 {"Exactness/Actions/Multi Down", NULL, &_multi_down_cb},
848 {"Exactness/Actions/Multi Up", NULL, &_multi_up_cb},
849 {"Exactness/Actions/Multi Move", NULL, &_multi_move_cb},
850 {"Exactness/Actions/Key Down", NULL, &_key_down_cb},
851 {"Exactness/Actions/Key Up", NULL, &_key_up_cb},
852 {"Exactness/Actions/Take Shot", &_take_shot_op, &_take_shot_cb},
853 {"Exactness/Actions/EFL Event", NULL, &_efl_event_cb},
854 {"Exactness/Actions/Click On", NULL, &_click_on_cb},
855 {"Exactness/Actions/Stabilize", NULL, &_stabilize_cb},
856 {"Exactness/Actions/Finish", NULL, &_finish_cb},
857 {NULL, NULL, NULL}
858);
859
860static Eina_Bool
861_src_feed(void *data EINA_UNUSED)
862{
863 if (!_evas_list) return EINA_TRUE;
864 _cur_event_list = _src_unit->actions;
865 Exactness_Action *act = eina_list_data_get(_cur_event_list);
866
867 if (act && act->delay_ms)
868 {
869 _printf(2, " Waiting <%f>\n", act->delay_ms / 1000.0);
870 ecore_timer_add(act->delay_ms / 1000.0, _feed_event_timer_cb, NULL);
871 }
872 else
873 {
874 _feed_event_timer_cb(NULL);
875 }
876 return EINA_FALSE;
877}
878
879static Eina_Bool
880_src_open()
881{
882 if (_src_type != FTYPE_REMOTE)
883 {
884 Eina_List *itr, *itr2;
885 Exactness_Action *act;
886 _printf(2, "<%s> Source file is <%s>\n", __func__, _src_filename);
887 if (_src_type == FTYPE_EXU)
888 {
889 _src_unit = exactness_unit_file_read(_src_filename);
890 }
891 else if (_src_type == FTYPE_REC)
892 {
893 _src_unit = legacy_rec_file_read(_src_filename);
894 }
895 if (!_src_unit) return EINA_FALSE;
896 if (_stabilize_shots)
897 {
898 Exactness_Action_Type last_action_type = EXACTNESS_ACTION_UNKNOWN;
899 EINA_LIST_FOREACH_SAFE(_src_unit->actions, itr, itr2, act)
900 {
901 if (act->type == EXACTNESS_ACTION_TAKE_SHOT &&
902 last_action_type != EXACTNESS_ACTION_STABILIZE)
903 {
904 Exactness_Action *act2 = calloc(1, sizeof(*act2));
905 act2->type = EXACTNESS_ACTION_STABILIZE;
906 _src_unit->actions = eina_list_prepend_relative(_src_unit->actions, act2, act);
907 }
908 last_action_type = act->type;
909 }
910 }
911 if (_speed && _speed != 1)