enlightenment/src/bin/e_thumb_main.c

530 lines
15 KiB
C

/*
* vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <Ecore.h>
#include <Ecore_Evas.h>
#include <Ecore_Ipc.h>
#include <Ecore_File.h>
#include <Evas.h>
#include <Eet.h>
#include <Edje.h>
#include "e_sha1.h"
#include "e_user.h"
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 int _e_ipc_cb_server_add(void *data, int type, void *event);
static int _e_ipc_cb_server_del(void *data, int type, void *event);
static int _e_ipc_cb_server_data(void *data, int type, void *event);
static int _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 Enlightenment.\n"
"do not use it.\n"
);
exit(0);
}
else if (!strncmp(argv[i], "--nice=", 7))
{
const char *val;
val = argv[i] + 7;
if (*val)
nice(atoi(val));
}
}
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();
e_user_dir_concat_static(_thumbdir, "fileman/thumbnails");
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("E_IPC_SOCKET");
if (!sdir)
{
printf("The E_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 int
_e_ipc_cb_server_add(void *data, int type, void *event)
{
Ecore_Ipc_Event_Server_Add *e;
e = event;
ecore_ipc_server_send(e->server,
5/*E_IPC_DOMAIN_THUMB*/,
1/*hello*/,
0, 0, 0, NULL, 0); /* send hello */
return 1;
}
static int
_e_ipc_cb_server_del(void *data, int type, void *event)
{
/* quit now */
ecore_main_loop_quit();
return 1;
}
static int
_e_ipc_cb_server_data(void *data, int type, 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 != 5/*E_IPC_DOMAIN_THUMB*/) return 1;
switch (e->minor)
{
case 1:
if (e->data)
{
/* begin thumb */
/* don't check stuff. since this connects TO e17 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 formattign 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);
if (eth->file) free(eth->file);
if (eth->key) free(eth->key);
free(eth);
break;
}
}
break;
case 3:
/* quit now */
ecore_main_loop_quit();
break;
default:
break;
}
return 1;
}
static int
_e_cb_timer(void *data)
{
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);
if (eth->file) free(eth->file);
if (eth->key) free(eth->key);
free(eth);
if (_thumblist) _timer = ecore_timer_add(0.01, _e_cb_timer, NULL);
else _timer = NULL;
}
else
_timer = NULL;
return 0;
}
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;
int iw, ih, alpha, ww, hh;
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);
if (mtime_thumb <= mtime_orig)
{
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, '.');
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);
}
}
else
{
im = evas_object_image_add(evas);
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);
ecore_evas_resize(ee, ww, hh);
evas_object_show(im);
if (ww > 0)
{
data = (int *)ecore_evas_buffer_pixels_get(ee);
if (data)
{
ef = eet_open(buf, EET_FILE_MODE_WRITE);
if (ef)
{
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);
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 = (int *)ecore_evas_buffer_pixels_get(ee);
if (data)
{
unsigned int *data1;
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 = (int *)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 = (int *)ecore_evas_buffer_pixels_get(ee);
if (data)
{
unsigned int *data3;
unsigned char id[(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
};
data3 = malloc(ww * hh * sizeof(unsigned int));
memcpy(data3, data, ww * hh * 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) \
id[n++] = 'a' + h; \
id[n++] = 'a' + v; \
id[n++] = 'a' + s;
#define SAVEX(x) \
id[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
id[n++] = 0;
eet_write(ef, "/thumbnail/sort_id", id, n, 1);
free(data3);
}
free(data2);
}
free(data1);
}
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);
ecore_evas_free(ee);
eet_clearcache();
}
/* send back path to thumb */
ecore_ipc_server_send(_e_ipc_server, 5, 2, eth->objid, 0, 0, buf, strlen(buf) + 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);
}