1 #ifdef HAVE_CONFIG_H
2 #include <config.h>
3 #endif
4 
5 #include <stdio.h>
6 #include <string.h>
7 #include <stdlib.h>
8 #include <errno.h>
9 #include <unistd.h>
10 #include <fcntl.h>
11 #include <ctype.h>
12 
13 #include <Evas.h>
14 #include <Ecore.h>
15 #include <Ecore_Getopt.h>
16 #include <Ecore_Evas.h>
17 #include <Edje.h>
18 
19 struct opts
20 {
21    char          *file;
22    char          *group;
23    Eina_Bool      list_groups;
24    char          *engine;
25    Eina_Rectangle size;
26    unsigned char  color[3];
27    Eina_Bool      borderless;
28    Eina_Bool      sticky;
29    Eina_Bool      shaped;
30    Eina_Bool      alpha;
31    Eina_Bool      print;
32    Eina_Bool      slave_mode;
33    double         scale;
34    int            pad;
35    char          *title;
36 };
37 
38 static Eina_Bool _edje_load_or_show_error(Evas_Object *edje, const char *file, const char *group);
39 
40 static Ecore_Evas *win;
41 static Evas *evas;
42 static Evas_Object *bg, *bg2 = NULL, *edje;
43 static struct opts opts;
44 
45 static void
_win_title_set(const char * group,const char * file)46 _win_title_set(const char *group, const char *file)
47 {
48    char buf[1024];
49    snprintf(buf, sizeof(buf), "Edje_Player - %s of %s", group, file);
50    ecore_evas_title_set(win, buf);
51 }
52 
53 static char *
_slave_mode_tok(char ** p_arg)54 _slave_mode_tok(char **p_arg)
55 {
56    char *s, *e;
57    Eina_Bool is_quoted;
58 
59    if (!*p_arg) return NULL;
60 
61    s = *p_arg;
62    while (isspace(*s))
63      s++;
64 
65    if (*s == '\0')
66      {
67         *p_arg = NULL;
68         return NULL;
69      }
70    else if (*s == '"')
71      {
72         is_quoted = EINA_TRUE;
73         s++;
74         *p_arg = s;
75      }
76    else
77      {
78         is_quoted = EINA_FALSE;
79         *p_arg = s;
80      }
81 
82    for (e = s; *e != '\0'; e++)
83      {
84         if ((!is_quoted) && (isspace(*e)))
85           break;
86         else if ((is_quoted) && (*e == '"'))
87           break;
88      }
89 
90    if (*e == '\0') return NULL;
91 
92    *e = '\0';
93    return e + 1;
94 }
95 
96 static void
_slave_mode_signal(Evas_Object * edje,char * args)97 _slave_mode_signal(Evas_Object *edje, char *args)
98 {
99    char *emission, *source;
100 
101    emission = args;
102    source = _slave_mode_tok(&emission);
103    _slave_mode_tok(&source);
104 
105    if ((!emission) || (!source))
106      {
107         fputs("ERROR: Invalid command arguments.\n", stderr);
108         return;
109      }
110 
111    edje_object_signal_emit(edje, emission, source);
112 }
113 
114 static void
_slave_mode_message_string(Evas_Object * edje,int id,char * arg)115 _slave_mode_message_string(Evas_Object *edje, int id, char *arg)
116 {
117    Edje_Message_String msg;
118    msg.str = arg;
119    edje_object_message_send(edje, EDJE_MESSAGE_STRING, id, &msg);
120 }
121 
122 static void
_slave_mode_message_int(Evas_Object * edje,int id,char * arg)123 _slave_mode_message_int(Evas_Object *edje, int id, char *arg)
124 {
125    Edje_Message_Int msg;
126    msg.val = atoi(arg);
127    edje_object_message_send(edje, EDJE_MESSAGE_INT, id, &msg);
128 }
129 
130 static void
_slave_mode_message_float(Evas_Object * edje,int id,char * arg)131 _slave_mode_message_float(Evas_Object *edje, int id, char *arg)
132 {
133    Edje_Message_Float msg;
134    msg.val = atof(arg);
135    edje_object_message_send(edje, EDJE_MESSAGE_FLOAT, id, &msg);
136 }
137 
138 static void
_slave_mode_message_string_set(Evas_Object * edje,int id,char * arg,char * extra_args)139 _slave_mode_message_string_set(Evas_Object *edje, int id, char *arg,
140                                char *extra_args)
141 {
142    Edje_Message_String_Set *msg;
143    int count, i;
144 
145    count = atoi(arg);
146    msg = alloca(sizeof(Edje_Message_String_Set) + (count - 1) * sizeof(char *));
147 
148    for (i = 0; i < count; i++)
149      {
150         char *next = _slave_mode_tok(&extra_args);
151         if (!extra_args)
152           {
153              fputs("ERROR: Message missing arg.\n", stderr);
154              return;
155           }
156         msg->str[i] = extra_args;
157         extra_args = next;
158      }
159 
160    msg->count = count;
161    edje_object_message_send(edje, EDJE_MESSAGE_STRING_SET, id, msg);
162 }
163 
164 static void
_slave_mode_message_int_set(Evas_Object * edje,int id,char * arg,char * extra_args)165 _slave_mode_message_int_set(Evas_Object *edje, int id, char *arg,
166                             char *extra_args)
167 {
168    Edje_Message_Int_Set *msg;
169    int count, i;
170 
171    count = atoi(arg);
172    msg = alloca(sizeof(Edje_Message_Int_Set) + (count - 1) * sizeof(int));
173 
174    for (i = 0; i < count; i++)
175      {
176         char *next = _slave_mode_tok(&extra_args);
177         if (!extra_args)
178           {
179              fputs("ERROR: Message missing arg.\n", stderr);
180              return;
181           }
182         msg->val[i] = atoi(extra_args);
183         extra_args = next;
184      }
185 
186    msg->count = count;
187    edje_object_message_send(edje, EDJE_MESSAGE_INT_SET, id, msg);
188 }
189 
190 static void
_slave_mode_message_float_set(Evas_Object * edje,int id,char * arg,char * extra_args)191 _slave_mode_message_float_set(Evas_Object *edje, int id, char *arg,
192                               char *extra_args)
193 {
194    Edje_Message_Float_Set *msg;
195    int count, i;
196 
197    count = atoi(arg);
198    msg = alloca(sizeof(Edje_Message_Float_Set) + (count - 1) * sizeof(double));
199 
200    for (i = 0; i < count; i++)
201      {
202         char *next = _slave_mode_tok(&extra_args);
203         if (!extra_args)
204           {
205              fputs("ERROR: Message missing arg.\n", stderr);
206              return;
207           }
208         msg->val[i] = atof(extra_args);
209         extra_args = next;
210      }
211 
212    msg->count = count;
213    edje_object_message_send(edje, EDJE_MESSAGE_FLOAT_SET, id, msg);
214 }
215 
216 static void
_slave_mode_message_string_int(Evas_Object * edje,int id,char * arg,char * extra_args)217 _slave_mode_message_string_int(Evas_Object *edje, int id, char *arg,
218                                char *extra_args)
219 {
220    Edje_Message_String_Int msg;
221 
222    if (!extra_args)
223      {
224         fputs("ERROR: Message STRING_INT requires integer arg.\n", stderr);
225         return;
226      }
227    _slave_mode_tok(&extra_args);
228 
229    msg.str = arg;
230    msg.val = atoi(extra_args);
231 
232    edje_object_message_send(edje, EDJE_MESSAGE_STRING_INT, id, &msg);
233 }
234 
235 static void
_slave_mode_message_string_float(Evas_Object * edje,int id,char * arg,char * extra_args)236 _slave_mode_message_string_float(Evas_Object *edje, int id, char *arg,
237                                  char *extra_args)
238 {
239    Edje_Message_String_Float msg;
240 
241    if (!extra_args)
242      {
243         fputs("ERROR: Message STRING_FLOAT requires float arg.\n", stderr);
244         return;
245      }
246    _slave_mode_tok(&extra_args);
247 
248    msg.str = arg;
249    msg.val = atof(extra_args);
250 
251    edje_object_message_send(edje, EDJE_MESSAGE_STRING_FLOAT, id, &msg);
252 }
253 
254 static void
_slave_mode_message_string_int_set(Evas_Object * edje,int id,char * arg,char * extra_args)255 _slave_mode_message_string_int_set(Evas_Object *edje, int id, char *arg,
256                                    char *extra_args)
257 {
258    Edje_Message_String_Int_Set *msg;
259    int count, i;
260    char *val;
261 
262    if (!extra_args)
263      {
264         fputs("ERROR: Message STRING_INT_SET requires int args.\n", stderr);
265         return;
266      }
267 
268    val = _slave_mode_tok(&extra_args);
269    count = atoi(extra_args);
270    msg = alloca(sizeof(Edje_Message_String_Int_Set) +
271                 (count - 1) * sizeof(int));
272 
273    for (i = 0; i < count; i++)
274      {
275         char *next = _slave_mode_tok(&val);
276         if (!val)
277           {
278              fputs("ERROR: Message missing arg.\n", stderr);
279              return;
280           }
281         msg->val[i] = atoi(val);
282         val = next;
283      }
284 
285    msg->count = count;
286    msg->str = arg;
287    edje_object_message_send(edje, EDJE_MESSAGE_STRING_INT_SET, id, msg);
288 }
289 
290 static void
_slave_mode_message_string_float_set(Evas_Object * edje,int id,char * arg,char * extra_args)291 _slave_mode_message_string_float_set(Evas_Object *edje, int id, char *arg,
292                                      char *extra_args)
293 {
294    Edje_Message_String_Float_Set *msg;
295    int count, i;
296    char *val;
297 
298    if (!extra_args)
299      {
300         fputs("ERROR: Message STRING_FLOAT_SET requires float set.\n", stderr);
301         return;
302      }
303 
304    val = _slave_mode_tok(&extra_args);
305    count = atoi(extra_args);
306    msg = alloca(sizeof(Edje_Message_String_Float_Set) +
307                 (count - 1) * sizeof(double));
308 
309    for (i = 0; i < count; i++)
310      {
311         char *next = _slave_mode_tok(&val);
312         if (!val)
313           {
314              fputs("ERROR: Message missing arg.\n", stderr);
315              return;
316           }
317         msg->val[i] = atof(val);
318         val = next;
319      }
320 
321    msg->count = count;
322    msg->str = arg;
323    edje_object_message_send(edje, EDJE_MESSAGE_STRING_FLOAT_SET, id, msg);
324 }
325 
326 static void
_slave_mode_message(Evas_Object * edje,char * args)327 _slave_mode_message(Evas_Object *edje, char *args)
328 {
329    char *id_str, *type, *message_arg, *extra_args;
330    int id;
331 
332    id_str = args;
333    type = _slave_mode_tok(&id_str);
334    message_arg = _slave_mode_tok(&type);
335    extra_args = _slave_mode_tok(&message_arg);
336 
337    if (!id_str)
338      {
339         fputs("ERROR: Message id is required.\n", stderr);
340         return;
341      }
342 
343    id = atoi(id_str);
344 
345    if (!type)
346      {
347         fputs("ERROR: Message type is required.\n", stderr);
348         return;
349      }
350 
351    if (!message_arg)
352      {
353         fputs("ERROR: Missing message argument.\n", stderr);
354         return;
355      }
356 
357    if (!strcmp(type, "STRING"))
358      {
359         _slave_mode_message_string(edje, id, message_arg);
360         return;
361      }
362 
363    if (!strcmp(type, "INT"))
364      {
365         _slave_mode_message_int(edje, id, message_arg);
366         return;
367      }
368 
369    if (!strcmp(type, "FLOAT"))
370      {
371         _slave_mode_message_float(edje, id, message_arg);
372         return;
373      }
374 
375    if (!strcmp(type, "STRING_SET"))
376      {
377         _slave_mode_message_string_set(edje, id, message_arg, extra_args);
378         return;
379      }
380 
381    if (!strcmp(type, "INT_SET"))
382      {
383         _slave_mode_message_int_set(edje, id, message_arg, extra_args);
384         return;
385      }
386 
387    if (!strcmp(type, "FLOAT_SET"))
388      {
389         _slave_mode_message_float_set(edje, id, message_arg, extra_args);
390         return;
391      }
392 
393    if (!strcmp(type, "STRING_INT"))
394      {
395         _slave_mode_message_string_int(edje, id, message_arg, extra_args);
396         return;
397      }
398 
399    if (!strcmp(type, "STRING_FLOAT"))
400      {
401         _slave_mode_message_string_float(edje, id, message_arg, extra_args);
402         return;
403      }
404 
405    if (!strcmp(type, "STRING_INT_SET"))
406      {
407         _slave_mode_message_string_int_set(edje, id, message_arg, extra_args);
408         return;
409      }
410 
411    if (!strcmp(type, "STRING_FLOAT_SET"))
412      {
413         _slave_mode_message_string_float_set(edje, id, message_arg, extra_args);
414         return;
415      }
416 
417    fputs("ERROR: Invalid type. Check types list using \"help\".\n", stderr);
418 }
419 
420 static void
_slave_mode_info(Evas_Object * edje,char * args)421 _slave_mode_info(Evas_Object *edje, char *args)
422 {
423    _slave_mode_tok(&args);
424 
425    if (!args)
426      {
427         fputs("ERROR: Invalid command arguments.\n", stderr);
428         return;
429      }
430 
431    if (!edje_object_part_exists(edje, args))
432      {
433         printf("INFO: \"%s\" does not exist.\n", args);
434      }
435    else
436      {
437         Evas_Coord x, y, w, h;
438         edje_object_part_geometry_get(edje, args, &x, &y, &w, &h);
439         printf("INFO: \"%s\" %d,%d,%d,%d\n", args, x, y, w, h);
440      }
441 }
442 
443 static void
_slave_mode_text(Evas_Object * edje,char * args)444 _slave_mode_text(Evas_Object *edje, char *args)
445 {
446    char *part, *text, *p;
447 
448    if (!args) return;
449    p = strchr(args, ' ');
450    if (!p) return;
451    part = malloc(p - args + 1);
452    strncpy(part, args, p - args);
453    part[p - args] = 0;
454    text = p + 1;
455    edje_object_part_text_set(edje, part, text);
456    free(part);
457 }
458 
459 static void
_slave_mode_quit(Evas_Object * edje EINA_UNUSED,char * args EINA_UNUSED)460 _slave_mode_quit(Evas_Object *edje EINA_UNUSED, char *args EINA_UNUSED)
461 {
462    puts("Bye!");
463    ecore_main_loop_quit();
464 }
465 
466 static void
_slave_mode_help(Evas_Object * edje EINA_UNUSED,char * args EINA_UNUSED)467 _slave_mode_help(Evas_Object *edje EINA_UNUSED, char *args EINA_UNUSED)
468 {
469    puts("Help:\n"
470         "One command per line, arguments separated by space.\n"
471         "Strings may have spaces if enclosed in quotes (\").\n"
472         "\n"
473         "\t<command> [arguments]\n"
474         "\n"
475         "Available commands:\n"
476         "\tsignal <emission> <source>\n"
477         "\t   sends a signal to edje\n"
478         "\tmessage <id> <type> <args list>\n"
479         "\t   sends a message to edje.\n"
480         "\t   Possible types (and args):\n"
481         "\t     * STRING \"string\"\n"
482         "\t     * INT integer\n"
483         "\t     * FLOAT float\n"
484         "\t     * STRING_SET <set length> \"string1\" \"string2\" ...\n"
485         "\t     * INT_SET <set length> integer1 integer2 integer3 ...\n"
486         "\t     * FLOAT_SET <set length> float1 float2 float3 ...\n"
487         "\t     * STRING_INT \"message\" integer\n"
488         "\t     * STRING_FLOAT \"message\" float\n"
489         "\t     * STRING_INT_SET \"string\" <set length> integer1 ...\n"
490         "\t     * STRING_FLOAT_SET \"string\" <set length> float1 float2 ...\n"
491         "\tinfo <part>\n"
492         "\t   Print part geometry: <x>,<y>,<w>,<h>\n"
493         "\ttext <part> <text string>\n"
494         "\t   Set text of named part\n"
495         "\tquit\n"
496         "\t   exit edje player.\n"
497         "\thelp\n"
498         "\t   shows this message.\n");
499    /*
500     * Extension ideas (are they useful?):
501     *  - data: show data value
502     *  - color_class: set color class values (maybe also list?)
503     *  - text_class: set text class values (maybe also list?)
504     *  - play_set: change play state
505     *  - animation_set: change animation state
506     */
507 }
508 
509 struct slave_cmd
510 {
511    const char *cmd;
512    void        (*func)(Evas_Object *edje, char *args);
513 } _slave_mode_commands[] = {
514    {"signal", _slave_mode_signal},
515    {"message", _slave_mode_message},
516    {"info", _slave_mode_info},
517    {"text", _slave_mode_text},
518    {"quit", _slave_mode_quit},
519    {"help", _slave_mode_help},
520    {NULL, NULL}
521 };
522 
523 #ifndef _WIN32
524 static Eina_Bool
_slave_mode(void * data,Ecore_Fd_Handler * fd_handler)525 _slave_mode(void *data, Ecore_Fd_Handler *fd_handler)
526 {
527    Evas_Object *edje = data;
528    char buf[1024], *p;
529    const struct slave_cmd *itr;
530    size_t len;
531 
532    if (ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_ERROR))
533      {
534         fputs("ERROR: error on stdin! Exit.\n", stderr);
535         ecore_main_loop_quit();
536         return ECORE_CALLBACK_CANCEL;
537      }
538    if (!ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_READ))
539      return ECORE_CALLBACK_RENEW;
540 
541    if (!fgets(buf, sizeof(buf), stdin))
542      {
543         fputs("ERROR: end of stdin! Exit.\n", stderr);
544         ecore_main_loop_quit();
545         return ECORE_CALLBACK_CANCEL;
546      }
547 
548    len = strlen(buf);
549    if (len < 1)
550      {
551         fputs("ERROR: no input! Try: help\n", stderr);
552         return ECORE_CALLBACK_RENEW;
553      }
554    if (buf[len - 1] == '\n')
555      {
556         len--;
557         buf[len] = '\0';
558      }
559 
560    p = strchr(buf, ' ');
561    if (p)
562      {
563         *p = '\0';
564         p++;
565 
566         while (isspace(*p))
567           p++;
568         if (*p == '\0')
569           p = NULL;
570 
571         if (p)
572           {
573              char *q = p + strlen(p) - 1;
574              while (isspace(*q))
575                {
576                   *q = '\0';
577                   q--;
578                }
579           }
580      }
581 
582    for (itr = _slave_mode_commands; itr->cmd; itr++)
583      {
584         if (strcasecmp(itr->cmd, buf) == 0)
585           {
586              itr->func(edje, p);
587              break;
588           }
589      }
590 
591    return ECORE_CALLBACK_RENEW;
592 }
593 
594 #endif
595 
596 static void
_print_signal(void * data EINA_UNUSED,Evas_Object * o EINA_UNUSED,const char * emission,const char * source)597 _print_signal(void *data EINA_UNUSED, Evas_Object *o EINA_UNUSED, const char *emission, const char *source)
598 {
599    printf("SIGNAL: \"%s\" \"%s\"\n", emission, source);
600 }
601 
602 static void
_print_message(void * data EINA_UNUSED,Evas_Object * edje EINA_UNUSED,Edje_Message_Type type,int id,void * msg)603 _print_message(void *data EINA_UNUSED, Evas_Object *edje EINA_UNUSED, Edje_Message_Type type, int id, void *msg)
604 {
605    const char *typestr;
606    char buf[64];
607 
608    switch (type)
609      {
610       case EDJE_MESSAGE_NONE:
611         typestr = "NONE";
612         break;
613 
614       case EDJE_MESSAGE_SIGNAL:
615         typestr = "SIGNAL";
616         break;
617 
618       case EDJE_MESSAGE_STRING:
619         typestr = "STRING";
620         break;
621 
622       case EDJE_MESSAGE_INT:
623         typestr = "INT";
624         break;
625 
626       case EDJE_MESSAGE_FLOAT:
627         typestr = "FLOAT";
628         break;
629 
630       case EDJE_MESSAGE_STRING_SET:
631         typestr = "STRING_SET";
632         break;
633 
634       case EDJE_MESSAGE_INT_SET:
635         typestr = "INT_SET";
636         break;
637 
638       case EDJE_MESSAGE_FLOAT_SET:
639         typestr = "FLOAT_SET";
640         break;
641 
642       case EDJE_MESSAGE_STRING_INT:
643         typestr = "STRING_INT";
644         break;
645 
646       case EDJE_MESSAGE_STRING_FLOAT:
647         typestr = "STRING_FLOAT";
648         break;
649 
650       case EDJE_MESSAGE_STRING_INT_SET:
651         typestr = "STRING_INT_SET";
652         break;
653 
654       case EDJE_MESSAGE_STRING_FLOAT_SET:
655         typestr = "STRING_FLOAT_SET";
656         break;
657 
658       default:
659         snprintf(buf, sizeof(buf), "UNKNOWN(%d)", type);
660         typestr = buf;
661      }
662 
663    printf("MESSAGE: type=%s, id=%d", typestr, id);
664 
665    switch (type)
666      {
667       case EDJE_MESSAGE_NONE: break;
668 
669       case EDJE_MESSAGE_SIGNAL: break;
670 
671       case EDJE_MESSAGE_STRING:
672       {
673          Edje_Message_String *m = msg;
674          printf(" \"%s\"", m->str);
675       }
676       break;
677 
678       case EDJE_MESSAGE_INT:
679       {
680          Edje_Message_Int *m = msg;
681          printf(" %d", m->val);
682       }
683       break;
684 
685       case EDJE_MESSAGE_FLOAT:
686       {
687          Edje_Message_Float *m = msg;
688          printf(" %f", m->val);
689       }
690       break;
691 
692       case EDJE_MESSAGE_STRING_SET:
693       {
694          Edje_Message_String_Set *m = msg;
695          int i;
696          for (i = 0; i < m->count; i++)
697            printf(" \"%s\"", m->str[i]);
698       }
699       break;
700 
701       case EDJE_MESSAGE_INT_SET:
702       {
703          Edje_Message_Int_Set *m = msg;
704          int i;
705          for (i = 0; i < m->count; i++)
706            printf(" %d", m->val[i]);
707       }
708       break;
709 
710       case EDJE_MESSAGE_FLOAT_SET:
711       {
712          Edje_Message_Float_Set *m = msg;
713          int i;
714          for (i = 0; i < m->count; i++)
715            printf(" %f", m->val[i]);
716       }
717       break;
718 
719       case EDJE_MESSAGE_STRING_INT:
720       {
721          Edje_Message_String_Int *m = msg;
722          printf(" \"%s\" %d", m->str, m->val);
723       }
724       break;
725 
726       case EDJE_MESSAGE_STRING_FLOAT:
727       {
728          Edje_Message_String_Float *m = msg;
729          printf(" \"%s\" %f", m->str, m->val);
730       }
731       break;
732 
733       case EDJE_MESSAGE_STRING_INT_SET:
734       {
735          Edje_Message_String_Int_Set *m = msg;
736          int i;
737          printf(" \"%s\"", m->str);
738          for (i = 0; i < m->count; i++)
739            printf(" %d", m->val[i]);
740       }
741       break;
742 
743       case EDJE_MESSAGE_STRING_FLOAT_SET:
744       {
745          Edje_Message_String_Float_Set *m = msg;
746          int i;
747          printf(" \"%s\"", m->str);
748          for (i = 0; i < m->count; i++)
749            printf(" %f", m->val[i]);
750       }
751       break;
752 
753       default:
754         break;
755      }
756 
757    putchar('\n');
758 }
759 
760 static void
_key_down(void * data EINA_UNUSED,Evas * e EINA_UNUSED,Evas_Object * obj EINA_UNUSED,void * event_info)761 _key_down(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event_info)
762 {
763    Evas_Event_Key_Down *ev = event_info;
764 
765    if ((!strcmp(ev->keyname, "equal")) ||
766        (!strcmp(ev->keyname, "plus")))
767      opts.scale += 0.1;
768    else if ((!strcmp(ev->keyname, "minus")) ||
769             (!strcmp(ev->keyname, "underscore")))
770      opts.scale -= 0.1;
771    else if ((!strcmp(ev->keyname, "0")))
772      opts.scale = 1.0;
773    if (opts.scale < 0.1) opts.scale = 0.1;
774    else if (opts.scale > 10.0)
775      opts.scale = 10.0;
776    edje_scale_set(opts.scale);
777 }
778 
779 static Evas_Object *
_create_bg(void)780 _create_bg(void)
781 {
782    const unsigned char *color = opts.color;
783    Evas_Object *o = evas_object_rectangle_add(evas);
784    if (!o)
785      {
786         fputs("ERROR: could not create background.\n", stderr);
787         return NULL;
788      }
789    evas_object_color_set(o, color[0], color[1], color[2], 255);
790    evas_object_show(o);
791    return o;
792 }
793 
794 static void
_edje_reload(void * data EINA_UNUSED,Evas_Object * obj,const char * emission EINA_UNUSED,const char * source EINA_UNUSED)795 _edje_reload(void *data EINA_UNUSED, Evas_Object *obj, const char *emission EINA_UNUSED, const char *source EINA_UNUSED)
796 {
797    const char *file;
798    const char *group;
799    edje_object_signal_callback_del(obj, "edje,change,file", "edje", _edje_reload);
800    edje_object_file_get(obj, &file, &group);
801    _edje_load_or_show_error(obj, file, group);
802 }
803 
804 static void
_edje_circul(void * data,Evas_Object * obj EINA_UNUSED,void * event_info)805 _edje_circul(void *data, Evas_Object *obj EINA_UNUSED, void *event_info)
806 {
807    char buf[1024] = "";
808    Eina_List *parts = event_info;
809    Eina_List *l;
810    char *part_name;
811    char *group = data;
812 
813    part_name = eina_list_data_get(eina_list_last(parts));
814    strncpy(buf, part_name, sizeof(buf) - 1);
815    part_name[sizeof(buf) - 1] = 0;
816    EINA_LIST_FOREACH(parts, l, part_name)
817      {
818         strncat(buf, " -> ", sizeof(buf) - strlen(buf) - 1);
819         part_name[sizeof(buf) - 1] = 0;
820         strncat(buf, part_name, sizeof(buf) - strlen(buf) - 1);
821         part_name[sizeof(buf) - 1] = 0;
822      }
823 
824    fprintf(stderr, "Group '%s' have a circul dependency between parts: %s\n",
825            group, buf);
826 }
827 
828 static Eina_Bool
_edje_load_or_show_error(Evas_Object * edje,const char * file,const char * group)829 _edje_load_or_show_error(Evas_Object *edje, const char *file, const char *group)
830 {
831    Eina_File *f = NULL;
832    const char *errmsg;
833    int err;
834 
835    f = eina_file_open(file, EINA_FALSE);
836    if (edje_object_file_set(edje, file, group))
837      {
838         edje_object_signal_callback_add(edje, "edje,change,file", "edje", _edje_reload, NULL);
839         evas_object_focus_set(edje, EINA_TRUE);
840         eina_file_close(f);
841         return EINA_TRUE;
842      }
843 
844    err = edje_object_load_error_get(edje);
845    errmsg = edje_load_error_str(err);
846    eina_file_close(f);
847    fprintf(stderr, "ERROR: could not load edje file '%s', group '%s': %s\n",
848            file, group, errmsg);
849    return EINA_FALSE;
850 }
851 
852 static Evas_Object *
_create_edje(void)853 _create_edje(void)
854 {
855    Evas_Coord minw, minh, maxw, maxh;
856    Evas_Object *o = edje_object_add(evas);
857    if (!o)
858      {
859         fputs("ERROR: could not create edje.\n", stderr);
860         return NULL;
861      }
862 
863    if (opts.group)
864      {
865         if (!_edje_load_or_show_error(o, opts.file, opts.group))
866           {
867              evas_object_del(edje);
868              return NULL;
869           }
870         if (!opts.title) _win_title_set(opts.group, opts.file);
871      }
872    else
873      {
874         if (edje_file_group_exists(opts.file, "main"))
875           {
876              if (!_edje_load_or_show_error(o, opts.file, "main"))
877                {
878                   evas_object_del(edje);
879                   return NULL;
880                }
881              if (!opts.title) _win_title_set("main", opts.file);
882           }
883         else
884           {
885              Eina_List *groups = edje_file_collection_list(opts.file);
886              const char *group;
887              if (!groups)
888                {
889                   fprintf(stderr, "ERROR: file '%s' has no groups!\n",
890                           opts.file);
891                   evas_object_del(edje);
892                   return NULL;
893                }
894              group = groups->data;
895              if (!_edje_load_or_show_error(o, opts.file, group))
896                {
897                   edje_file_collection_list_free(groups);
898                   evas_object_del(edje);
899                   return NULL;
900                }
901              if (!opts.title) _win_title_set(group, opts.file);
902              edje_file_collection_list_free(groups);
903           }
904      }
905    evas_object_smart_callback_add(o, "circular,dependency", _edje_circul, opts.group);
906 
907    edje_object_size_max_get(o, &maxw, &maxh);
908    edje_object_size_min_get(o, &minw, &minh);
909    if ((minw <= 0) && (minh <= 0))
910      edje_object_size_min_calc(o, &minw, &minh);
911 
912    ecore_evas_size_max_set(win,
913                            maxw > 0 ? (maxw + opts.pad * 2) : 0,
914                            maxh > 0 ? (maxh + opts.pad * 2) : 0);
915    ecore_evas_size_min_set(win, (minw + opts.pad * 2), (minh + opts.pad * 2));
916 
917    evas_object_show(o);
918 
919    return o;
920 }
921 
922 static unsigned char
_parse_color(EINA_UNUSED const Ecore_Getopt * parser,EINA_UNUSED const Ecore_Getopt_Desc * desc,const char * str,EINA_UNUSED void * data,Ecore_Getopt_Value * storage)923 _parse_color(EINA_UNUSED const Ecore_Getopt *parser, EINA_UNUSED const Ecore_Getopt_Desc *desc, const char *str, EINA_UNUSED void *data, Ecore_Getopt_Value *storage)
924 {
925    unsigned char *color = (unsigned char *)storage->ptrp;
926 
927    if (sscanf(str, "%hhu,%hhu,%hhu", color, color + 1, color + 2) != 3)
928      {
929         fprintf(stderr, "ERROR: incorrect color value '%s'\n", str);
930         return 0;
931      }
932 
933    return 1;
934 }
935 
936 static void
_cb_delete(EINA_UNUSED Ecore_Evas * ee)937 _cb_delete(EINA_UNUSED Ecore_Evas *ee)
938 {
939    ecore_main_loop_quit();
940 }
941 
942 static void
_cb_resize(Ecore_Evas * ee)943 _cb_resize(Ecore_Evas *ee)
944 {
945    int w, h;
946    ecore_evas_geometry_get(ee, NULL, NULL, &w, &h);
947    evas_object_move(edje, opts.pad, opts.pad);
948    evas_object_resize(edje, w - (opts.pad * 2), h - (opts.pad * 2));
949    evas_object_move(bg, opts.pad, opts.pad);
950    evas_object_resize(bg, w - (opts.pad * 2), h - (opts.pad * 2));
951    if (bg2) evas_object_resize(bg2, w, h);
952 }
953 
954 const Ecore_Getopt optdesc = {
955    "edje_player",
956    "%prog [options] <filename.edj>",
957    PACKAGE_VERSION,
958    "(C) 2010 Enlightenment",
959    "BSD with advertisement clause",
960    "Simple application to view edje files.",
961    0,
962    {
963       ECORE_GETOPT_STORE_STR
964         ('g', "group", "The edje group to view (defaults to 'main')."),
965       ECORE_GETOPT_STORE_TRUE
966         ('G', "list-groups", "The groups in the given file."),
967       ECORE_GETOPT_STORE_STR
968         ('e', "engine", "The Ecore-Evas engine to use (see --list-engines)"),
969       ECORE_GETOPT_CALLBACK_NOARGS
970         ('E', "list-engines", "list Ecore-Evas engines",
971         ecore_getopt_callback_ecore_evas_list_engines, NULL),
972       ECORE_GETOPT_CALLBACK_ARGS
973         ('Z', "size", "size to use in wxh form.", "WxH",
974         ecore_getopt_callback_size_parse, NULL),
975       ECORE_GETOPT_CALLBACK_ARGS
976         ('c', "bg-color", "Color of the background (if not shaped or alpha) e.g. 255,150,50",
977         "R,G,B", _parse_color, NULL),
978       ECORE_GETOPT_STORE_TRUE
979         ('b', "borderless", "Display window without border."),
980       ECORE_GETOPT_STORE_TRUE
981         ('y', "sticky", "Display window sticky."),
982       ECORE_GETOPT_STORE_TRUE
983         ('s', "shaped", "Display window shaped."),
984       ECORE_GETOPT_STORE_TRUE
985         ('a', "alpha", "Display window with alpha channel "
986                        "(needs composite manager!)"),
987       ECORE_GETOPT_STORE_STR
988         ('t', "title", "Define the window title string"),
989       ECORE_GETOPT_STORE_TRUE
990         ('p', "print", "Print signals and messages to stdout"),
991       ECORE_GETOPT_STORE_TRUE
992         ('S', "slave-mode", "Listen for commands on stdin"),
993       ECORE_GETOPT_STORE_DOUBLE
994         ('z', "scale", "Set scale factor"),
995       ECORE_GETOPT_STORE_INT
996         ('P', "pad", "Set pixel padding around object"),
997       ECORE_GETOPT_LICENSE('L', "license"),
998       ECORE_GETOPT_COPYRIGHT('C', "copyright"),
999       ECORE_GETOPT_VERSION('V', "version"),
1000       ECORE_GETOPT_HELP('h', "help"),
1001       ECORE_GETOPT_SENTINEL
1002    }
1003 };
1004 
1005 int
main(int argc,char ** argv)1006 main(int argc, char **argv)
1007 {
1008    Eina_Bool quit_option = EINA_FALSE;
1009    int args;
1010    Eina_List *groups;
1011    const char *group;
1012    Ecore_Getopt_Value values[] = {
1013       ECORE_GETOPT_VALUE_STR(opts.group),
1014       ECORE_GETOPT_VALUE_BOOL(opts.list_groups),
1015       ECORE_GETOPT_VALUE_STR(opts.engine),
1016       ECORE_GETOPT_VALUE_BOOL(quit_option),
1017       ECORE_GETOPT_VALUE_PTR_CAST(opts.size),
1018       ECORE_GETOPT_VALUE_PTR_CAST(opts.color),
1019       ECORE_GETOPT_VALUE_BOOL(opts.borderless),
1020       ECORE_GETOPT_VALUE_BOOL(opts.sticky),
1021       ECORE_GETOPT_VALUE_BOOL(opts.shaped),
1022       ECORE_GETOPT_VALUE_BOOL(opts.alpha),
1023       ECORE_GETOPT_VALUE_STR(opts.title),
1024       ECORE_GETOPT_VALUE_BOOL(opts.print),
1025       ECORE_GETOPT_VALUE_BOOL(opts.slave_mode),
1026       ECORE_GETOPT_VALUE_DOUBLE(opts.scale),
1027       ECORE_GETOPT_VALUE_INT(opts.pad),
1028       ECORE_GETOPT_VALUE_BOOL(quit_option),
1029       ECORE_GETOPT_VALUE_BOOL(quit_option),
1030       ECORE_GETOPT_VALUE_BOOL(quit_option),
1031       ECORE_GETOPT_VALUE_BOOL(quit_option),
1032       ECORE_GETOPT_VALUE_NONE
1033    };
1034 
1035    memset(&opts, 0, sizeof(opts));
1036    opts.scale = 1.0;
1037 
1038    if (!ecore_evas_init())
1039      return EXIT_FAILURE;
1040    if (!edje_init())
1041      goto shutdown_ecore_evas;
1042    edje_frametime_set(1.0 / 60.0);
1043 
1044    args = ecore_getopt_parse(&optdesc, values, argc, argv);
1045    if (args < 0)
1046      {
1047         fputs("Could not parse arguments.\n", stderr);
1048         goto shutdown_edje;
1049      }
1050    else if (quit_option)
1051      {
1052         goto end;
1053      }
1054    else if (args >= argc)
1055      {
1056         fputs("Missing edje file to load.\n", stderr);
1057         goto shutdown_edje;
1058      }
1059 
1060    ecore_app_args_set(argc, (const char **)argv);
1061    edje_scale_set(opts.scale);
1062 
1063    // check if the given edj file is there
1064    if (access(argv[args], R_OK) == -1)
1065      {
1066         int e = errno;
1067         fprintf(stderr, "ERROR: file '%s' not accessible, error %d (%s).\n",
1068                 argv[args], e, strerror(e));
1069         goto end;
1070      }
1071 
1072    opts.file = argv[args];
1073    groups = edje_file_collection_list(opts.file);
1074    if (opts.list_groups)
1075      {
1076         Eina_List *n;
1077         printf("%d groups in file '%s':\n", eina_list_count(groups), opts.file);
1078         EINA_LIST_FOREACH(groups, n, group)
1079           printf("\t'%s'\n", group);
1080         edje_file_collection_list_free(groups);
1081         goto end;
1082      }
1083 
1084    if (opts.size.w <= 0) opts.size.w = 320;
1085    if (opts.size.h <= 0) opts.size.h = 240;
1086    win = ecore_evas_new(opts.engine, 0, 0, opts.size.w, opts.size.h, NULL);
1087    if (!win)
1088      {
1089         fprintf(stderr,
1090                 "ERROR: could not create window of "
1091                 "size %dx%d using engine %s.\n",
1092                 opts.size.w, opts.size.h, opts.engine ? opts.engine : "(auto)");
1093         goto shutdown_edje;
1094      }
1095 
1096    ecore_evas_callback_delete_request_set(win, _cb_delete);
1097    evas = ecore_evas_get(win);
1098 
1099    if (opts.alpha)
1100      ecore_evas_alpha_set(win, EINA_TRUE);
1101    else if (opts.shaped)
1102      ecore_evas_shaped_set(win, EINA_TRUE);
1103 
1104    if (opts.pad > 0)
1105      {
1106         bg2 = evas_object_rectangle_add(evas);
1107         evas_object_resize(bg2, opts.size.w, opts.size.h);
1108         if (opts.alpha)
1109           evas_object_color_set(bg2, 0, 0, 0, 64);
1110         else
1111           evas_object_color_set(bg2, 64, 64, 64, 255);
1112         evas_object_show(bg2);
1113      }
1114    bg = _create_bg();
1115 
1116    edje = _create_edje();
1117    if (!edje) goto free_ecore_evas;
1118 
1119    ecore_evas_callback_resize_set(win, _cb_resize);
1120    _cb_resize(win);
1121    evas_object_focus_set(bg, EINA_TRUE);
1122    evas_object_event_callback_add(bg, EVAS_CALLBACK_KEY_DOWN,
1123                                   _key_down, &opts);
1124 
1125    if (opts.print)
1126      {
1127         edje_object_signal_callback_add(edje, "*", "*", _print_signal, NULL);
1128         edje_object_message_handler_set(edje, _print_message, NULL);
1129      }
1130 
1131    if (opts.slave_mode)
1132      {
1133 #ifndef _WIN32
1134         int flags;
1135         flags = fcntl(STDIN_FILENO, F_GETFL, 0);
1136         flags |= O_NONBLOCK;
1137         if (fcntl(STDIN_FILENO, F_SETFL, flags) < 0)
1138           {
1139              fprintf(stderr, "ERROR: Could not set stdin to non-block: %s\n",
1140                      strerror(errno));
1141              goto free_ecore_evas;
1142           }
1143         ecore_main_fd_handler_add(STDIN_FILENO, ECORE_FD_READ | ECORE_FD_ERROR,
1144                                   _slave_mode, edje, NULL, NULL);
1145 #else
1146         /* TODO: port the code above to Windows */
1147         fprintf(stderr, "ERROR: slave mode not working on Windows\n");
1148         goto free_ecore_evas;
1149 #endif
1150      }
1151 
1152    ecore_evas_borderless_set(win, opts.borderless);
1153    ecore_evas_sticky_set(win, opts.sticky);
1154    if (opts.title)
1155      ecore_evas_title_set(win, opts.title);
1156 
1157    ecore_evas_show(win);
1158    ecore_main_loop_begin();
1159 
1160    ecore_evas_free(win);
1161 end:
1162    edje_shutdown();
1163    ecore_evas_shutdown();
1164 
1165    return 0;
1166 
1167 free_ecore_evas:
1168    ecore_evas_free(win);
1169 shutdown_edje:
1170    edje_shutdown();
1171 shutdown_ecore_evas:
1172    ecore_evas_shutdown();
1173    return EXIT_FAILURE;
1174 }
1175 
1176