From bcef93cabaee2a474ad668df47618bbd49ebf951 Mon Sep 17 00:00:00 2001 From: Cedric BAIL Date: Wed, 27 Apr 2011 18:06:42 +0000 Subject: [PATCH] ethumb: make exists client API async. Ethumb_Client now use Ecore_Thread with this patch. TODO: * cache exists requests (client side). * cache generate requests (server side). SVN revision: 58977 --- legacy/ethumb/src/bin/ethumbd_client.c | 47 +++-- legacy/ethumb/src/lib/Ethumb.c | 117 +++++++++++- legacy/ethumb/src/lib/Ethumb.h | 6 +- legacy/ethumb/src/lib/client/Ethumb_Client.c | 181 ++++++++++++++++--- legacy/ethumb/src/lib/client/Ethumb_Client.h | 27 ++- 5 files changed, 325 insertions(+), 53 deletions(-) diff --git a/legacy/ethumb/src/bin/ethumbd_client.c b/legacy/ethumb/src/bin/ethumbd_client.c index 351eff4c66..57950e3884 100644 --- a/legacy/ethumb/src/bin/ethumbd_client.c +++ b/legacy/ethumb/src/bin/ethumbd_client.c @@ -157,12 +157,38 @@ _finished_thumb(void *data __UNUSED__, Ethumb_Client *client __UNUSED__, int id } static void -_connected(void *data, Ethumb_Client *c, Eina_Bool success) +_exists(Ethumb_Client *c, __UNUSED__ Ethumb_Exists *thread, Eina_Bool exists, void *data) { struct options *opts = data; const char *thumb_path, *thumb_key; long id; + if (exists) + { + ethumb_client_thumb_path_get(c, &thumb_path, &thumb_key); + _thumb_report + ("EXISTS", opts->src_path, opts->src_key, thumb_path, thumb_key); + ecore_main_loop_quit(); + return; + } + + id = ethumb_client_generate(c, _finished_thumb, NULL, NULL); + if (id < 0) + { + fputs("ERROR: could not request thumbnail to be generated.\n", stderr); + ecore_main_loop_quit(); + return; + } + printf("request id=%ld, file='%s', key='%s'\n", + id, opts->src_path, opts->src_key ? opts->src_key : ""); + +} + +static void +_connected(void *data, Ethumb_Client *c, Eina_Bool success) +{ + struct options *opts = data; + if (!success) { fputs("ERROR: could not connect to DBus server.\n", stderr); @@ -196,24 +222,7 @@ _connected(void *data, Ethumb_Client *c, Eina_Bool success) } ethumb_client_thumb_path_set(c, opts->thumb_path, opts->thumb_key); - ethumb_client_thumb_path_get(c, &thumb_path, &thumb_key); - if (ethumb_client_thumb_exists(c)) - { - _thumb_report - ("EXISTS", opts->src_path, opts->src_key, thumb_path, thumb_key); - ecore_main_loop_quit(); - return; - } - - id = ethumb_client_generate(c, _finished_thumb, NULL, NULL); - if (id < 0) - { - fputs("ERROR: could not request thumbnail to be generated.\n", stderr); - ecore_main_loop_quit(); - return; - } - printf("request id=%ld, file='%s', key='%s'\n", - id, opts->src_path, opts->src_key ? opts->src_key : ""); + ethumb_client_thumb_exists(c, _exists, opts); } int diff --git a/legacy/ethumb/src/lib/Ethumb.c b/legacy/ethumb/src/lib/Ethumb.c index 067a4092d8..7035ea2196 100644 --- a/legacy/ethumb/src/lib/Ethumb.c +++ b/legacy/ethumb/src/lib/Ethumb.c @@ -244,6 +244,7 @@ ethumb_new(void) if (!e) { ERR("could not create ecore evas buffer"); + free(ethumb); return NULL; } @@ -259,8 +260,8 @@ ethumb_new(void) return NULL; } - sub_ee = evas_object_data_get(o, "Ecore_Evas"); - sub_e = ecore_evas_get(sub_ee); + sub_ee = ecore_evas_object_ecore_evas_get(o); + sub_e = ecore_evas_object_evas_get(o); evas_image_cache_set(sub_e, 0); evas_font_cache_set(sub_e, 0); @@ -678,12 +679,12 @@ ethumb_video_start_get(const Ethumb *e) } EAPI void -ethumb_video_time_set(Ethumb *e, float time) +ethumb_video_time_set(Ethumb *e, float t) { EINA_SAFETY_ON_NULL_RETURN(e); - DBG("ethumb=%p, video_start=%f", e, time); - e->video.time = time; + DBG("ethumb=%p, video_start=%f", e, t); + e->video.time = t; } EAPI float @@ -1550,3 +1551,109 @@ ethumb_ecore_evas_get(const Ethumb *e) return e->sub_ee; } + +Ethumb * +ethumb_dup(const Ethumb *e) +{ + Ecore_Evas *ee; + Ecore_Evas *sub_ee; + Evas *ev; + Evas *sub_ev; + Evas_Object *o; + Evas_Object *img; + Ethumb *r; + + r = malloc(sizeof (Ethumb)); + if (!r) return NULL; + + memcpy(r, e, sizeof (Ethumb)); + + r->thumb_dir = eina_stringshare_ref(e->thumb_dir); + r->category = eina_stringshare_ref(e->category); + r->src_path = eina_stringshare_ref(e->src_path); + r->src_key = eina_stringshare_ref(e->src_key); + r->thumb_path = eina_stringshare_ref(e->thumb_path); + r->thumb_key = eina_stringshare_ref(e->thumb_key); + + ee = ecore_evas_buffer_new(1, 1); + ev = ecore_evas_get(ee); + if (!ev) + { + ERR("could not create ecore evas buffer"); + free(r); + return NULL; + } + + evas_image_cache_set(ev, 0); + evas_font_cache_set(ev, 0); + + o = ecore_evas_object_image_new(ee); + if (!o) + { + ERR("could not create sub ecore evas buffer"); + ecore_evas_free(ee); + free(r); + return NULL; + } + + sub_ee = ecore_evas_object_ecore_evas_get(o); + sub_ev = ecore_evas_object_evas_get(o); + + evas_image_cache_set(sub_ev, 0); + evas_font_cache_set(sub_ev, 0); + + img = evas_object_image_add(sub_ev); + if (!img) + { + ERR("could not create source objects."); + ecore_evas_free(ee); + free(r); + return NULL; + } + + r->ee = ee; + r->sub_ee = sub_ee; + r->e = ev; + r->sub_e = sub_ev; + r->o = o; + r->img = img; + + r->frame = NULL; + r->finished_idler = NULL; + r->finished_cb = NULL; + r->cb_data = NULL; + r->cb_data_free = NULL; + r->cb_result = 0; + + return r; +} + +#define CHECK_DELTA(Param) \ + if (e1->Param != e2->Param) \ + return EINA_TRUE; + +Eina_Bool +ethumb_cmp(const Ethumb *e1, const Ethumb *e2) +{ + CHECK_DELTA(thumb_dir); + CHECK_DELTA(category); + CHECK_DELTA(tw); + CHECK_DELTA(th); + CHECK_DELTA(format); + CHECK_DELTA(aspect); + CHECK_DELTA(orientation); + CHECK_DELTA(crop_x); + CHECK_DELTA(crop_y); + CHECK_DELTA(quality); + CHECK_DELTA(compress); + CHECK_DELTA(rw); + CHECK_DELTA(rh); + CHECK_DELTA(video.start); + CHECK_DELTA(video.time); + CHECK_DELTA(video.interval); + CHECK_DELTA(video.ntimes); + CHECK_DELTA(video.fps); + CHECK_DELTA(document.page); + + return EINA_FALSE; +} diff --git a/legacy/ethumb/src/lib/Ethumb.h b/legacy/ethumb/src/lib/Ethumb.h index b9c0c86413..afa0220c00 100644 --- a/legacy/ethumb/src/lib/Ethumb.h +++ b/legacy/ethumb/src/lib/Ethumb.h @@ -183,7 +183,11 @@ EAPI void ethumb_file_free(Ethumb *e) EINA_ARG_NONNULL(1); EAPI Eina_Bool ethumb_generate(Ethumb *e, Ethumb_Generate_Cb finished_cb, const void *data, Eina_Free_Cb free_data) EINA_ARG_NONNULL(1, 2); EAPI Eina_Bool ethumb_exists(Ethumb *e) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1) EINA_PURE; -/** + +EAPI Ethumb *ethumb_dup(const Ethumb *e) EINA_ARG_NONNULL(1); +EAPI Eina_Bool ethumb_cmp(const Ethumb *e1, const Ethumb *e2) EINA_ARG_NONNULL(1, 2) EINA_WARN_UNUSED_RESULT EINA_PURE; + + /** * @} */ diff --git a/legacy/ethumb/src/lib/client/Ethumb_Client.c b/legacy/ethumb/src/lib/client/Ethumb_Client.c index e67fbf250d..3e05fac36b 100644 --- a/legacy/ethumb/src/lib/client/Ethumb_Client.c +++ b/legacy/ethumb/src/lib/client/Ethumb_Client.c @@ -78,6 +78,7 @@ #include #include #include +#include #include "Ethumb_Client.h" @@ -123,9 +124,12 @@ struct _Ethumb_Client } die; const char *object_path; + int refcount; + Eina_Bool ethumb_dirty : 1; Eina_Bool connected : 1; Eina_Bool server_started : 1; + Eina_Bool delete_me : 1; }; struct _ethumb_pending_add @@ -164,6 +168,22 @@ struct _ethumb_pending_gen Eina_Free_Cb free_data; }; +typedef struct _Ethumb_Async_Exists Ethumb_Async_Exists; + +struct _Ethumb_Async_Exists +{ + Ethumb *dup; + Ethumb_Client *source; + + Ethumb_Client_Thumb_Exists_Cb exists_cb; + const void *data; + + Ecore_Thread *thread; + int refcount; + + Eina_Bool exists : 1; +}; + static const char _ethumb_dbus_bus_name[] = "org.enlightenment.Ethumb"; static const char _ethumb_dbus_interface[] = "org.enlightenment.Ethumb"; static const char _ethumb_dbus_objects_interface[] = "org.enlightenment.Ethumb.objects"; @@ -463,6 +483,54 @@ error: _ethumb_client_report_connect(client, 0); } +static void +_ethumb_client_exists_heavy(void *data, Ecore_Thread *thread) +{ + Ethumb_Async_Exists *async = data; + + async->exists = ethumb_exists(async->dup); +} + +static void +_ethumb_client_exists_end(void *data, Ecore_Thread *thread) +{ + Ethumb_Async_Exists *async = data; + Ethumb *tmp = async->source->ethumb; + + async->source->ethumb = async->dup; + async->source->ethumb_dirty = ethumb_cmp(tmp, async->dup); + async->exists_cb(async->source, (Ethumb_Exists*) async, async->exists, (void*) async->data); + async->source->ethumb = tmp; + + ethumb_free(async->dup); + async->source->refcount--; + + if (async->source->delete_me == EINA_TRUE) + ethumb_client_disconnect(async->source); + + free(async); +} + +static void +_ethumb_client_exists_cancel(void *data, Ecore_Thread *thread) +{ + Ethumb_Async_Exists *async = data; + Ethumb *tmp = async->source->ethumb; + + async->source->ethumb = async->dup; + async->source->ethumb_dirty = ethumb_cmp(tmp, async->dup); + async->exists_cb(async->source, (Ethumb_Exists*) async, EINA_FALSE, (void*) async->data); + async->source->ethumb = tmp; + + ethumb_free(async->dup); + async->source->refcount--; + + if (async->source->delete_me == EINA_TRUE) + ethumb_client_disconnect(async->source); + + free(async); +} + /** * @endcond */ @@ -652,6 +720,10 @@ ethumb_client_disconnect(Ethumb_Client *client) EINA_SAFETY_ON_NULL_RETURN(client); + client->delete_me = EINA_TRUE; + if (client->refcount > 0) + return ; + if (!client->connected) goto end_connection; @@ -1218,22 +1290,22 @@ ethumb_client_generate_cancel(Ethumb_Client *client, int id, Ethumb_Client_Gener l = client->pending_add; while (l) { - struct _ethumb_pending_add *pending = l->data; - if (pending->id != id32) + struct _ethumb_pending_add *pending_add = l->data; + if (pending_add->id != id32) { l = l->next; continue; } client->pending_add = eina_list_remove_list(client->pending_add, l); - eina_stringshare_del(pending->file); - eina_stringshare_del(pending->key); - eina_stringshare_del(pending->thumb); - eina_stringshare_del(pending->thumb_key); - dbus_pending_call_cancel(pending->pending_call); - dbus_pending_call_unref(pending->pending_call); - if (pending->free_data) - pending->free_data(pending->data); - free(pending); + eina_stringshare_del(pending_add->file); + eina_stringshare_del(pending_add->key); + eina_stringshare_del(pending_add->thumb); + eina_stringshare_del(pending_add->thumb_key); + dbus_pending_call_cancel(pending_add->pending_call); + dbus_pending_call_unref(pending_add->pending_call); + if (pending_add->free_data) + pending_add->free_data(pending_add->data); + free(pending_add); found = 1; break; } @@ -1244,20 +1316,20 @@ ethumb_client_generate_cancel(Ethumb_Client *client, int id, Ethumb_Client_Gener l = client->pending_gen; while (l) { - struct _ethumb_pending_gen *pending = l->data; - if (pending->id != id32) + struct _ethumb_pending_gen *pending_gen = l->data; + if (pending_gen->id != id32) { l = l->next; continue; } client->pending_gen = eina_list_remove_list(client->pending_gen, l); - eina_stringshare_del(pending->file); - eina_stringshare_del(pending->key); - eina_stringshare_del(pending->thumb); - eina_stringshare_del(pending->thumb_key); - if (pending->free_data) - pending->free_data(pending->data); - free(pending); + eina_stringshare_del(pending_gen->file); + eina_stringshare_del(pending_gen->key); + eina_stringshare_del(pending_gen->thumb); + eina_stringshare_del(pending_gen->thumb_key); + if (pending_gen->free_data) + pending_gen->free_data(pending_gen->data); + free(pending_gen); break; } @@ -1781,15 +1853,15 @@ ethumb_client_category_get(const Ethumb_Client *client) * @param client the client instance to use. Must @b not be @c * NULL. May be pending connected (can be called before @c * connected_cb) - * @param time duration (in seconds). Defaults to 3 seconds. + * @param t duration (in seconds). Defaults to 3 seconds. */ EAPI void -ethumb_client_video_time_set(Ethumb_Client *client, float time) +ethumb_client_video_time_set(Ethumb_Client *client, float t) { EINA_SAFETY_ON_NULL_RETURN(client); client->ethumb_dirty = 1; - ethumb_video_time_set(client->ethumb, time); + ethumb_video_time_set(client->ethumb, t); } /** @@ -2047,12 +2119,67 @@ ethumb_client_thumb_path_get(Ethumb_Client *client, const char **path, const cha * * @return @c EINA_TRUE if it exists, @c EINA_FALSE otherwise. */ -EAPI Eina_Bool -ethumb_client_thumb_exists(Ethumb_Client *client) +EAPI Ethumb_Exists * +ethumb_client_thumb_exists(Ethumb_Client *client, Ethumb_Client_Thumb_Exists_Cb exists_cb, const void *data) { - EINA_SAFETY_ON_NULL_RETURN_VAL(client, 0); + Ethumb_Async_Exists *async; - return ethumb_exists(client->ethumb); + EINA_SAFETY_ON_NULL_RETURN_VAL(client, NULL); + + async = malloc(sizeof (Ethumb_Async_Exists)); + if (!async) + { + exists_cb(client, NULL, EINA_FALSE, (void*) data); + return NULL; + } + + async->dup = ethumb_dup(client->ethumb); + async->source = client; + async->source->refcount++; + async->exists_cb = exists_cb; + async->data = data; + async->exists = EINA_FALSE; + + async->refcount = 1; + async->thread = ecore_thread_run(_ethumb_client_exists_heavy, + _ethumb_client_exists_end, + _ethumb_client_exists_cancel, + async); + + return (Ethumb_Exists*) async; +} + +/** + * Cancel an ongoing exists request. + * + * @param exists the request to cancel. + */ +EAPI void +ethumb_client_thumb_exists_cancel(Ethumb_Exists *exists) +{ + Ethumb_Async_Exists *async = (Ethumb_Async_Exists*) exists; + + async->refcount--; + + if (async->refcount > 0) return ; + + ecore_thread_cancel(async->thread); +} + +/** + * Check if an exists request was cancelled. + * + * @param exists the request to check. + * @result return EINA_TRUE if the request was cancelled. + */ +EAPI Eina_Bool +ethumb_client_thumb_exists_check(Ethumb_Exists *exists) +{ + Ethumb_Async_Exists *async = (Ethumb_Async_Exists*) exists; + + if (!async) return EINA_TRUE; + + return ecore_thread_check(async->thread); } /** diff --git a/legacy/ethumb/src/lib/client/Ethumb_Client.h b/legacy/ethumb/src/lib/client/Ethumb_Client.h index 355ecadc1f..e105693e0a 100644 --- a/legacy/ethumb/src/lib/client/Ethumb_Client.h +++ b/legacy/ethumb/src/lib/client/Ethumb_Client.h @@ -1,6 +1,7 @@ #ifndef __ETHUMB_CLIENT_H__ #define __ETHUMB_CLIENT_H__ 1 +#include #include #ifdef EAPI @@ -63,6 +64,15 @@ extern "C" { */ typedef struct _Ethumb_Client Ethumb_Client; +/** + * @brief client exists request handle. + * + * The exists request handle is created by ethumb_client_thumb_exists(), + * automatically destroyed when it end and cancelled when requested by + * ethumb_client_thumb_exists_cancel(). + */ +typedef struct _Ethumb_Exists Ethumb_Exists; + /** * @brief reports results of ethumb_client_connect() * @@ -100,6 +110,19 @@ typedef void (*Ethumb_Client_Die_Cb)(void *data, Ethumb_Client *client); */ typedef void (*Ethumb_Client_Generate_Cb)(void *data, Ethumb_Client *client, int id, const char *file, const char *key, const char *thumb_path, const char *thumb_key, Eina_Bool success); +/** + * @brief report results of ethumb_client_thumb_exists(). + * + * @param client handle of the current connection to server. + * @param exists EINA_TRUE if the thumbnail exists. + * @param data extra context given to ethumb_client_thumb_exists(). + * + * During the execution of the callback the state of the @p client is + * temporarily realy restored to what it was when the call to + * ethumb_client_thumb_exists() was done. + */ +typedef void (*Ethumb_Client_Thumb_Exists_Cb)(Ethumb_Client *client, Ethumb_Exists *thread, Eina_Bool exists, void *data); + /** * @brief reports results of ethumb_client_generate_cancel() * @@ -171,7 +194,9 @@ EAPI Eina_Bool ethumb_client_file_set(Ethumb_Client *client, const char *path, c EAPI void ethumb_client_file_get(Ethumb_Client *client, const char **path, const char **key); EAPI void ethumb_client_file_free(Ethumb_Client *client); -EAPI Eina_Bool ethumb_client_thumb_exists(Ethumb_Client *client); +EAPI Ethumb_Exists *ethumb_client_thumb_exists(Ethumb_Client *client, Ethumb_Client_Thumb_Exists_Cb exists_cb, const void *data); +EAPI void ethumb_client_thumb_exists_cancel(Ethumb_Exists *exists); +EAPI Eina_Bool ethumb_client_thumb_exists_check(Ethumb_Exists *exists); EAPI int ethumb_client_generate(Ethumb_Client *client, Ethumb_Client_Generate_Cb generated_cb, const void *data, Eina_Free_Cb free_data); EAPI void ethumb_client_generate_cancel(Ethumb_Client *client, int id, Ethumb_Client_Generate_Cancel_Cb cancel_cb, const void *data, Eina_Free_Cb free_data); EAPI void ethumb_client_generate_cancel_all(Ethumb_Client *client);