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