Git init
[platform/core/uifw/e17.git] / src / bin / e_thumb_main.c
1 #include "config.h"
2
3 #ifdef HAVE_ALLOCA_H
4 # include <alloca.h>
5 #elif defined __GNUC__
6 # define alloca __builtin_alloca
7 #elif defined _AIX
8 # define alloca __alloca
9 #elif defined _MSC_VER
10 # include <malloc.h>
11 # define alloca _alloca
12 #else
13 # include <stddef.h>
14 # ifdef  __cplusplus
15 extern "C"
16 # endif
17 void *alloca(size_t);
18 #endif
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <unistd.h>
23 #include <string.h>
24 #include <Ecore.h>
25 #include <Ecore_Evas.h>
26 #include <Ecore_Ipc.h>
27 #include <Ecore_File.h>
28 #include <Evas.h>
29 #include <Eet.h>
30 #include <Edje.h>
31 #include "e_sha1.h"
32 #include "e_user.h"
33
34 typedef struct _E_Thumb E_Thumb;
35
36 struct _E_Thumb
37 {
38    int   objid;
39    int   w, h;
40    char *file;
41    char *key;
42 };
43
44 /* local subsystem functions */
45 static int       _e_ipc_init(void);
46 static Eina_Bool _e_ipc_cb_server_add(void *data,
47                                       int   type,
48                                       void *event);
49 static Eina_Bool _e_ipc_cb_server_del(void *data,
50                                       int   type,
51                                       void *event);
52 static Eina_Bool _e_ipc_cb_server_data(void *data,
53                                        int   type,
54                                        void *event);
55 static Eina_Bool _e_cb_timer(void *data);
56 static void      _e_thumb_generate(E_Thumb *eth);
57 static char     *_e_thumb_file_id(char *file,
58                                   char *key);
59
60 /* local subsystem globals */
61 static Ecore_Ipc_Server *_e_ipc_server = NULL;
62 static Eina_List *_thumblist = NULL;
63 static Ecore_Timer *_timer = NULL;
64 static char _thumbdir[4096] = "";
65
66 /* externally accessible functions */
67 int
68 main(int    argc,
69      char **argv)
70 {
71    int i;
72
73    for (i = 1; i < argc; i++)
74      {
75         if ((!strcmp(argv[i], "-h")) ||
76             (!strcmp(argv[i], "-help")) ||
77             (!strcmp(argv[i], "--help")))
78           {
79              printf(
80                "This is an internal tool for Enlightenment.\n"
81                "do not use it.\n"
82                );
83              exit(0);
84           }
85         else if (!strncmp(argv[i], "--nice=", 7))
86           {
87              const char *val;
88              int ret = 0;
89
90              val = argv[i] + 7;
91              if (*val)
92                ret = nice(atoi(val));
93           }
94      }
95
96    ecore_init();
97    ecore_app_args_set(argc, (const char **)argv);
98    eet_init();
99    evas_init();
100    ecore_evas_init();
101    edje_init();
102    ecore_file_init();
103    ecore_ipc_init();
104
105    e_user_dir_concat_static(_thumbdir, "fileman/thumbnails");
106    ecore_file_mkpath(_thumbdir);
107
108    if (_e_ipc_init()) ecore_main_loop_begin();
109
110    if (_e_ipc_server)
111      {
112         ecore_ipc_server_del(_e_ipc_server);
113         _e_ipc_server = NULL;
114      }
115
116    ecore_ipc_shutdown();
117    ecore_file_shutdown();
118    ecore_evas_shutdown();
119    edje_shutdown();
120    evas_shutdown();
121    eet_shutdown();
122    ecore_shutdown();
123
124    return 0;
125 }
126
127 /* local subsystem functions */
128 static int
129 _e_ipc_init(void)
130 {
131    char *sdir;
132
133    sdir = getenv("E_IPC_SOCKET");
134    if (!sdir)
135      {
136         printf("The E_IPC_SOCKET environment variable is not set. This is\n"
137                "exported by Enlightenment to all processes it launches.\n"
138                "This environment variable must be set and must point to\n"
139                "Enlightenment's IPC socket file (minus port number).\n");
140         return 0;
141      }
142    _e_ipc_server = ecore_ipc_server_connect(ECORE_IPC_LOCAL_SYSTEM, sdir, 0, NULL);
143    if (!_e_ipc_server) return 0;
144
145    ecore_event_handler_add(ECORE_IPC_EVENT_SERVER_ADD, _e_ipc_cb_server_add, NULL);
146    ecore_event_handler_add(ECORE_IPC_EVENT_SERVER_DEL, _e_ipc_cb_server_del, NULL);
147    ecore_event_handler_add(ECORE_IPC_EVENT_SERVER_DATA, _e_ipc_cb_server_data, NULL);
148
149    return 1;
150 }
151
152 static Eina_Bool
153 _e_ipc_cb_server_add(void *data __UNUSED__,
154                      int type   __UNUSED__,
155                      void      *event)
156 {
157    Ecore_Ipc_Event_Server_Add *e;
158
159    e = event;
160    ecore_ipc_server_send(e->server,
161                          5 /*E_IPC_DOMAIN_THUMB*/,
162                          1 /*hello*/,
163                          0, 0, 0, NULL, 0); /* send hello */
164    return ECORE_CALLBACK_PASS_ON;
165 }
166
167 static Eina_Bool
168 _e_ipc_cb_server_del(void *data  __UNUSED__,
169                      int type    __UNUSED__,
170                      void *event __UNUSED__)
171 {
172    /* quit now */
173     ecore_main_loop_quit();
174     return ECORE_CALLBACK_PASS_ON;
175 }
176
177 static Eina_Bool
178 _e_ipc_cb_server_data(void *data __UNUSED__,
179                       int type   __UNUSED__,
180                       void      *event)
181 {
182    Ecore_Ipc_Event_Server_Data *e;
183    E_Thumb *eth;
184    Eina_List *l;
185    char *file = NULL;
186    char *key = NULL;
187
188    e = event;
189    if (e->major != 5 /*E_IPC_DOMAIN_THUMB*/) return ECORE_CALLBACK_PASS_ON;
190    switch (e->minor)
191      {
192       case 1:
193         if (e->data)
194           {
195              /* begin thumb */
196              /* don't check stuff. since this connects TO e17 it is connecting */
197              /* TO a trusted process that WILL send this message properly */
198              /* formatted. if the thumbnailer dies anyway - it's not a big loss */
199              /* but it is a sign of a bug in e formattign messages maybe */
200                   file = e->data;
201                   key = file + strlen(file) + 1;
202                   if (!key[0]) key = NULL;
203                   eth = calloc(1, sizeof(E_Thumb));
204                   if (eth)
205                     {
206                        eth->objid = e->ref;
207                        eth->w = e->ref_to;
208                        eth->h = e->response;
209                        eth->file = strdup(file);
210                        if (key) eth->key = strdup(key);
211                        _thumblist = eina_list_append(_thumblist, eth);
212                        if (!_timer) _timer = ecore_timer_add(0.001, _e_cb_timer, NULL);
213                     }
214           }
215         break;
216
217       case 2:
218         /* end thumb */
219         EINA_LIST_FOREACH(_thumblist, l, eth)
220           {
221              if (eth->objid == e->ref)
222                {
223                   _thumblist = eina_list_remove_list(_thumblist, l);
224                   if (eth->file) free(eth->file);
225                   if (eth->key) free(eth->key);
226                   free(eth);
227                   break;
228                }
229           }
230         break;
231
232       case 3:
233         /* quit now */
234         ecore_main_loop_quit();
235         break;
236
237       default:
238         break;
239      }
240    return ECORE_CALLBACK_PASS_ON;
241 }
242
243 static Eina_Bool
244 _e_cb_timer(void *data __UNUSED__)
245 {
246    E_Thumb *eth;
247    /*
248       Eina_List *del_list = NULL, *l;
249     */
250
251    /* take thumb at head of list */
252    if (_thumblist)
253      {
254         eth = eina_list_data_get(_thumblist);
255         _thumblist = eina_list_remove_list(_thumblist, _thumblist);
256         _e_thumb_generate(eth);
257         if (eth->file) free(eth->file);
258         if (eth->key) free(eth->key);
259         free(eth);
260
261         if (_thumblist) _timer = ecore_timer_add(0.01, _e_cb_timer, NULL);
262         else _timer = NULL;
263      }
264    else
265      _timer = NULL;
266    return ECORE_CALLBACK_CANCEL;
267 }
268
269 typedef struct _Color Color;
270
271 struct _Color
272 {
273    Color        *closest;
274    int           closest_dist;
275    int           use;
276    unsigned char r, g, b;
277 };
278
279 static void
280 _e_thumb_generate(E_Thumb *eth)
281 {
282    char buf[4096], dbuf[4096], *id, *td, *ext = NULL;
283    Evas *evas = NULL, *evas_im = NULL;
284    Ecore_Evas *ee = NULL, *ee_im = NULL;
285    Evas_Object *im = NULL, *edje = NULL;
286    Eet_File *ef;
287    int iw, ih, alpha, ww, hh;
288    const unsigned int *data = NULL;
289    time_t mtime_orig, mtime_thumb;
290
291    id = _e_thumb_file_id(eth->file, eth->key);
292    if (!id) return;
293
294    td = strdup(id);
295    if (!td)
296      {
297         free(id);
298         return;
299      }
300    td[2] = 0;
301
302    snprintf(dbuf, sizeof(dbuf), "%s/%s", _thumbdir, td);
303    snprintf(buf, sizeof(buf), "%s/%s/%s-%ix%i.thm",
304             _thumbdir, td, id + 2, eth->w, eth->h);
305    free(id);
306    free(td);
307
308    mtime_orig = ecore_file_mod_time(eth->file);
309    mtime_thumb = ecore_file_mod_time(buf);
310    if (mtime_thumb <= mtime_orig)
311      {
312         ecore_file_mkdir(dbuf);
313
314         edje_file_cache_set(0);
315         edje_collection_cache_set(0);
316         ee = ecore_evas_buffer_new(1, 1);
317         evas = ecore_evas_get(ee);
318         evas_image_cache_set(evas, 0);
319         evas_font_cache_set(evas, 0);
320         ww = 0;
321         hh = 0;
322         alpha = 1;
323         ext = strrchr(eth->file, '.');
324
325         if ((ext) && (eth->key) &&
326             ((!strcasecmp(ext, ".edj")) ||
327              (!strcasecmp(ext, ".eap"))))
328           {
329              ww = eth->w;
330              hh = eth->h;
331              im = ecore_evas_object_image_new(ee);
332              ee_im = evas_object_data_get(im, "Ecore_Evas");
333              evas_im = ecore_evas_get(ee_im);
334              evas_image_cache_set(evas_im, 0);
335              evas_font_cache_set(evas_im, 0);
336              evas_object_image_size_set(im, ww * 4, hh * 4);
337              evas_object_image_fill_set(im, 0, 0, ww, hh);
338              edje = edje_object_add(evas_im);
339              if ((eth->key) &&
340                  ((!strcmp(eth->key, "e/desktop/background")) ||
341                   (!strcmp(eth->key, "e/init/splash"))))
342                alpha = 0;
343              if (edje_object_file_set(edje, eth->file, eth->key))
344                {
345                   evas_object_move(edje, 0, 0);
346                   evas_object_resize(edje, ww * 4, hh * 4);
347                   evas_object_show(edje);
348                }
349           }
350         else
351           {
352              im = evas_object_image_add(evas);
353              evas_object_image_load_size_set(im, eth->w, eth->h);
354              evas_object_image_file_set(im, eth->file, NULL);
355              iw = 0; ih = 0;
356              evas_object_image_size_get(im, &iw, &ih);
357              alpha = evas_object_image_alpha_get(im);
358              if ((iw > 0) && (ih > 0))
359                {
360                   ww = eth->w;
361                   hh = (eth->w * ih) / iw;
362                   if (hh > eth->h)
363                     {
364                        hh = eth->h;
365                        ww = (eth->h * iw) / ih;
366                     }
367                   evas_object_image_fill_set(im, 0, 0, ww, hh);
368                }
369           }
370         evas_object_move(im, 0, 0);
371         evas_object_resize(im, ww, hh);
372         ecore_evas_resize(ee, ww, hh);
373         evas_object_show(im);
374         if (ww > 0)
375           {
376              data = ecore_evas_buffer_pixels_get(ee);
377              if (data)
378                {
379                   ef = eet_open(buf, EET_FILE_MODE_WRITE);
380                   if (ef)
381                     {
382                        eet_write(ef, "/thumbnail/orig_file",
383                                  eth->file, strlen(eth->file), 1);
384                        if (eth->key)
385                          eet_write(ef, "/thumbnail/orig_key",
386                                    eth->key, strlen(eth->key), 1);
387                        eet_data_image_write(ef, "/thumbnail/data",
388                                             (void *)data, ww, hh, alpha,
389                                             0, 91, 1);
390                        ww = 4; hh = 4;
391                        evas_object_image_fill_set(im, 0, 0, ww, hh);
392                        evas_object_resize(im, ww, hh);
393                        ecore_evas_resize(ee, ww, hh);
394                        data = ecore_evas_buffer_pixels_get(ee);
395                        if (data)
396                          {
397                             unsigned int *data1;
398
399                             data1 = malloc(ww * hh * sizeof(unsigned int));
400                             memcpy(data1, data, ww * hh * sizeof(unsigned int));
401                             ww = 2; hh = 2;
402                             evas_object_image_fill_set(im, 0, 0, ww, hh);
403                             evas_object_resize(im, ww, hh);
404                             ecore_evas_resize(ee, ww, hh);
405                             data = ecore_evas_buffer_pixels_get(ee);
406                             if (data)
407                               {
408                                  unsigned int *data2;
409
410                                  data2 = malloc(ww * hh * sizeof(unsigned int));
411                                  memcpy(data2, data, ww * hh * sizeof(unsigned int));
412                                  ww = 1; hh = 1;
413                                  evas_object_image_fill_set(im, 0, 0, ww, hh);
414                                  evas_object_resize(im, ww, hh);
415                                  ecore_evas_resize(ee, ww, hh);
416                                  data = ecore_evas_buffer_pixels_get(ee);
417                                  if (data)
418                                    {
419                                       unsigned int *data3;
420                                       unsigned char id[(21 * 4) + 1];
421                                       int n, i;
422                                       int hi, si, vi;
423                                       float h, s, v;
424                                       const int pat2[4] =
425                                       {
426                                          0, 3, 1, 2
427                                       };
428                                       const int pat1[16] =
429                                       {
430                                          5, 10, 6, 9,
431                                          0, 15, 3, 12,
432                                          1, 14, 7, 8,
433                                          4, 11, 2, 13
434                                       };
435
436                                       data3 = malloc(ww * hh * sizeof(unsigned int));
437                                       memcpy(data3, data, ww * hh * sizeof(unsigned int));
438      // sort_id
439                                       n = 0;
440 #define A(v) (((v) >> 24) & 0xff)
441 #define R(v) (((v) >> 16) & 0xff)
442 #define G(v) (((v) >> 8) & 0xff)
443 #define B(v) (((v)) & 0xff)
444 #define HSV(p)                                         \
445   evas_color_rgb_to_hsv(R(p), G(p), B(p), &h, &s, &v); \
446   hi = 20 * (h / 360.0);                               \
447   si = 20 * s;                                         \
448   vi = 20 * v;                                         \
449   if (si < 2) hi = 25;
450 #define SAVEHSV(h, s, v) \
451   id[n++] = 'a' + h;     \
452   id[n++] = 'a' + v;     \
453   id[n++] = 'a' + s;
454 #define SAVEX(x) \
455   id[n++] = 'a' + x;
456 #if 0
457                                       HSV(data3[0]);
458                                       SAVEHSV(hi, si, vi);
459                                       for (i = 0; i < 4; i++)
460                                         {
461                                            HSV(data2[pat2[i]]);
462                                            SAVEHSV(hi, si, vi);
463                                         }
464                                       for (i = 0; i < 16; i++)
465                                         {
466                                            HSV(data1[pat1[i]]);
467                                            SAVEHSV(hi, si, vi);
468                                         }
469 #else
470                                       HSV(data3[0]);
471                                       SAVEX(hi);
472                                       for (i = 0; i < 4; i++)
473                                         {
474                                            HSV(data2[pat2[i]]);
475                                            SAVEX(hi);
476                                         }
477                                       for (i = 0; i < 16; i++)
478                                         {
479                                            HSV(data1[pat1[i]]);
480                                            SAVEX(hi);
481                                         }
482                                       HSV(data3[0]);
483                                       SAVEX(vi);
484                                       for (i = 0; i < 4; i++)
485                                         {
486                                            HSV(data2[pat2[i]]);
487                                            SAVEX(vi);
488                                         }
489                                       for (i = 0; i < 16; i++)
490                                         {
491                                            HSV(data1[pat1[i]]);
492                                            SAVEX(vi);
493                                         }
494                                       HSV(data3[0]);
495                                       SAVEX(si);
496                                       for (i = 0; i < 4; i++)
497                                         {
498                                            HSV(data2[pat2[i]]);
499                                            SAVEX(si);
500                                         }
501                                       for (i = 0; i < 16; i++)
502                                         {
503                                            HSV(data1[pat1[i]]);
504                                            SAVEX(si);
505                                         }
506 #endif
507                                       id[n++] = 0;
508                                       eet_write(ef, "/thumbnail/sort_id", id, n, 1);
509                                       free(data3);
510                                    }
511                                  free(data2);
512                               }
513                             free(data1);
514                          }
515                        eet_close(ef);
516                     }
517                }
518           }
519
520         /* will free all */
521         if (edje) evas_object_del(edje);
522         if (ee_im) ecore_evas_free(ee_im);
523         else if (im)
524           evas_object_del(im);
525         ecore_evas_free(ee);
526         eet_clearcache();
527      }
528    /* send back path to thumb */
529    ecore_ipc_server_send(_e_ipc_server, 5, 2, eth->objid, 0, 0, buf, strlen(buf) + 1);
530 }
531
532 static char *
533 _e_thumb_file_id(char *file,
534                  char *key)
535 {
536    char s[64];
537    const char *chmap = "0123456789abcdef";
538    unsigned char *buf, id[20];
539    int i, len, lenf;
540
541    len = 0;
542    lenf = strlen(file);
543    len += lenf;
544    len++;
545    if (key)
546      {
547         key += strlen(key);
548         len++;
549      }
550    buf = alloca(len);
551
552    strcpy((char *)buf, file);
553    if (key) strcpy((char *)(buf + lenf + 1), key);
554
555    e_sha1_sum(buf, len, id);
556
557    for (i = 0; i < 20; i++)
558      {
559         s[(i * 2) + 0] = chmap[(id[i] >> 4) & 0xf];
560         s[(i * 2) + 1] = chmap[(id[i]) & 0xf];
561      }
562    s[(i * 2)] = 0;
563    return strdup(s);
564 }
565