Add a task to copy configuration files to user's HOME dir from data dir for multi...
[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 = NULL;
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    while (mtime_thumb <= mtime_orig)
311      {
312         unsigned int *data1;
313
314         ecore_file_mkdir(dbuf);
315
316         edje_file_cache_set(0);
317         edje_collection_cache_set(0);
318         ee = ecore_evas_buffer_new(1, 1);
319         evas = ecore_evas_get(ee);
320         evas_image_cache_set(evas, 0);
321         evas_font_cache_set(evas, 0);
322         ww = 0;
323         hh = 0;
324         alpha = 1;
325         ext = strrchr(eth->file, '.');
326
327         if ((ext) && (eth->key) &&
328             ((!strcasecmp(ext, ".edj")) ||
329              (!strcasecmp(ext, ".eap"))))
330           {
331              ww = eth->w;
332              hh = eth->h;
333              im = ecore_evas_object_image_new(ee);
334              ee_im = evas_object_data_get(im, "Ecore_Evas");
335              evas_im = ecore_evas_get(ee_im);
336              evas_image_cache_set(evas_im, 0);
337              evas_font_cache_set(evas_im, 0);
338              evas_object_image_size_set(im, ww * 4, hh * 4);
339              evas_object_image_fill_set(im, 0, 0, ww, hh);
340              edje = edje_object_add(evas_im);
341              if ((eth->key) &&
342                  ((!strcmp(eth->key, "e/desktop/background")) ||
343                   (!strcmp(eth->key, "e/init/splash"))))
344                alpha = 0;
345              if (edje_object_file_set(edje, eth->file, eth->key))
346                {
347                   evas_object_move(edje, 0, 0);
348                   evas_object_resize(edje, ww * 4, hh * 4);
349                   evas_object_show(edje);
350                }
351           }
352         else if (evas_object_image_extension_can_load_get(ext))
353           {
354              im = evas_object_image_add(evas);
355              evas_object_image_load_size_set(im, eth->w, eth->h);
356              evas_object_image_file_set(im, eth->file, NULL);
357              iw = 0; ih = 0;
358              evas_object_image_size_get(im, &iw, &ih);
359              alpha = evas_object_image_alpha_get(im);
360              if ((iw > 0) && (ih > 0))
361                {
362                   ww = eth->w;
363                   hh = (eth->w * ih) / iw;
364                   if (hh > eth->h)
365                     {
366                        hh = eth->h;
367                        ww = (eth->h * iw) / ih;
368                     }
369                   evas_object_image_fill_set(im, 0, 0, ww, hh);
370                }
371           }
372         else
373           goto end;
374         ecore_evas_alpha_set(ee, alpha);
375         evas_object_move(im, 0, 0);
376         evas_object_resize(im, ww, hh);
377         ecore_evas_resize(ee, ww, hh);
378         evas_object_show(im);
379         if (ww <= 0) goto end;
380         data = ecore_evas_buffer_pixels_get(ee);
381         if (!data) goto end;
382         ef = eet_open(buf, EET_FILE_MODE_WRITE);
383         if (!ef) goto end;
384         eet_write(ef, "/thumbnail/orig_file",
385                   eth->file, strlen(eth->file), 1);
386         if (eth->key)
387           eet_write(ef, "/thumbnail/orig_key",
388                     eth->key, strlen(eth->key), 1);
389         eet_data_image_write(ef, "/thumbnail/data",
390                              (void *)data, ww, hh, alpha,
391                              0, 91, 1);
392         ww = 4; hh = 4;
393         evas_object_image_fill_set(im, 0, 0, ww, hh);
394         evas_object_resize(im, ww, hh);
395         ecore_evas_resize(ee, ww, hh);
396         data = ecore_evas_buffer_pixels_get(ee);
397         if (!data) goto end;
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 id2[(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 id2[n++] = 'a' + h;    \
452 id2[n++] = 'a' + v;    \
453 id2[n++] = 'a' + s;
454 #define SAVEX(x) \
455 id2[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                   id2[n++] = 0;
508                   eet_write(ef, "/thumbnail/sort_id", id2, n, 1);
509                   free(data3);
510                }
511              free(data2);
512           }
513         free(data1);
514 end:
515         if (ef) eet_close(ef);
516
517         /* will free all */
518         if (edje) evas_object_del(edje);
519         if (ee_im) ecore_evas_free(ee_im);
520         else if (im)
521           evas_object_del(im);
522         ecore_evas_free(ee);
523         eet_clearcache();
524         break;
525      }
526    /* send back path to thumb */
527    ecore_ipc_server_send(_e_ipc_server, 5, 2, eth->objid, 0, 0, buf, strlen(buf) + 1);
528 }
529
530 static char *
531 _e_thumb_file_id(char *file,
532                  char *key)
533 {
534    char s[64];
535    const char *chmap = "0123456789abcdef";
536    unsigned char *buf, id[20];
537    int i, len, lenf;
538
539    len = 0;
540    lenf = strlen(file);
541    len += lenf;
542    len++;
543    if (key)
544      {
545         key += strlen(key);
546         len++;
547      }
548    buf = alloca(len);
549
550    strcpy((char *)buf, file);
551    if (key) strcpy((char *)(buf + lenf + 1), key);
552
553    e_sha1_sum(buf, len, id);
554
555    for (i = 0; i < 20; i++)
556      {
557         s[(i * 2) + 0] = chmap[(id[i] >> 4) & 0xf];
558         s[(i * 2) + 1] = chmap[(id[i]) & 0xf];
559      }
560    s[(i * 2)] = 0;
561    return strdup(s);
562 }
563