1 #include <Eina.h>
2 #include <Ecore.h>
3 #include <Evas.h>
4 #include <Ecore_Evas.h>
5 #include <Ecore_File.h>
6 #include <Edje.h>
7 #include <Emotion.h>
8 #include <termios.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <unistd.h>
12 #include <string.h>
13 #include "private.h"
14 #include "tycommon.h"
15 
16 enum {
17   CENTER,
18   FILL,
19   STRETCH,
20   NOIMG
21 };
22 
23 #define VIDEO_DECODE_TIMEOUT 1.0
24 
25 static Evas *evas = NULL;
26 static struct termios told, tnew;
27 static int tw = 0, th = 0, cw = 0, ch = 0, maxw = 0, maxh = 0, _mode = CENTER;
28 static Ecore_Timer *timeout_t = NULL;
29 
30 #include "extns.h"
31 
32 static int
echo_off(void)33 echo_off(void)
34 {
35    if (tcgetattr(0, &told) != 0) return -1;
36    tnew = told;
37    tnew.c_lflag &= ~ECHO;
38    if (tcsetattr(0, TCSAFLUSH, &tnew) != 0) return -1;
39    return 0;
40 }
41 
42 static int
echo_on(void)43 echo_on(void)
44 {
45    return tcsetattr(0, TCSAFLUSH, &told);
46 }
47 
48 static void
scaleterm(int w,int h,int * iw,int * ih)49 scaleterm(int w, int h, int *iw, int *ih)
50 {
51    int width = maxw ? maxw : tw;
52    if (w > (width * cw))
53      {
54         *iw = width;
55         *ih = ((h * (width * cw) / w) + (ch - 1)) / ch;
56      }
57    else
58      {
59         *iw = (w + (cw - 1)) / cw;
60         *ih = (h + (ch - 1)) / ch;
61      }
62    if (maxh && *ih > maxh)
63      {
64         *ih = maxh;
65         *iw = ((w * (maxh * ch) / h) + (cw - 1)) / cw;
66      }
67 }
68 
69 static const char *
is_fmt(const char * f,const char ** extn)70 is_fmt(const char *f, const char **extn)
71 {
72    int i, len;
73 
74    len = strlen(f);
75    for (i = 0; extn[i]; i++)
76      {
77         int l = strlen(extn[i]);
78         if (len < l) continue;
79         if (!strcasecmp(extn[i], f + len - l)) return extn[i];
80      }
81    return NULL;
82 }
83 
84 static void
prnt(const char * path,int w,int h,int mode)85 prnt(const char *path, int w, int h, int mode)
86 {
87    int x, y, i;
88    char *line, buf[4096];
89 
90    if ((w >= 512) || (h >= 512)) return;
91    line = malloc(w + 100);
92    if (!line) return;
93    if (mode == CENTER)
94      snprintf(buf, sizeof(buf), "%c}ic#%i;%i;%s", 0x1b, w, h, path);
95    else if (mode == FILL)
96      snprintf(buf, sizeof(buf), "%c}if#%i;%i;%s", 0x1b, w, h, path);
97    else
98      snprintf(buf, sizeof(buf), "%c}is#%i;%i;%s", 0x1b, w, h, path);
99    if (ty_write(1, buf, strlen(buf) + 1) < 0)
100      perror("write");
101    i = 0;
102    line[i++] = 0x1b;
103    line[i++] = '}';
104    line[i++] = 'i';
105    line[i++] = 'b';
106    line[i++] = 0;
107    for (x = 0; x < w; x++) line[i++] = '#';
108    line[i++] = 0x1b;
109    line[i++] = '}';
110    line[i++] = 'i';
111    line[i++] = 'e';
112    line[i++] = 0;
113    line[i++] = '\n';
114    for (y = 0; y < h; y++)
115      {
116         if (ty_write(1, line, i) < 0)
117           perror("write");
118      }
119    free(line);
120 }
121 
122 static void
print_usage(const char * argv0)123 print_usage(const char *argv0)
124 {
125    printf("Usage: %s "HELP_ARGUMENT_SHORT" [-s|-f|-c] [-g <width>x<height>] FILE1 [FILE2 ...]\n"
126           "\n"
127           "  -s  Stretch file to fill nearest character cell size\n"
128           "  -f  Fill file to totally cover character cells with no gaps\n"
129           "  -c  Center file in nearest character cells but only scale down (default)\n"
130           "  -g <width>x<height>  Set maximum geometry for the image (cell count)\n"
131           HELP_ARGUMENT_DOC"\n",
132          argv0);
133 }
134 
135 static Eina_Bool
timeout_cb(void * data)136 timeout_cb(void *data)
137 {
138    evas_object_del(data);
139    timeout_t = NULL;
140 
141    return ECORE_CALLBACK_CANCEL;
142 }
143 
144 static int
handle_image(char * rp)145 handle_image(char *rp)
146 {
147    Evas_Object *o;
148    int w = 0, h = 0;
149    int iw = 0, ih = 0;
150    int r = -1;
151 
152    if (!is_fmt(rp, extn_img) &&
153        !is_fmt(rp, extn_scale) &&
154        !is_fmt(rp, extn_mov))
155      return -1;
156 
157    o = evas_object_image_add(evas);
158    evas_object_image_file_set(o, rp, NULL);
159    evas_object_image_size_get(o, &w, &h);
160    if ((w >= 0) && (h > 0))
161      {
162         scaleterm(w, h, &iw, &ih);
163         prnt(rp, iw, ih, _mode);
164         r = 0;
165      }
166 
167    evas_object_del(o);
168 
169    return r;
170 }
171 
172 static int
handle_edje(char * rp)173 handle_edje(char *rp)
174 {
175    Evas_Object *o;
176    int iw = 0, ih = 0;
177    int r = -1;
178 
179    if (!is_fmt(rp, extn_edj)) return -1;
180 
181    o = edje_object_add(evas);
182    if (edje_object_file_set
183        (o, rp, "terminology/background") == EINA_TRUE ||
184        !edje_object_file_set
185        (o, rp, "e/desktop/background"))
186      {
187         Evas_Coord mw = 0, mh = 0;
188         edje_object_size_min_get(o, &mw, &mh);
189         if ((mw <= 0) || (mh <= 0))
190           edje_object_size_min_calc(o, &mw, &mh);
191         if ((mw <= 0) || (mh <= 0))
192           {
193              mw = (tw) * cw;
194              mh = (th - 1) * ch;
195           }
196         scaleterm(mw, mh, &iw, &ih);
197         prnt(rp, iw, ih, _mode);
198         r = 0;
199      }
200 
201    evas_object_del(o);
202 
203    return r;
204 }
205 
206 static void
video_decoded(void * data,Evas_Object * o,void * ei EINA_UNUSED)207 video_decoded(void *data, Evas_Object *o, void *ei EINA_UNUSED)
208 {
209    int w = 0, h = 0;
210    int iw = 0, ih = 0;
211 
212    if (emotion_object_video_handled_get(o))
213      {
214         emotion_object_size_get(o, &w, &h);
215         if ((w >= 0) && (h > 0))
216           {
217              scaleterm(w, h, &iw, &ih);
218              prnt(data, iw, ih, _mode);
219              goto done;
220           }
221         else
222           {
223              double ar = emotion_object_ratio_get(o);
224              if (ar > 0.0)
225                {
226                   scaleterm(tw * cw, (int) ((tw * cw) / ar), &iw, &ih);
227                   prnt(data, iw, ih, _mode);
228                   goto done;
229                }
230           }
231      }
232 
233    prnt(data, tw, 3, NOIMG);
234 
235 done:
236    ecore_timer_del(timeout_t);
237    timeout_t = NULL;
238    evas_object_del(o);
239    free(data);
240 }
241 
242 static int
handle_video(char * rp)243 handle_video(char *rp)
244 {
245    Evas_Object *o;
246 
247    if (!is_fmt(rp, extn_aud) &&
248        !is_fmt(rp, extn_mov))
249      return -1;
250 
251    o = emotion_object_add(evas);
252    if (emotion_object_init(o, NULL) == EINA_TRUE)
253      {
254         if (emotion_object_file_set(o, rp))
255           {
256              emotion_object_audio_mute_set(o, EINA_TRUE);
257              emotion_object_play_set(o, EINA_TRUE);
258              timeout_t = ecore_timer_add(VIDEO_DECODE_TIMEOUT,
259                                          timeout_cb, o);
260              evas_object_smart_callback_add(o, "frame_decode",
261                                             video_decoded,
262                                             strdup(rp));
263              return 0;
264           }
265 
266      }
267 
268    evas_object_del(o);
269 
270    return -1;
271 }
272 
273 static Eina_Bool
handle_file(void * data)274 handle_file(void *data)
275 {
276    Eina_List **file_q = data;
277 
278    int (*handlers[])(char *rp) = {
279      handle_image,
280      handle_edje,
281      handle_video,
282      NULL
283    };
284    char *rp;
285    int i;
286 
287    if (timeout_t) return ECORE_CALLBACK_RENEW;
288    if (!(*file_q))
289      {
290         ecore_main_loop_quit();
291         return ECORE_CALLBACK_CANCEL;
292      }
293 
294    rp = eina_list_data_get(*file_q);
295    *file_q = eina_list_remove_list(*file_q, *file_q);
296    if (!rp) return ECORE_CALLBACK_RENEW;
297 
298    for (i = 0; handlers[i]; i++)
299      {
300         if (handlers[i](rp) == 0) break;
301      }
302    free(rp);
303 
304    return ECORE_CALLBACK_RENEW;
305 }
306 
307 int
main(int argc,char ** argv)308 main(int argc, char **argv)
309 {
310    Ecore_Evas *ee;
311    char buf[64];
312    int i;
313    char *rp;
314    Eina_List *file_q = NULL;
315 
316    ON_NOT_RUNNING_IN_TERMINOLOGY_EXIT_1();
317    ARGUMENT_ENTRY_CHECK(argc, argv, print_usage);
318    if (argc <= 1)
319      {
320         print_usage(argv[0]);
321         return 0;
322      }
323 
324    eina_init();
325    ecore_app_no_system_modules();
326    ecore_init();
327    ecore_file_init();
328    evas_init();
329    ecore_evas_init();
330    edje_init();
331    emotion_init();
332 
333    ee = ecore_evas_buffer_new(1, 1);
334    if (!ee)
335      goto shutdown;
336    evas = ecore_evas_get(ee);
337    echo_off();
338    snprintf(buf, sizeof(buf), "%c}qs", 0x1b);
339    if (ty_write(1, buf, strlen(buf) + 1) < 0)
340      {
341         perror("write");
342         echo_on();
343         goto shutdown;
344      }
345    if (scanf("%i;%i;%i;%i", &tw, &th, &cw, &ch) != 4 ||
346        ((tw <= 0) || (th <= 0) || (cw <= 1) || (ch <= 1)))
347      {
348         echo_on();
349         goto shutdown;
350      }
351    echo_on();
352 
353    for (i = 1; i < argc; i++)
354      {
355         char *path;
356 
357         if (!strcmp(argv[i], "-c"))
358           {
359              _mode = CENTER;
360              i++;
361              if (i >= argc) goto done;
362           }
363         else if (!strcmp(argv[i], "-s"))
364           {
365              _mode = STRETCH;
366              i++;
367              if (i >= argc) goto done;
368           }
369         else if (!strcmp(argv[i], "-f"))
370           {
371              _mode = FILL;
372              i++;
373              if (i >= argc) goto done;
374           }
375 
376         if (!strcmp(argv[i], "-g"))
377           {
378              unsigned int width = 0, height = 0;
379              int cnt;
380 
381              if (i + 2 >= argc)
382                {
383                   print_usage(argv[0]);
384                   goto shutdown;
385                }
386              i++;
387              cnt = sscanf(argv[i], "%ux%u", &width, &height);
388              if (cnt != 2)
389                {
390                   print_usage(argv[0]);
391                   goto done;
392                }
393              if (!width || tw > (int)width) maxw = width;
394              maxh = height;
395           }
396         path = argv[i];
397         rp = ecore_file_realpath(path);
398         if (rp)
399           file_q = eina_list_append(file_q, rp);
400      }
401    if (!file_q) goto done;
402 
403    ecore_idler_add(handle_file, &file_q);
404    ecore_main_loop_begin();
405 
406 done:
407    EINA_LIST_FREE(file_q, rp)
408      free(rp);
409 
410    ecore_evas_free(ee);
411 
412 shutdown:
413    emotion_shutdown();
414    edje_shutdown();
415    ecore_evas_shutdown();
416    evas_shutdown();
417    ecore_file_shutdown();
418    ecore_shutdown();
419    eina_shutdown();
420 
421    return 0;
422 }
423