enlightenment/src/bin/e_thumb.c

557 lines
13 KiB
C

/*
* vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
*/
#include "e.h"
#ifdef EFM_DEBUG
# define D(x) do {printf(__FILE__ ":%d: ", __LINE__); printf x; fflush(stdout);} while (0)
#else
# define D(x) ((void) 0)
#endif
typedef struct _E_Thumb_Item E_Thumb_Item;
static char *_e_thumb_file_id(char *file);
static void _e_thumb_generate(void);
static int _e_thumb_cb_exe_exit(void *data, int type, void *event);
static char *thumb_path = NULL;
static Evas_List *thumb_files = NULL;
static Evas_List *event_handlers = NULL;
static pid_t pid = -1;
struct _E_Thumb_Item
{
char path[PATH_MAX];
Evas_Object *obj;
Evas *evas;
Evas_Coord w, h;
void (*cb)(Evas_Object *obj, void *data);
void *data;
};
int
e_thumb_init(void)
{
char *homedir;
char path[PATH_MAX];
homedir = e_user_homedir_get();
if (homedir)
{
snprintf(path, sizeof(path), "%s/.e/e/fileman/thumbnails", homedir);
if (!ecore_file_exists(path))
ecore_file_mkpath(path);
thumb_path = strdup(path);
free(homedir);
}
else return 0;
event_handlers =
evas_list_append(event_handlers,
ecore_event_handler_add(ECORE_EVENT_EXE_EXIT,
_e_thumb_cb_exe_exit,
NULL));
return 1;
}
int
e_thumb_shutdown(void)
{
E_FREE(thumb_path);
while (event_handlers)
{
ecore_event_handler_del(event_handlers->data);
event_handlers = evas_list_remove_list(event_handlers, event_handlers);
}
evas_list_free(thumb_files);
return 1;
}
/* return dir where thumbs are saved */
const char *
e_thumb_dir_get(void)
{
return thumb_path;
}
/* queue an image for thumbnailing or return the thumb if it exists */
Evas_Object *
e_thumb_generate_begin(char *path, Evas_Coord w, Evas_Coord h, Evas *evas, Evas_Object **tmp, void (*cb)(Evas_Object *obj, void *data), void *data)
{
E_Thumb_Item *t;
if(!ecore_file_exists(path)) return *tmp;
if (e_thumb_exists(path))
{
evas_object_del(*tmp);
*tmp = e_thumb_evas_object_get(path, evas, w, h, 1);
return *tmp;
}
t = E_NEW(E_Thumb_Item, 1);
t->w = w;
t->h = h;
t->evas = evas;
t->cb = cb;
t->data = data;
*tmp = e_icon_add(evas);
t->obj = *tmp;
snprintf(t->path, sizeof(t->path), "%s", path);
thumb_files = evas_list_append(thumb_files, t);
if (pid == -1) _e_thumb_generate();
return *tmp;
}
/* delete an image from the thumb queue */
void
e_thumb_generate_end(char *path)
{
Evas_List *l;
E_Thumb_Item *t;
for(l = thumb_files; l; l = l->next)
{
t = l->data;
if(!strcmp(path, t->path))
{
thumb_files = evas_list_remove_list(thumb_files, l);
break;
}
}
}
/* return hashed path of thumb */
char *
e_thumb_file_get(char *file)
{
char *id;
char thumb[PATH_MAX];
id = _e_thumb_file_id(file);
if (!id) return NULL;
snprintf(thumb, sizeof(thumb), "%s/%s", thumb_path, id);
free(id);
return strdup(thumb);
}
/* return true if the saved thumb exists OR if its an eap */
int
e_thumb_exists(char *file)
{
char *thumb;
char *ext;
ext = strrchr(file, '.');
if ((ext) && (!strcasecmp(ext, ".eap")))
return 1;
thumb = e_thumb_file_get(file);
if (ecore_file_exists(thumb))
{
free(thumb);
return 1;
}
return 0;
}
int *
_e_thumb_image_create(char *file, Evas_Coord w, Evas_Coord h, int *ww, int *hh, int *alpha, Evas_Object **im, Ecore_Evas **buf)
{
Evas *evasbuf;
int iw, ih;
*buf = ecore_evas_buffer_new(1, 1);
evasbuf = ecore_evas_get(*buf);
*im = evas_object_image_add(evasbuf);
evas_object_image_file_set(*im, 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 = w;
*hh = (w * ih) / iw;
if (*hh > h)
{
*hh = h;
*ww = (h * iw) / ih;
}
ecore_evas_resize(*buf, *ww, *hh);
evas_object_image_fill_set(*im, 0, 0, *ww, *hh);
evas_object_resize(*im, *ww, *hh);
evas_object_move(*im, 0, 0);
evas_object_show(*im);
return (int *)ecore_evas_buffer_pixels_get(*buf);
}
return NULL;
}
/* thumbnail an e17 background and return pixel data */
const int *
_e_thumb_ebg_create(char *file, Evas_Coord w, Evas_Coord h, int *ww, int *hh, int *alpha, Evas_Object **im, Ecore_Evas **buf)
{
Evas *evasbuf;
Evas_Object *wallpaper;
const int *pixels;
*ww = 640;
*hh = 480;
*alpha = 0;
w = 640;
h = 480;
*buf = ecore_evas_buffer_new(w, h);
evasbuf = ecore_evas_get(*buf);
wallpaper = edje_object_add(evasbuf);
edje_object_file_set(wallpaper, file, "desktop/background");
/* wallpaper */
evas_object_move(wallpaper, 0, 0);
evas_object_resize(wallpaper, w, h);
evas_object_show(wallpaper);
pixels = ecore_evas_buffer_pixels_get(*buf);
evas_object_del(wallpaper);
return pixels;
}
/* thumbnail an e17 theme and return pixel data */
const int *
_e_thumb_etheme_create(char *file, Evas_Coord w, Evas_Coord h, int *ww, int *hh, int *alpha, Evas_Object **im, Ecore_Evas **buf)
{
Evas *evasbuf;
Evas_Object *wallpaper, *window, *clock, *start, **pager;
const int *pixels;
*ww = 640;
*hh = 480;
*alpha = 0;
w = 640;
h = 480;
*buf = ecore_evas_buffer_new(w, h);
evasbuf = ecore_evas_get(*buf);
wallpaper = edje_object_add(evasbuf);
window = edje_object_add(evasbuf);
clock = edje_object_add(evasbuf);
start = edje_object_add(evasbuf);
pager = E_NEW(Evas_Object*, 3);
pager[0] = edje_object_add(evasbuf);
pager[1] = edje_object_add(evasbuf);
pager[2] = edje_object_add(evasbuf);
edje_object_file_set(wallpaper, file, "desktop/background");
edje_object_file_set(window, file, "widgets/border/default/border");
edje_object_file_set(clock, file, "modules/clock/main");
edje_object_file_set(clock, file, "modules/clock/main");
edje_object_file_set(start, file, "modules/start/main");
edje_object_file_set(pager[0], file, "modules/pager/main");
edje_object_file_set(pager[1], file, "modules/pager/desk");
edje_object_file_set(pager[2], file, "modules/pager/window");
edje_object_part_text_set(window, "title_text", file);
edje_object_part_swallow(pager[0], "items", pager[1]);
edje_object_part_swallow(pager[1], "items", pager[2]);
/* wallpaper */
evas_object_move(wallpaper, 0, 0);
evas_object_resize(wallpaper, w, h);
/* main window */
evas_object_move(window, (w * 0.1), (h * 0.05));
evas_object_resize(window, w * 0.8, h * 0.75);
/* clock */
evas_object_move(clock, (w * 0.9), (h * 0.9));
evas_object_resize(clock, w * 0.1, h * 0.1);
/* start */
evas_object_move(start, (w * 0.9), (h * 0.9));
evas_object_resize(start, w * 0.1, h * 0.1);
/* pager */
evas_object_move(pager[0], (w * 0.3), (h * 0.9));
evas_object_resize(pager[0], w * 0.1, h * 0.1);
evas_object_show(wallpaper);
evas_object_show(window);
evas_object_show(clock);
evas_object_show(start);
evas_object_show(pager[0]);
evas_object_show(pager[1]);
evas_object_show(pager[2]);
pixels = ecore_evas_buffer_pixels_get(*buf);
evas_object_del(wallpaper);
evas_object_del(window);
evas_object_del(clock);
evas_object_del(start);
evas_object_del(pager[0]);
evas_object_del(pager[1]);
evas_object_del(pager[2]);
free(pager);
return pixels;
}
/* create and save a thumb to disk */
int
e_thumb_create(char *file, Evas_Coord w, Evas_Coord h)
{
Eet_File *ef;
char *thumbpath, *ext;
Evas_Object *im;
const int *data;
int size, ww, hh;
Ecore_Evas *buf;
int alpha;
ext = strrchr(file, '.');
if ((ext) && (!strcasecmp(ext, ".eap")))
return 1;
thumbpath = e_thumb_file_get(file);
if (!thumbpath)
return -1;
if (ext)
{
if(!strcasecmp(ext, ".edj"))
{
/* for now, this function does both the bg and theme previews */
data = _e_thumb_etheme_create(file, w, h, &ww, &hh, &alpha, &im, &buf);
}
else
data = _e_thumb_image_create(file, w, h, &ww, &hh, &alpha, &im, &buf);
}
else
data = _e_thumb_image_create(file, w, h, &ww, &hh, &alpha, &im, &buf);
if (data)
{
ef = eet_open(thumbpath, EET_FILE_MODE_WRITE);
if (!ef)
{
free(thumbpath);
evas_object_del(im);
ecore_evas_free(buf);
return -1;
}
free(thumbpath);
eet_write(ef, "/thumbnail/orig_path", file, strlen(file), 1);
if ((size = eet_data_image_write(ef, "/thumbnail/data",
(void *)data, ww, hh, alpha,
0, 91, 1)) <= 0)
{
evas_object_del(im);
ecore_evas_free(buf);
eet_close(ef);
return -1;
}
eet_close(ef);
}
evas_object_del(im);
ecore_evas_free(buf);
return 1;
}
/* get evas object containing image of the thumb */
Evas_Object *
e_thumb_evas_object_get(char *file, Evas *evas, Evas_Coord width, Evas_Coord height, int shrink)
{
Eet_File *ef;
char *thumb, *ext;
Evas_Object *im = NULL;
#define DEF_THUMB_RETURN im = evas_object_rectangle_add(evas); \
evas_object_color_set(im, 255, 255, 255, 255); \
evas_object_resize(im, width, height); \
return im
D(("e_thumb_evas_object_get: (%s)\n", file));
/* eap thumbnailer */
ext = strrchr(file, '.');
if (ext)
{
if (!strcasecmp(ext, ".eap"))
{
E_App *app;
D(("e_thumb_evas_object_get: eap found\n"));
app = e_app_new(file, 0);
D(("e_thumb_evas_object_get: eap loaded\n"));
if (!app)
{
D(("e_thumb_evas_object_get: invalid eap\n"));
DEF_THUMB_RETURN;
}
else
{
D(("e_thumb_evas_object_get: creating eap thumb\n"));
im = e_icon_add(evas);
e_icon_file_edje_set(im, file, "icon");
e_object_unref(E_OBJECT(app));
D(("e_thumb_evas_object_get: returning eap thumb\n"));
return im;
}
}
}
/* saved thumb */
/* TODO: add ability to fetch thumbs from freedesktop dirs */
if (!e_thumb_exists(file))
{
if (!e_thumb_create(file, width, height))
{
DEF_THUMB_RETURN;
}
}
thumb = e_thumb_file_get(file);
if (!thumb)
{
DEF_THUMB_RETURN;
}
ef = eet_open(thumb, EET_FILE_MODE_READ);
if (!ef)
{
eet_close(ef);
free(thumb);
DEF_THUMB_RETURN;
}
im = e_icon_add(evas);
e_icon_file_key_set(im, thumb, "/thumbnail/data");
if (shrink)
{
Evas_Coord sw, sh;
e_icon_size_get(im, &sw, &sh);
evas_object_resize(im, sw, sh);
}
e_icon_fill_inside_set(im, 1);
free(thumb);
eet_close(ef);
return im;
}
/* return hash for a file */
static char *
_e_thumb_file_id(char *file)
{
char s[256], *sp;
const char *chmap =
"0123456789abcdef"
"ghijklmnopqrstuv"
"wxyz`~!@#$%^&*()"
"[];',.{}<>?-=_+|";
unsigned int id[4], i;
struct stat st;
if (stat(file, &st) < 0)
return NULL;
id[0] = st.st_ino;
id[1] = st.st_dev;
id[2] = (st.st_size & 0xffffffff);
id[3] = (st.st_mtime & 0xffffffff);
sp = s;
for (i = 0; i < 4; i++)
{
unsigned int t, tt;
int j;
t = id[i];
j = 32;
while (j > 0)
{
tt = t & ((1 << 6) - 1);
*sp = chmap[tt];
t >>= 6;
j -= 6;
sp++;
}
}
*sp = 0;
return strdup(s);
}
/* generate a thumb from the list of queued thumbs */
static void
_e_thumb_generate(void)
{
E_Thumb_Item *t;
if ((!thumb_files) || (pid != -1)) return;
pid = fork();
if (pid == 0)
{
/* reset signal handlers for the child */
signal(SIGSEGV, SIG_DFL);
signal(SIGILL, SIG_DFL);
signal(SIGFPE, SIG_DFL);
signal(SIGBUS, SIG_DFL);
t = thumb_files->data;
if (!e_thumb_exists(t->path))
e_thumb_create(t->path, t->w, t->h);
eet_cacheburst(0);
exit(0);
}
}
/* called when a thumb is generated */
static int
_e_thumb_cb_exe_exit(void *data, int type, void *event)
{
Ecore_Event_Exe_Exit *ev;
E_Thumb_Item *t;
char *ext;
ev = event;
if (ev->pid != pid) return 1;
if (!thumb_files) return 1;
t = thumb_files->data;
thumb_files = evas_list_remove_list(thumb_files, thumb_files);
ext = strrchr(t->path, '.');
if ((ext) && (strcasecmp(ext, ".eap")))
ext = NULL;
if ((ext) || (ecore_file_exists(t->path)))
{
Evas_Coord w, h;
Evas_Object *tmp;
void *data;
tmp = e_thumb_evas_object_get(t->path,
t->evas,
t->w,
t->h,
1);
data = e_icon_data_get(tmp, &w, &h);
e_icon_data_set(t->obj, data, w, h);
evas_object_del(tmp);
if(t->cb)
t->cb(t->obj, t->data);
free(t);
}
pid = -1;
_e_thumb_generate();
return 1;
}