Add new files for thumbnailing

This commit is contained in:
Stephen okra Houston 2016-03-24 12:14:39 -05:00
parent 4b8ea0492b
commit c2a555939d
4 changed files with 1338 additions and 0 deletions

27
COPYING.thumbnailer Normal file
View File

@ -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.

164
src/bin/ephoto_ipc.c Normal file
View File

@ -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

438
src/bin/ephoto_thumb.c Normal file
View File

@ -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;
}

View File

@ -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);
}