okra pushed a commit to branch master.

http://git.enlightenment.org/apps/ephoto.git/commit/?id=c2a555939dfd2d14a3409af027789fc13ef60f46

commit c2a555939dfd2d14a3409af027789fc13ef60f46
Author: Stephen okra Houston <smhousto...@gmail.com>
Date:   Thu Mar 24 12:14:39 2016 -0500

    Add new files for thumbnailing
---
 COPYING.thumbnailer          |  27 ++
 src/bin/ephoto_ipc.c         | 164 ++++++++++
 src/bin/ephoto_thumb.c       | 438 ++++++++++++++++++++++++++
 src/bin/ephoto_thumbnailer.c | 709 +++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 1338 insertions(+)

diff --git a/COPYING.thumbnailer b/COPYING.thumbnailer
new file mode 100644
index 0000000..87c8026
--- /dev/null
+++ b/COPYING.thumbnailer
@@ -0,0 +1,27 @@
+Ephoto's thumbnailing code is from Enlightenment using the following license:
+
+Copyright notice for Enlightenment:
+
+Copyright (C) 2000-2012 Carsten Haitzler and various contributors (see AUTHORS)
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+   1. Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+   2. Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/src/bin/ephoto_ipc.c b/src/bin/ephoto_ipc.c
new file mode 100644
index 0000000..df243ca
--- /dev/null
+++ b/src/bin/ephoto_ipc.c
@@ -0,0 +1,164 @@
+#include "ephoto.h"
+#undef ERR
+#define ERR(...)        do { printf(__VA_ARGS__); putc('\n', stdout); } 
while(0)
+
+char *e_ipc_socket = NULL;
+
+#ifdef USE_IPC
+/* local subsystem functions */
+static Eina_Bool _e_ipc_cb_client_del(void *data EINA_UNUSED, int type 
EINA_UNUSED, void *event);
+static Eina_Bool _e_ipc_cb_client_data(void *data EINA_UNUSED, int type 
EINA_UNUSED, void *event);
+
+/* local subsystem globals */
+static Ecore_Ipc_Server *_e_ipc_server = NULL;
+#endif
+
+/* externally accessible functions */
+int
+e_ipc_init(void)
+{
+   char buf[4096], buf2[128], buf3[4096];
+   char *tmp, *user, *base;
+   int pid, trynum = 0, id1 = 0;
+   struct stat st;
+
+   tmp = getenv("TMPDIR");
+   if (!tmp) tmp = "/tmp";
+   base = tmp;
+
+   tmp = getenv("XDG_RUNTIME_DIR");
+   if (tmp)
+     {
+        if (stat(tmp, &st) == 0)
+          {
+             if ((st.st_uid == getuid()) &&
+                 ((st.st_mode & (S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO)) ==
+                  (S_IRWXU | S_IFDIR)))
+               base = tmp;
+             else
+               ERR("XDG_RUNTIME_DIR of '%s' failed permissions check", tmp);
+          }
+        else
+          ERR("XDG_RUNTIME_DIR of '%s' cannot be accessed", tmp);
+     }
+   
+   tmp = getenv("SD_USER_SOCKETS_DIR");
+   if (tmp)
+     {
+        if (stat(tmp, &st) == 0)
+          {
+             if ((st.st_uid == getuid()) &&
+                 ((st.st_mode & (S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO)) ==
+                  (S_IRWXU | S_IFDIR)))
+               base = tmp;
+             else
+               ERR("SD_USER_SOCKETS_DIR of '%s' failed permissions check", 
tmp);
+          }
+        else
+          ERR("SD_USER_SOCKETS_DIR of '%s' cannot be accessed", tmp);
+     }
+
+   user = getenv("USER");
+   if (!user)
+     {
+        int uidint;
+
+        user = "__unknown__";
+        uidint = getuid();
+        if (uidint >= 0)
+          {
+             snprintf(buf2, sizeof(buf2), "%i", uidint);
+             user = buf2;
+          }
+     }
+
+   setenv("EPHOTO_IPC_SOCKET", "", 1);
+
+   pid = (int)getpid();
+   for (trynum = 0; trynum <= 4096; trynum++)
+     {
+        snprintf(buf, sizeof(buf), "%s/e-%s@%x",
+                 base, user, id1);
+        if (!mkdir(buf, S_IRWXU))
+          {
+#ifdef USE_IPC
+             snprintf(buf3, sizeof(buf3), "%s/%i",
+                      buf, pid);
+             _e_ipc_server = ecore_ipc_server_add
+                (ECORE_IPC_LOCAL_SYSTEM, buf3, 0, NULL);
+             if (_e_ipc_server)
+#endif
+               {
+                  e_ipc_socket = strdup(ecore_file_file_get(buf));
+                  break;
+               }
+          }
+        id1 = rand();
+     }
+#ifdef USE_IPC
+   if (!_e_ipc_server)
+     {
+        ERR("Gave up after 4096 sockets in '%s'. All failed", base);
+        return 0;
+     }
+   setenv("EPHOTO_IPC_SOCKET", "", 1);
+   setenv("EPHOTO_IPC_SOCKET", buf3, 1);
+   ecore_event_handler_add(ECORE_IPC_EVENT_CLIENT_DEL,
+                           _e_ipc_cb_client_del, NULL);
+   ecore_event_handler_add(ECORE_IPC_EVENT_CLIENT_DATA,
+                           _e_ipc_cb_client_data, NULL);
+#endif
+   return 1;
+}
+
+int
+e_ipc_shutdown(void)
+{
+#ifdef USE_IPC
+   if (_e_ipc_server)
+     {
+        ecore_ipc_server_del(_e_ipc_server);
+        _e_ipc_server = NULL;
+     }
+#endif
+   free(e_ipc_socket);
+   return 1;
+}
+
+#ifdef USE_IPC
+/* local subsystem globals */
+static Eina_Bool
+_e_ipc_cb_client_del(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
+{
+   Ecore_Ipc_Event_Client_Del *e;
+
+   e = event;
+   if (ecore_ipc_client_server_get(e->client) != _e_ipc_server)
+     return ECORE_CALLBACK_PASS_ON;
+   /* delete client sruct */
+   e_thumb_client_del(e);
+   ecore_ipc_client_del(e->client);
+   return ECORE_CALLBACK_PASS_ON;
+}
+
+static Eina_Bool
+_e_ipc_cb_client_data(void *data EINA_UNUSED, int type EINA_UNUSED, void 
*event)
+{
+   Ecore_Ipc_Event_Client_Data *e;
+
+   e = event;
+   if (ecore_ipc_client_server_get(e->client) != _e_ipc_server)
+     return ECORE_CALLBACK_PASS_ON;
+   switch (e->major)
+     {
+      case EPHOTO_IPC_DOMAIN_THUMB:
+        e_thumb_client_data(e);
+        break;
+      
+      default:
+        break;
+     }
+   return ECORE_CALLBACK_PASS_ON;
+}
+
+#endif
diff --git a/src/bin/ephoto_thumb.c b/src/bin/ephoto_thumb.c
new file mode 100644
index 0000000..3421eb9
--- /dev/null
+++ b/src/bin/ephoto_thumb.c
@@ -0,0 +1,438 @@
+#include "ephoto.h"
+
+/* Taken from Enlightenment's Internal Thumbnailer */
+
+typedef struct _E_Thumb E_Thumb;
+
+struct _E_Thumb
+{
+   int           objid;
+   int           w, h;
+   const char   *file;
+   const char   *key;
+   char         *sort_id;
+   unsigned char queued : 1;
+   unsigned char busy : 1;
+   unsigned char done : 1;
+};
+
+/* local subsystem functions */
+static void         _e_thumb_gen_begin(int objid, const char *file, const char 
*key, int w, int h);
+static void         _e_thumb_gen_end(int objid);
+static void         _e_thumb_del_hook(void *data, Evas *e, Evas_Object *obj, 
void *event_info);
+static void         _e_thumb_hash_add(int objid, Evas_Object *obj);
+static void         _e_thumb_hash_del(int objid);
+static Evas_Object *_e_thumb_hash_find(int objid);
+static void         _e_thumb_thumbnailers_kill(void);
+static void         _e_thumb_thumbnailers_kill_cancel(void);
+static Eina_Bool    _e_thumb_cb_kill(void *data);
+static Eina_Bool    _e_thumb_cb_exe_event_del(void *data, int type, void 
*event);
+
+/* local subsystem globals */
+static Eina_List *_thumbnailers = NULL;
+static Eina_List *_thumbnailers_exe = NULL;
+static Eina_List *_thumb_queue = NULL;
+static int _objid = 0;
+static Eina_Hash *_thumbs = NULL;
+static int _pending = 0;
+static int _num_thumbnailers = 1;
+static Ecore_Event_Handler *_exe_del_handler = NULL;
+static Ecore_Timer *_kill_timer = NULL;
+
+/* externally accessible functions */
+int
+e_thumb_init(void)
+{
+   _exe_del_handler = ecore_event_handler_add(ECORE_EXE_EVENT_DEL,
+                                              _e_thumb_cb_exe_event_del,
+                                              NULL);
+   _thumbs = eina_hash_string_superfast_new(NULL);
+   return 1;
+}
+
+int
+e_thumb_shutdown(void)
+{
+   Ecore_Exe *exe_free;
+
+   _e_thumb_thumbnailers_kill_cancel();
+   _e_thumb_cb_kill(NULL);
+   if (_exe_del_handler) ecore_event_handler_del(_exe_del_handler);
+   _exe_del_handler = NULL;
+   _thumbnailers = eina_list_free(_thumbnailers);
+   EINA_LIST_FREE(_thumbnailers_exe, exe_free)
+      ecore_exe_free(exe_free);
+   _thumb_queue = eina_list_free(_thumb_queue);
+   _objid = 0;
+   eina_hash_free(_thumbs);
+   _thumbs = NULL;
+   _pending = 0;
+   return 1;
+}
+
+static void
+_thumb_preloaded(void *data, Evas_Object *obj EINA_UNUSED, void *event 
EINA_UNUSED)
+{
+   evas_object_smart_callback_call(data, "e_thumb_gen", NULL);
+}
+
+Evas_Object *
+e_thumb_icon_add(Evas *evas)
+{
+   Evas_Object *obj;
+   E_Thumb *eth;
+
+   obj = elm_icon_add(evas);
+   elm_image_fill_outside_set(obj, EINA_TRUE);
+   evas_object_smart_callback_add(obj, "preloaded", _thumb_preloaded, obj);
+   _objid++;
+   eth = calloc(1, sizeof(E_Thumb));
+   eth->objid = _objid;
+   eth->w = 64;
+   eth->h = 64;
+   evas_object_data_set(obj, "e_thumbdata", eth);
+   evas_object_event_callback_add(obj, EVAS_CALLBACK_FREE,
+                                  _e_thumb_del_hook, NULL);
+   _e_thumb_hash_add(eth->objid, obj);
+   return obj;
+}
+
+void
+e_thumb_icon_file_set(Evas_Object *obj, const char *file, const char *key)
+{
+   E_Thumb *eth;
+
+   eth = evas_object_data_get(obj, "e_thumbdata");
+   if (!eth) return;
+   eina_stringshare_replace(&eth->file, file);
+   eina_stringshare_replace(&eth->key, key);
+   free(eth->sort_id);
+}
+
+void
+e_thumb_icon_size_set(Evas_Object *obj, int w, int h)
+{
+   E_Thumb *eth;
+
+   eth = evas_object_data_get(obj, "e_thumbdata");
+   if (!eth) return;
+   if ((w < 1) || (h < 1)) return;
+   eth->w = w;
+   eth->h = h;
+}
+
+void
+e_thumb_icon_begin(Evas_Object *obj)
+{
+   E_Thumb *eth, *eth2;
+   char buf[4096];
+
+   eth = evas_object_data_get(obj, "e_thumbdata");
+   if (!eth) return;
+   if (eth->queued) return;
+   if (eth->busy) return;
+   if (eth->done) return;
+   if (!eth->file) return;
+   if (!_thumbnailers)
+     {
+        while ((int)eina_list_count(_thumbnailers_exe) < _num_thumbnailers)
+          {
+             Ecore_Exe *exe;
+
+             snprintf(buf, sizeof(buf), "%s/ephoto_thumbnail --nice=1", 
PACKAGE_DATA_DIR);
+             exe = ecore_exe_run(buf, NULL);
+             _thumbnailers_exe = eina_list_append(_thumbnailers_exe, exe);
+          }
+        _thumb_queue = eina_list_append(_thumb_queue, eth);
+        eth->queued = 1;
+        return;
+     }
+   EINA_LIST_FREE(_thumb_queue, eth2)
+     {
+        eth2->queued = 0;
+        eth2->busy = 1;
+        _pending++;
+        if (_pending == 1) _e_thumb_thumbnailers_kill_cancel();
+        _e_thumb_gen_begin(eth2->objid, eth2->file, eth2->key, eth2->w, 
eth2->h);
+     }
+   eth->busy = 1;
+   _pending++;
+   if (_pending == 1) _e_thumb_thumbnailers_kill_cancel();
+   _e_thumb_gen_begin(eth->objid, eth->file, eth->key, eth->w, eth->h);
+}
+
+void
+e_thumb_icon_end(Evas_Object *obj)
+{
+   E_Thumb *eth;
+
+   eth = evas_object_data_get(obj, "e_thumbdata");
+   if (!eth) return;
+   if (eth->queued)
+     {
+        _thumb_queue = eina_list_remove(_thumb_queue, eth);
+        eth->queued = 0;
+     }
+   if (eth->busy)
+     {
+        _e_thumb_gen_end(eth->objid);
+        eth->busy = 0;
+        _pending--;
+        if (_pending == 0) _e_thumb_thumbnailers_kill();
+     }
+}
+
+void
+e_thumb_icon_rethumb(Evas_Object *obj)
+{
+   E_Thumb *eth;
+   eth = evas_object_data_get(obj, "e_thumbdata");
+   if (!eth) return;
+
+   if (eth->done) eth->done = 0;
+   else e_thumb_icon_end(obj);
+
+   e_thumb_icon_begin(obj);
+}
+
+#define A(v)          (((v) >> 24) & 0xff)
+#define R(v)          (((v) >> 16) & 0xff)
+#define G(v)          (((v) >> 8) & 0xff)
+#define B(v)          (((v)) & 0xff)
+#define PIX(p, x, y)  p[((y) << 2) + (x)]
+#define PIX2(p, x, y) p[((y) << 1) + (x)]
+
+static void
+_e_thumb_key_load(E_Thumb *eth, const char *icon)
+{
+   Eet_File *ef;
+   int size = 0;
+
+   ef = eet_open(icon, EET_FILE_MODE_READ);
+   if (!ef) return;
+   eth->sort_id = eet_read(ef, "/thumbnail/sort_id", &size);
+   if (eth->sort_id)
+     {
+        if (size > 0) eth->sort_id[size - 1] = 0;
+        else
+          {
+             free(eth->sort_id);
+             eth->sort_id = NULL;
+          }
+     }
+   eet_close(ef);
+}
+
+const char *
+e_thumb_sort_id_get(Evas_Object *obj)
+{
+   E_Thumb *eth;
+   eth = evas_object_data_get(obj, "e_thumbdata");
+   if (!eth) return "";
+   if (!eth->sort_id) return "";
+   return eth->sort_id;
+}
+
+void
+e_thumb_client_data(Ecore_Ipc_Event_Client_Data *e)
+{
+   int objid;
+   char *icon;
+   E_Thumb *eth;
+   Evas_Object *obj;
+
+   if (!eina_list_data_find(_thumbnailers, e->client))
+     _thumbnailers = eina_list_prepend(_thumbnailers, e->client);
+   if (e->minor == 2)
+     {
+        objid = e->ref;
+        icon = e->data;
+        if ((icon) && (e->size > 1) && (icon[e->size - 1] == 0))
+          {
+             obj = _e_thumb_hash_find(objid);
+             if (obj)
+               {
+                  eth = evas_object_data_get(obj, "e_thumbdata");
+                  if (eth)
+                    {
+                       eth->busy = 0;
+                       _pending--;
+                       eth->done = 1;
+                       if (_pending == 0) _e_thumb_thumbnailers_kill();
+                       if (ecore_file_exists(icon))
+                         {
+                            elm_image_file_set(obj, icon, "/thumbnail/data");
+                            _e_thumb_key_load(eth, icon);
+                            elm_image_preload_disabled_set(obj, EINA_FALSE);
+                         }
+                       evas_object_smart_callback_call(obj, "e_thumb_gen", 
NULL);
+                    }
+               }
+          }
+     }
+   if (e->minor == 1)
+     {
+        /* hello message */
+        EINA_LIST_FREE(_thumb_queue, eth)
+          {
+             eth->queued = 0;
+             eth->busy = 1;
+             _pending++;
+             if (_pending == 1) _e_thumb_thumbnailers_kill_cancel();
+             _e_thumb_gen_begin(eth->objid, eth->file, eth->key, eth->w, 
eth->h);
+          }
+     }
+}
+
+void
+e_thumb_client_del(Ecore_Ipc_Event_Client_Del *e)
+{
+   if (!eina_list_data_find(_thumbnailers, e->client)) return;
+   _thumbnailers = eina_list_remove(_thumbnailers, e->client);
+   if ((!_thumbs) && (!_thumbnailers)) _objid = 0;
+}
+
+/* local subsystem functions */
+static void
+_e_thumb_gen_begin(int objid, const char *file, const char *key, int w, int h)
+{
+   char *buf;
+   int l1, l2;
+   Ecore_Ipc_Client *cli;
+
+   /* send thumb req */
+   l1 = strlen(file);
+   l2 = 0;
+   if (key) l2 = strlen(key);
+   buf = alloca(l1 + 1 + l2 + 1);
+   strcpy(buf, file);
+   if (key) strcpy(buf + l1 + 1, key);
+   else buf[l1 + 1] = 0;
+   cli = eina_list_data_get(_thumbnailers);
+   if (!cli) return;
+   _thumbnailers = eina_list_remove_list(_thumbnailers, _thumbnailers);
+   _thumbnailers = eina_list_append(_thumbnailers, cli);
+   ecore_ipc_client_send(cli, EPHOTO_IPC_DOMAIN_THUMB, 1, objid, w, h, buf, l1 
+ 1 + l2 + 1);
+}
+
+static void
+_e_thumb_gen_end(int objid)
+{
+   Eina_List *l;
+   Ecore_Ipc_Client *cli;
+
+   /* send thumb cancel */
+   EINA_LIST_FOREACH(_thumbnailers, l, cli)
+     {
+        ecore_ipc_client_send(cli, EPHOTO_IPC_DOMAIN_THUMB, 2, objid, 0, 0, 
NULL, 0);
+     }
+}
+
+static void
+_e_thumb_del_hook(void *data EINA_UNUSED, Evas *e EINA_UNUSED, Evas_Object 
*obj, void *event_info EINA_UNUSED)
+{
+   E_Thumb *eth;
+
+   eth = evas_object_data_get(obj, "e_thumbdata");
+   if (!eth) return;
+   evas_object_data_del(obj, "e_thumbdata");
+   _e_thumb_hash_del(eth->objid);
+   if (eth->busy)
+     {
+        _e_thumb_gen_end(eth->objid);
+        eth->busy = 0;
+        _pending--;
+        if (_pending == 0) _e_thumb_thumbnailers_kill();
+     }
+   if (eth->queued)
+     _thumb_queue = eina_list_remove(_thumb_queue, eth);
+   if (eth->file) eina_stringshare_del(eth->file);
+   if (eth->key) eina_stringshare_del(eth->key);
+   free(eth->sort_id);
+   free(eth);
+}
+
+static void
+_e_thumb_hash_add(int objid, Evas_Object *obj)
+{
+   char buf[32];
+
+   snprintf(buf, sizeof(buf), "%i", objid);
+   eina_hash_add(_thumbs, buf, obj);
+}
+
+static void
+_e_thumb_hash_del(int objid)
+{
+   char buf[32];
+
+   snprintf(buf, sizeof(buf), "%i", objid);
+   if (_thumbs) eina_hash_del(_thumbs, buf, NULL);
+   if ((!_thumbs) && (!_thumbnailers)) _objid = 0;
+}
+
+static Evas_Object *
+_e_thumb_hash_find(int objid)
+{
+   char buf[32];
+
+   snprintf(buf, sizeof(buf), "%i", objid);
+   return eina_hash_find(_thumbs, buf);
+}
+
+static void
+_e_thumb_thumbnailers_kill(void)
+{
+   if (_kill_timer) ecore_timer_del(_kill_timer);
+   _kill_timer = ecore_timer_add(1.0, _e_thumb_cb_kill, NULL);
+}
+
+static void
+_e_thumb_thumbnailers_kill_cancel(void)
+{
+   if (_kill_timer) ecore_timer_del(_kill_timer);
+   _kill_timer = NULL;
+}
+
+static Eina_Bool
+_e_thumb_cb_kill(void *data EINA_UNUSED)
+{
+   Eina_List *l;
+   Ecore_Exe *exe;
+
+   EINA_LIST_FOREACH(_thumbnailers_exe, l, exe)
+     ecore_exe_terminate(exe);
+   _kill_timer = NULL;
+   return ECORE_CALLBACK_DONE;
+}
+
+static Eina_Bool
+_e_thumb_cb_exe_event_del(void *data EINA_UNUSED, int type EINA_UNUSED, void 
*event)
+{
+   Ecore_Exe_Event_Del *ev;
+   Ecore_Exe *exe;
+   Eina_List *l;
+
+   ev = event;
+   EINA_LIST_FOREACH(_thumbnailers_exe, l, exe)
+     {
+        if (exe == ev->exe)
+          {
+             _thumbnailers_exe = eina_list_remove_list(_thumbnailers_exe, l);
+             break;
+          }
+     }
+   if ((!_thumbnailers_exe) && (_thumb_queue))
+     {
+        while ((int)eina_list_count(_thumbnailers_exe) < _num_thumbnailers)
+          {
+             Ecore_Exe *exe_thumb;
+             char buf[4096];
+
+             snprintf(buf, sizeof(buf), "%s/ephoto_thumbnail --nice=1", 
PACKAGE_DATA_DIR);
+             exe_thumb = ecore_exe_run(buf, NULL);
+             _thumbnailers_exe = eina_list_append(_thumbnailers_exe, 
exe_thumb);
+          }
+     }
+   return ECORE_CALLBACK_PASS_ON;
+}
diff --git a/src/bin/ephoto_thumbnailer.c b/src/bin/ephoto_thumbnailer.c
new file mode 100644
index 0000000..417c332
--- /dev/null
+++ b/src/bin/ephoto_thumbnailer.c
@@ -0,0 +1,709 @@
+#include "ephoto.h"
+#ifdef HAVE_ARPA_INET_H
+# include <arpa/inet.h>
+#endif
+
+#ifdef HAVE_NETINET_IN_H
+# include <netinet/in.h>
+#endif
+
+#define SHSH(n, v) ((((v) << (n)) & 0xffffffff) | ((v) >> (32 - (n))))
+
+typedef struct _E_Thumb E_Thumb;
+
+struct _E_Thumb
+{
+   int   objid;
+   int   w, h;
+   char *file;
+   char *key;
+};
+
+/* local subsystem functions */
+static int       _e_ipc_init(void);
+static Eina_Bool _e_ipc_cb_server_add(void *data,
+                                      int type,
+                                      void *event);
+static Eina_Bool _e_ipc_cb_server_del(void *data,
+                                      int type,
+                                      void *event);
+static Eina_Bool _e_ipc_cb_server_data(void *data,
+                                       int type,
+                                       void *event);
+static Eina_Bool _e_cb_timer(void *data);
+static void      _e_thumb_generate(E_Thumb *eth);
+static char     *_e_thumb_file_id(char *file,
+                                  char *key);
+
+/* local subsystem globals */
+static Ecore_Ipc_Server *_e_ipc_server = NULL;
+static Eina_List *_thumblist = NULL;
+static Ecore_Timer *_timer = NULL;
+static char _thumbdir[4096] = "";
+
+/* externally accessible functions */
+int
+main(int argc,
+     char **argv)
+{
+   int i;
+
+   for (i = 1; i < argc; i++)
+     {
+        if ((!strcmp(argv[i], "-h")) ||
+            (!strcmp(argv[i], "-help")) ||
+            (!strcmp(argv[i], "--help")))
+          {
+             printf(
+               "This is an internal tool for Ephoto.\n"
+               "do not use it.\n"
+               );
+             exit(0);
+          }
+        else if (!strncmp(argv[i], "--nice=", 7))
+          {
+             const char *val;
+
+             val = argv[i] + 7;
+             if (*val)
+               {
+                  if (nice(atoi(val)) < 0) perror("nice");
+               }
+          }
+     }
+
+   ecore_app_no_system_modules();
+   ecore_init();
+   ecore_app_args_set(argc, (const char **)argv);
+   eet_init();
+   evas_init();
+   ecore_evas_init();
+   edje_init();
+   ecore_file_init();
+   ecore_ipc_init();
+
+   snprintf(_thumbdir, PATH_MAX, "%s/.config/ephoto/thumbnails", 
getenv("HOME"));
+   ecore_file_mkpath(_thumbdir);
+
+   if (_e_ipc_init()) ecore_main_loop_begin();
+
+   if (_e_ipc_server)
+     {
+        ecore_ipc_server_del(_e_ipc_server);
+        _e_ipc_server = NULL;
+     }
+
+   ecore_ipc_shutdown();
+   ecore_file_shutdown();
+   ecore_evas_shutdown();
+   edje_shutdown();
+   evas_shutdown();
+   eet_shutdown();
+   ecore_shutdown();
+
+   return 0;
+}
+
+/* local subsystem functions */
+static int
+_e_ipc_init(void)
+{
+   char *sdir;
+
+   sdir = getenv("EPHOTO_IPC_SOCKET");
+   if (!sdir)
+     {
+        printf("The EPHOTO_IPC_SOCKET environment variable is not set. This 
is\n"
+               "exported by Enlightenment to all processes it launches.\n"
+               "This environment variable must be set and must point to\n"
+               "Enlightenment's IPC socket file (minus port number).\n");
+        return 0;
+     }
+   _e_ipc_server = ecore_ipc_server_connect(ECORE_IPC_LOCAL_SYSTEM, sdir, 0, 
NULL);
+   if (!_e_ipc_server) return 0;
+
+   ecore_event_handler_add(ECORE_IPC_EVENT_SERVER_ADD, _e_ipc_cb_server_add, 
NULL);
+   ecore_event_handler_add(ECORE_IPC_EVENT_SERVER_DEL, _e_ipc_cb_server_del, 
NULL);
+   ecore_event_handler_add(ECORE_IPC_EVENT_SERVER_DATA, _e_ipc_cb_server_data, 
NULL);
+
+   return 1;
+}
+
+static Eina_Bool
+_e_ipc_cb_server_add(void *data EINA_UNUSED,
+                     int type   EINA_UNUSED,
+                     void *event)
+{
+   Ecore_Ipc_Event_Server_Add *e;
+
+   e = event;
+   ecore_ipc_server_send(e->server,
+                         EPHOTO_IPC_DOMAIN_THUMB,
+                         1 /*hello*/,
+                         0, 0, 0, NULL, 0); /* send hello */
+   return ECORE_CALLBACK_PASS_ON;
+}
+
+static Eina_Bool
+_e_ipc_cb_server_del(void *data  EINA_UNUSED,
+                     int type    EINA_UNUSED,
+                     void *event EINA_UNUSED)
+{
+   /* quit now */
+   ecore_main_loop_quit();
+   return ECORE_CALLBACK_PASS_ON;
+}
+
+static Eina_Bool
+_e_ipc_cb_server_data(void *data EINA_UNUSED,
+                      int type   EINA_UNUSED,
+                      void *event)
+{
+   Ecore_Ipc_Event_Server_Data *e;
+   E_Thumb *eth;
+   Eina_List *l;
+   char *file = NULL;
+   char *key = NULL;
+
+   e = event;
+   if (e->major != EPHOTO_IPC_DOMAIN_THUMB) return ECORE_CALLBACK_PASS_ON;
+   switch (e->minor)
+     {
+      case 1:
+        if (e->data)
+          {
+             /* begin thumb */
+             /* don't check stuff. since this connects TO E it is connecting */
+             /* TO a trusted process that WILL send this message properly */
+             /* formatted. if the thumbnailer dies anyway - it's not a big 
loss */
+             /* but it is a sign of a bug in e formatting messages maybe */
+             file = e->data;
+             key = file + strlen(file) + 1;
+             if (!key[0]) key = NULL;
+             eth = calloc(1, sizeof(E_Thumb));
+             if (eth)
+               {
+                  eth->objid = e->ref;
+                  eth->w = e->ref_to;
+                  eth->h = e->response;
+                  eth->file = strdup(file);
+                  if (key) eth->key = strdup(key);
+                  _thumblist = eina_list_append(_thumblist, eth);
+                  if (!_timer) _timer = ecore_timer_add(0.001, _e_cb_timer, 
NULL);
+               }
+          }
+        break;
+
+      case 2:
+        /* end thumb */
+        EINA_LIST_FOREACH(_thumblist, l, eth)
+          {
+             if (eth->objid == e->ref)
+               {
+                  _thumblist = eina_list_remove_list(_thumblist, l);
+                  free(eth->file);
+                  free(eth->key);
+                  free(eth);
+                  break;
+               }
+          }
+        break;
+
+      case 3:
+        /* quit now */
+        ecore_main_loop_quit();
+        break;
+
+      default:
+        break;
+     }
+   return ECORE_CALLBACK_PASS_ON;
+}
+
+static Eina_Bool
+_e_cb_timer(void *data EINA_UNUSED)
+{
+   E_Thumb *eth;
+   /*
+      Eina_List *del_list = NULL, *l;
+    */
+
+   /* take thumb at head of list */
+   if (_thumblist)
+     {
+        eth = eina_list_data_get(_thumblist);
+        _thumblist = eina_list_remove_list(_thumblist, _thumblist);
+        _e_thumb_generate(eth);
+        free(eth->file);
+        free(eth->key);
+        free(eth);
+
+        if (_thumblist) _timer = ecore_timer_add(0.01, _e_cb_timer, NULL);
+        else _timer = NULL;
+     }
+   else
+     _timer = NULL;
+   return ECORE_CALLBACK_CANCEL;
+}
+
+typedef struct _Color Color;
+
+struct _Color
+{
+   Color        *closest;
+   int           closest_dist;
+   int           use;
+   unsigned char r, g, b;
+};
+
+static void
+_e_thumb_generate(E_Thumb *eth)
+{
+   char buf[4096], dbuf[4096], *id, *td, *ext = NULL;
+   Evas *evas = NULL, *evas_im = NULL;
+   Ecore_Evas *ee = NULL, *ee_im = NULL;
+   Evas_Object *im = NULL, *edje = NULL;
+   Eet_File *ef = NULL;
+   int iw, ih, alpha, ww, hh;
+   const unsigned int *data = NULL;
+   time_t mtime_orig, mtime_thumb;
+
+   id = _e_thumb_file_id(eth->file, eth->key);
+   if (!id) return;
+
+   td = strdup(id);
+   if (!td)
+     {
+        free(id);
+        return;
+     }
+   td[2] = 0;
+
+   snprintf(dbuf, sizeof(dbuf), "%s/%s", _thumbdir, td);
+   snprintf(buf, sizeof(buf), "%s/%s/%s-%ix%i.thm",
+            _thumbdir, td, id + 2, eth->w, eth->h);
+   free(id);
+   free(td);
+
+   mtime_orig = ecore_file_mod_time(eth->file);
+   mtime_thumb = ecore_file_mod_time(buf);
+   while (mtime_thumb <= mtime_orig)
+     {
+        unsigned int *data1;
+        Eina_Bool sortkey;
+        Evas_Object *im2, *bg;
+        
+        im = NULL;
+        im2 = NULL;
+        bg = NULL;
+
+        ecore_file_mkdir(dbuf);
+
+        edje_file_cache_set(0);
+        edje_collection_cache_set(0);
+        ee = ecore_evas_buffer_new(1, 1);
+        evas = ecore_evas_get(ee);
+        evas_image_cache_set(evas, 0);
+        evas_font_cache_set(evas, 0);
+        ww = 0;
+        hh = 0;
+        alpha = 1;
+        ext = strrchr(eth->file, '.');
+
+        sortkey = EINA_FALSE;
+        
+        if ((ext) && (eth->key) &&
+            ((!strcasecmp(ext, ".edj")) ||
+             (!strcasecmp(ext, ".eap"))))
+          {
+             ww = eth->w;
+             hh = eth->h;
+             im = ecore_evas_object_image_new(ee);
+             ee_im = evas_object_data_get(im, "Ecore_Evas");
+             evas_im = ecore_evas_get(ee_im);
+             evas_image_cache_set(evas_im, 0);
+             evas_font_cache_set(evas_im, 0);
+             evas_object_image_size_set(im, ww * 4, hh * 4);
+             evas_object_image_fill_set(im, 0, 0, ww, hh);
+             edje = edje_object_add(evas_im);
+             if ((eth->key) &&
+                 ((!strcmp(eth->key, "e/desktop/background")) ||
+                  (!strcmp(eth->key, "e/init/splash"))))
+               alpha = 0;
+             if (edje_object_file_set(edje, eth->file, eth->key))
+               {
+                  evas_object_move(edje, 0, 0);
+                  evas_object_resize(edje, ww * 4, hh * 4);
+                  evas_object_show(edje);
+               }
+             evas_object_move(im, 0, 0);
+             evas_object_resize(im, ww, hh);
+             sortkey = EINA_TRUE;
+          }
+        else if ((ext) &&
+                 ((!strcasecmp(ext, ".ttf")) ||
+                  (!strcasecmp(ext, ".pcf")) ||
+                  (!strcasecmp(ext, ".bdf")) ||
+                  (!strcasecmp(ext, ".ttx")) ||
+                  (!strcasecmp(ext, ".pfa")) ||
+                  (!strcasecmp(ext, ".pfb")) ||
+                  (!strcasecmp(ext, ".afm")) ||
+                  (!strcasecmp(ext, ".sfd")) ||
+                  (!strcasecmp(ext, ".snf")) ||
+                  (!strcasecmp(ext, ".otf")) ||
+                  (!strcasecmp(ext, ".psf")) ||
+                  (!strcasecmp(ext, ".ttc")) ||
+                  (!strcasecmp(ext, ".ttx")) ||
+                  (!strcasecmp(ext, ".gsf")) ||
+                  (!strcasecmp(ext, ".spd"))
+                 ))
+          {
+             Evas_Coord tx = 0, ty = 0, tw = 0, th = 0;
+             ww = eth->w;
+             hh = eth->h;
+             alpha = 0;
+
+             bg = evas_object_rectangle_add(evas);
+             evas_object_color_set(bg, 96, 96, 96, 255);
+             evas_object_move(bg, 0, 0);
+             evas_object_resize(bg, ww, hh);
+             evas_object_show(bg);
+             
+             im = evas_object_text_add(evas);
+             evas_object_text_font_set(im, eth->file, hh / 4);
+             evas_object_color_set(im, 192, 192, 192, 255);
+             evas_object_text_ellipsis_set(im, 0.0);
+             evas_object_text_text_set(im, "ABCabc");
+             evas_object_geometry_get(im, NULL, NULL, &tw, &th);
+             if (tw > ww) tw = ww;
+             tx = 0 + ((ww - tw) / 2);
+             ty = 0 + (((hh / 2) - th) / 2);
+             evas_object_move(im, tx, ty);
+             evas_object_resize(im, tw, th);
+             evas_object_show(im);
+             
+             im2 = evas_object_text_add(evas);
+             evas_object_text_font_set(im2, eth->file, hh / 4);
+             evas_object_color_set(im2, 255, 255, 255, 255);
+             evas_object_text_ellipsis_set(im2, 0.0);
+             evas_object_text_text_set(im2, "123!@?");
+             evas_object_geometry_get(im2, NULL, NULL, &tw, &th);
+             if (tw > ww) tw = ww;
+             tx = 0 + ((ww - tw) / 2);
+             ty = (hh / 2) + (((hh / 2) - th) / 2);
+             evas_object_move(im2, tx, ty);
+             evas_object_resize(im2, tw, th);
+             evas_object_show(im2);
+          }
+        else if (evas_object_image_extension_can_load_get(ext))
+          {
+             im = evas_object_image_add(evas);
+             evas_object_image_load_orientation_set(im, EINA_TRUE);
+             evas_object_image_load_size_set(im, eth->w, eth->h);
+             evas_object_image_file_set(im, eth->file, NULL);
+             iw = 0; ih = 0;
+             evas_object_image_size_get(im, &iw, &ih);
+             alpha = evas_object_image_alpha_get(im);
+             if ((iw > 0) && (ih > 0))
+               {
+                  ww = eth->w;
+                  hh = (eth->w * ih) / iw;
+                  if (hh > eth->h)
+                    {
+                       hh = eth->h;
+                       ww = (eth->h * iw) / ih;
+                    }
+                  evas_object_image_fill_set(im, 0, 0, ww, hh);
+               }
+             evas_object_move(im, 0, 0);
+             evas_object_resize(im, ww, hh);
+             sortkey = EINA_TRUE;
+          }
+        else
+          goto end;
+        
+        ecore_evas_alpha_set(ee, alpha);
+        ecore_evas_resize(ee, ww, hh);
+        evas_object_show(im);
+        if (ww <= 0) goto end;
+        data = ecore_evas_buffer_pixels_get(ee);
+        if (!data) goto end;
+        ef = eet_open(buf, EET_FILE_MODE_WRITE);
+        if (!ef) goto end;
+        eet_write(ef, "/thumbnail/orig_file",
+                  eth->file, strlen(eth->file), 1);
+        if (eth->key)
+          eet_write(ef, "/thumbnail/orig_key",
+                    eth->key, strlen(eth->key), 1);
+        eet_data_image_write(ef, "/thumbnail/data",
+                             (void *)data, ww, hh, alpha,
+                             0, 91, 1);
+        if (sortkey)
+          {
+             ww = 4; hh = 4;
+             evas_object_image_fill_set(im, 0, 0, ww, hh);
+             evas_object_resize(im, ww, hh);
+             ecore_evas_resize(ee, ww, hh);
+             data = ecore_evas_buffer_pixels_get(ee);
+             if (!data) goto end;
+
+             data1 = malloc(ww * hh * sizeof(unsigned int));
+             memcpy(data1, data, ww * hh * sizeof(unsigned int));
+             ww = 2; hh = 2;
+             evas_object_image_fill_set(im, 0, 0, ww, hh);
+             evas_object_resize(im, ww, hh);
+             ecore_evas_resize(ee, ww, hh);
+             data = ecore_evas_buffer_pixels_get(ee);
+             if (data)
+               {
+                  unsigned int *data2;
+                  
+                  data2 = malloc(ww * hh * sizeof(unsigned int));
+                  memcpy(data2, data, ww * hh * sizeof(unsigned int));
+                  ww = 1; hh = 1;
+                  evas_object_image_fill_set(im, 0, 0, ww, hh);
+                  evas_object_resize(im, ww, hh);
+                  ecore_evas_resize(ee, ww, hh);
+                  data = ecore_evas_buffer_pixels_get(ee);
+                  if (data)
+                    {
+                       unsigned int *data3;
+                       unsigned char id2[(21 * 4) + 1];
+                       int n, i;
+                       int hi, si, vi;
+                       float h, s, v;
+                       const int pat2[4] =
+                         {
+                            0, 3, 1, 2
+                         };
+                       const int pat1[16] =
+                         {
+                            5, 10, 6, 9,
+                            0, 15, 3, 12,
+                            1, 14, 7, 8,
+                            4, 11, 2, 13
+                         };
+                       
+                       /* ww = hh = 1 here */
+                       data3 = malloc(sizeof(unsigned int));
+                       memcpy(data3, data, sizeof(unsigned int));
+                       // sort_id
+                       n = 0;
+#define A(v) (((v) >> 24) & 0xff)
+#define R(v) (((v) >> 16) & 0xff)
+#define G(v) (((v) >> 8) & 0xff)
+#define B(v) (((v)) & 0xff)
+#define HSV(p)                                         \
+  evas_color_rgb_to_hsv(R(p), G(p), B(p), &h, &s, &v); \
+  hi = 20 * (h / 360.0);                               \
+  si = 20 * s;                                         \
+  vi = 20 * v;                                         \
+  if (si < 2) hi = 25;
+#define SAVEHSV(h, s, v) \
+  id2[n++] = 'a' + h;    \
+  id2[n++] = 'a' + v;    \
+  id2[n++] = 'a' + s;
+#define SAVEX(x) \
+  id2[n++] = 'a' + x;
+#if 0
+                       HSV(data3[0]);
+                       SAVEHSV(hi, si, vi);
+                       for (i = 0; i < 4; i++)
+                         {
+                            HSV(data2[pat2[i]]);
+                            SAVEHSV(hi, si, vi);
+                         }
+                       for (i = 0; i < 16; i++)
+                         {
+                            HSV(data1[pat1[i]]);
+                            SAVEHSV(hi, si, vi);
+                         }
+#else
+                       HSV(data3[0]);
+                       SAVEX(hi);
+                       for (i = 0; i < 4; i++)
+                         {
+                            HSV(data2[pat2[i]]);
+                            SAVEX(hi);
+                         }
+                       for (i = 0; i < 16; i++)
+                         {
+                            HSV(data1[pat1[i]]);
+                            SAVEX(hi);
+                         }
+                       HSV(data3[0]);
+                       SAVEX(vi);
+                       for (i = 0; i < 4; i++)
+                         {
+                            HSV(data2[pat2[i]]);
+                            SAVEX(vi);
+                         }
+                       for (i = 0; i < 16; i++)
+                         {
+                            HSV(data1[pat1[i]]);
+                            SAVEX(vi);
+                         }
+                       HSV(data3[0]);
+                       SAVEX(si);
+                       for (i = 0; i < 4; i++)
+                         {
+                            HSV(data2[pat2[i]]);
+                            SAVEX(si);
+                         }
+                       for (i = 0; i < 16; i++)
+                         {
+                            HSV(data1[pat1[i]]);
+                            SAVEX(si);
+                         }
+#endif
+                       id2[n++] = 0;
+                       eet_write(ef, "/thumbnail/sort_id", id2, n, 1);
+                       free(data3);
+                    }
+                  free(data2);
+               }
+             free(data1);
+          }
+end:
+        if (ef) eet_close(ef);
+
+        /* will free all */
+        if (edje) evas_object_del(edje);
+        if (ee_im) ecore_evas_free(ee_im);
+        else if (im) evas_object_del(im);
+        if (im2) evas_object_del(im2);
+        if (bg) evas_object_del(bg);
+        ecore_evas_free(ee);
+        eet_clearcache();
+        break;
+     }
+   /* send back path to thumb */
+   ecore_ipc_server_send(_e_ipc_server, EPHOTO_IPC_DOMAIN_THUMB, 2, 
eth->objid, 0, 0, buf, strlen(buf) + 1);
+}
+
+static int
+e_sha1_sum(unsigned char *data, int size, unsigned char *dst)
+{
+   unsigned int digest[5], word[80], wa, wb, wc, wd, we, t;
+   unsigned char buf[64], *d;
+   int idx, left, i;
+   const unsigned int magic[4] =
+   {
+      0x5a827999,
+      0x6ed9eba1,
+      0x8f1bbcdc,
+      0xca62c1d6
+   };
+
+   idx = 0;
+   digest[0] = 0x67452301;
+   digest[1] = 0xefcdab89;
+   digest[2] = 0x98badcfe;
+   digest[3] = 0x10325476;
+   digest[4] = 0xc3d2e1f0;
+
+   memset(buf, 0, sizeof(buf));
+   for (left = size, d = data; left > 0; left--, d++)
+     {
+        if ((idx == 0) && (left < 64))
+          {
+             memset(buf, 0, 60);
+             buf[60] = (size >> 24) & 0xff;
+             buf[61] = (size >> 16) & 0xff;
+             buf[62] = (size >> 8) & 0xff;
+             buf[63] = (size) & 0xff;
+          }
+        buf[idx] = *d;
+        idx++;;
+        if ((idx == 64) || (left == 1))
+          {
+             if ((left == 1) && (idx < 64)) buf[idx] = 0x80;
+             for (i = 0; i < 16; i++)
+               {
+                  word[i] = (unsigned int)buf[(i * 4)    ] << 24;
+                  word[i] |= (unsigned int)buf[(i * 4) + 1] << 16;
+                  word[i] |= (unsigned int)buf[(i * 4) + 2] << 8;
+                  word[i] |= (unsigned int)buf[(i * 4) + 3];
+               }
+             for (i = 16; i < 80; i++)
+               word[i] = SHSH(1,
+                              word[i - 3 ] ^ word[i - 8 ] ^
+                              word[i - 14] ^ word[i - 16]);
+             wa = digest[0];
+             wb = digest[1];
+             wc = digest[2];
+             wd = digest[3];
+             we = digest[4];
+             for (i = 0; i < 80; i++)
+               {
+                  if (i < 20)
+                    t = SHSH(5, wa) + ((wb & wc) | ((~wb) & wd)) +
+                      we + word[i] + magic[0];
+                  else if (i < 40)
+                    t = SHSH(5, wa) + (wb ^ wc ^ wd) +
+                      we + word[i] + magic[1];
+                  else if (i < 60)
+                    t = SHSH(5, wa) + ((wb & wc) | (wb & wd) | (wc & wd)) +
+                      we + word[i] + magic[2];
+                  else if (i < 80)
+                    t = SHSH(5, wa) + (wb ^ wc ^ wd) +
+                      we + word[i] + magic[3];
+                  we = wd;
+                  wd = wc;
+                  wc = SHSH(30, wb);
+                  wb = wa;
+                  wa = t;
+               }
+             digest[0] += wa;
+             digest[1] += wb;
+             digest[2] += wc;
+             digest[3] += wd;
+             digest[4] += we;
+             idx = 0;
+          }
+     }
+
+   t = htonl(digest[0]); digest[0] = t;
+   t = htonl(digest[1]); digest[1] = t;
+   t = htonl(digest[2]); digest[2] = t;
+   t = htonl(digest[3]); digest[3] = t;
+   t = htonl(digest[4]); digest[4] = t;
+
+   memcpy(dst, digest, 5 * 4);
+   return 1;
+}
+
+static char *
+_e_thumb_file_id(char *file,
+                 char *key)
+{
+   char s[64];
+   const char *chmap = "0123456789abcdef";
+   unsigned char *buf, id[20];
+   int i, len, lenf;
+
+   len = 0;
+   lenf = strlen(file);
+   len += lenf;
+   len++;
+   if (key)
+     {
+        key += strlen(key);
+        len++;
+     }
+   buf = alloca(len);
+
+   strcpy((char *)buf, file);
+   if (key) strcpy((char *)(buf + lenf + 1), key);
+
+   e_sha1_sum(buf, len, id);
+
+   for (i = 0; i < 20; i++)
+     {
+        s[(i * 2) + 0] = chmap[(id[i] >> 4) & 0xf];
+        s[(i * 2) + 1] = chmap[(id[i]) & 0xf];
+     }
+   s[(i * 2)] = 0;
+   return strdup(s);
+}
+

-- 


Reply via email to