X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Flib%2Felm_thumb.c;h=fee178d6e9ef9e6ca4605d910d5e2fcb5c4b578c;hb=cc2079af4743ef36091f89275285a9c944474aa7;hp=eee274e229e8953ad809e5a45e7a2e0addcf266c;hpb=c341c3205fb79474e0705fd2f5da0b2b120fd9cb;p=framework%2Fuifw%2Felementary.git diff --git a/src/lib/elm_thumb.c b/src/lib/elm_thumb.c index eee274e..fee178d 100644 --- a/src/lib/elm_thumb.c +++ b/src/lib/elm_thumb.c @@ -1,25 +1,6 @@ #include #include "elm_priv.h" - -/** - * @defgroup Thumb Thumb - * - * A thumb object is used for displaying the thumbnail of an image or video. - * You must have compiled Elementary with Ethumb_Client support and the DBus - * service must be present and auto-activated in order to have thumbnails to - * be generated. - * - * Signals that you can add callbacks for are: - * - * "clicked" - This is called when a user has clicked the thumb without dragging - * around. - * "clicked,double" - This is called when a user has double-clicked the thumb. - * "press" - This is called when a user has pressed down the thumb. - * "generate,start" - The thumbnail generation started. - * "generate,stop" - The generation process stopped. - * "generate,error" - The generation failed. - * "load,error" - The thumbnail image loading failed. - */ +#include typedef struct _Widget_Data Widget_Data; @@ -32,9 +13,17 @@ struct _Widget_Data const char *key; struct { - int id; const char *file; const char *key; +#ifdef HAVE_ELEMENTARY_ETHUMB + const char *thumb_path; + const char *thumb_key; + Ethumb_Client_Async *request; + + Ethumb_Thumb_Format format; + + Eina_Bool retry : 1; +#endif } thumb; Ecore_Event_Handler *eeh; Elm_Thumb_Animation_Setting anim_setting; @@ -75,6 +64,10 @@ static const Evas_Smart_Cb_Description _signals[] = struct _Ethumb_Client *_elm_ethumb_client = NULL; Eina_Bool _elm_ethumb_connected = EINA_FALSE; +#ifdef HAVE_ELEMENTARY_ETHUMB +static Eina_List *retry = NULL; +static int pending_request = 0; +#endif EAPI int ELM_ECORE_EVENT_ETHUMB_CONNECT = 0; @@ -84,9 +77,19 @@ _del_hook(Evas_Object *obj) Widget_Data *wd = elm_widget_data_get(obj); #ifdef HAVE_ELEMENTARY_ETHUMB - if (wd->thumb.id >= 0) - ethumb_client_generate_cancel(_elm_ethumb_client, wd->thumb.id, - NULL, NULL, NULL); + if (wd->thumb.request) + { + ethumb_client_thumb_async_cancel(_elm_ethumb_client, wd->thumb.request); + wd->thumb.request = NULL; + } + if (wd->thumb.retry) + { + retry = eina_list_remove(retry, wd); + wd->thumb.retry = EINA_FALSE; + } + + eina_stringshare_del(wd->thumb.thumb_path); + eina_stringshare_del(wd->thumb.thumb_key); #endif eina_stringshare_del(wd->file); @@ -140,12 +143,105 @@ _mouse_up_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void * } static void -_finished_thumb(Widget_Data *wd, const char *thumb_path, const char *thumb_key) +_thumb_ready(Widget_Data *wd, const char *thumb_path, const char *thumb_key) { - Eina_Bool new_view = EINA_FALSE; - int r; Evas_Coord mw, mh; + Evas_Coord aw, ah; + + evas_object_image_size_get(wd->view, &aw, &ah); + evas_object_size_hint_aspect_set(wd->view, + EVAS_ASPECT_CONTROL_BOTH, + aw, ah); + edje_object_part_swallow(wd->frame, "elm.swallow.content", wd->view); + edje_object_size_min_get(wd->frame, &mw, &mh); + edje_object_size_min_restricted_calc(wd->frame, &mw, &mh, mw, mh); + evas_object_size_hint_min_set(wd->self, mw, mh); + eina_stringshare_replace(&(wd->thumb.file), thumb_path); + eina_stringshare_replace(&(wd->thumb.key), thumb_key); + edje_object_signal_emit(wd->frame, EDJE_SIGNAL_PULSE_STOP, "elm"); + edje_object_signal_emit(wd->frame, EDJE_SIGNAL_GENERATE_STOP, "elm"); + evas_object_smart_callback_call(wd->self, SIG_GENERATE_STOP, NULL); +} + +static void +_thumb_loaded(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__) +{ + Widget_Data *wd = data; + const char *thumb_path; + const char *thumb_key; + + evas_object_image_file_get(wd->view, &thumb_path, &thumb_key); + + _thumb_ready(wd, thumb_path, thumb_key); +} + +/* As we do use stat to check if a thumbnail is available, it's possible + that we end up accessing before the file is completly written on disk. + By retrying each time a thumbnail is finished we should be fine or not. +*/ +static Eina_Bool +_retry_thumb(Widget_Data *wd) +{ + int r; + + if ((wd->is_video) && (wd->thumb.format == ETHUMB_THUMB_EET)) + { + edje_object_file_set(wd->view, NULL, NULL); + if (!edje_object_file_set(wd->view, + wd->thumb.thumb_path, + "movie/thumb")) + { + if (pending_request == 0) + ERR("could not set file=%s key=%s for %s", + wd->thumb.thumb_path, + wd->thumb.thumb_key, + wd->file); + goto view_err; + } + } + else + { + evas_object_image_file_set(wd->view, NULL, NULL); + evas_object_image_file_set(wd->view, + wd->thumb.thumb_path, + wd->thumb.thumb_key); + r = evas_object_image_load_error_get(wd->view); + if (r != EVAS_LOAD_ERROR_NONE) + { + if (pending_request == 0) + ERR("%s: %s", wd->thumb.thumb_path, evas_load_error_str(r)); + goto view_err; + } + + evas_object_event_callback_add(wd->view, + EVAS_CALLBACK_IMAGE_PRELOADED, + _thumb_loaded, wd); + evas_object_image_preload(wd->view, EINA_TRUE); + return EINA_TRUE; + } + + _thumb_ready(wd, wd->thumb.thumb_path, wd->thumb.thumb_key); + + eina_stringshare_del(wd->thumb.thumb_path); + wd->thumb.thumb_path = NULL; + + eina_stringshare_del(wd->thumb.thumb_key); + wd->thumb.thumb_key = NULL; + + return EINA_TRUE; + + view_err: + return EINA_FALSE; +} + +static void +_finished_thumb(Widget_Data *wd, + const char *thumb_path, + const char *thumb_key) +{ + Eina_List *l, *ll; Evas *evas; + int r; evas = evas_object_evas_get(wd->self); if ((wd->view) && (wd->is_video ^ wd->was_video)) @@ -166,14 +262,18 @@ _finished_thumb(Widget_Data *wd, const char *thumb_path, const char *thumb_key) ERR("could not create edje object"); goto err; } - new_view = EINA_TRUE; + elm_widget_sub_object_add(wd->self, wd->view); } - if (!edje_object_file_set(wd->view, thumb_path, "movie/thumb")) + if (!edje_object_file_set(wd->view, thumb_path, thumb_key)) { - ERR("could not set file=%s key=%s for %s", thumb_path, thumb_key, - wd->file); - goto view_err; + wd->thumb.thumb_path = eina_stringshare_ref(thumb_path); + wd->thumb.thumb_key = eina_stringshare_ref(thumb_key); + wd->thumb.format = ethumb_client_format_get(_elm_ethumb_client); + wd->thumb.retry = EINA_TRUE; + + retry = eina_list_append(retry, wd); + return ; } } else @@ -186,54 +286,85 @@ _finished_thumb(Widget_Data *wd, const char *thumb_path, const char *thumb_key) ERR("could not create image object"); goto err; } - new_view = EINA_TRUE; + evas_object_event_callback_add(wd->view, + EVAS_CALLBACK_IMAGE_PRELOADED, + _thumb_loaded, wd); + elm_widget_sub_object_add(wd->self, wd->view); + evas_object_hide(wd->view); } evas_object_image_file_set(wd->view, thumb_path, thumb_key); r = evas_object_image_load_error_get(wd->view); if (r != EVAS_LOAD_ERROR_NONE) { - ERR("%s: %s", thumb_path, evas_load_error_str(r)); - goto view_err; + WRN("%s: %s", thumb_path, evas_load_error_str(r)); + wd->thumb.thumb_path = eina_stringshare_ref(thumb_path); + wd->thumb.thumb_key = eina_stringshare_ref(thumb_key); + wd->thumb.format = ethumb_client_format_get(_elm_ethumb_client); + wd->thumb.retry = EINA_TRUE; + + retry = eina_list_append(retry, wd); + return ; } + + evas_object_image_preload(wd->view, 0); + return ; } - if (new_view) elm_widget_sub_object_add(wd->self, wd->view); - edje_object_part_swallow(wd->frame, "elm.swallow.content", wd->view); - edje_object_size_min_get(wd->frame, &mw, &mh); - edje_object_size_min_restricted_calc(wd->frame, &mw, &mh, mw, mh); - evas_object_size_hint_min_set(wd->self, mw, mh); - eina_stringshare_replace(&(wd->thumb.file), thumb_path); - eina_stringshare_replace(&(wd->thumb.key), thumb_key); - edje_object_signal_emit(wd->frame, EDJE_SIGNAL_GENERATE_STOP, "elm"); - evas_object_smart_callback_call(wd->self, SIG_GENERATE_STOP, NULL); + _thumb_ready(wd, thumb_path, thumb_key); + + EINA_LIST_FOREACH_SAFE(retry, l, ll, wd) + if (_retry_thumb(wd)) + retry = eina_list_remove_list(retry, l); + + if (pending_request == 0) + EINA_LIST_FREE(retry, wd) + { + eina_stringshare_del(wd->thumb.thumb_path); + wd->thumb.thumb_path = NULL; + + eina_stringshare_del(wd->thumb.thumb_key); + wd->thumb.thumb_key = NULL; + + evas_object_del(wd->view); + wd->view = NULL; + + edje_object_signal_emit(wd->frame, EDJE_SIGNAL_LOAD_ERROR, "elm"); + evas_object_smart_callback_call(wd->self, SIG_LOAD_ERROR, NULL); + } + return; -view_err: - evas_object_del(wd->view); - wd->view = NULL; err: edje_object_signal_emit(wd->frame, EDJE_SIGNAL_LOAD_ERROR, "elm"); evas_object_smart_callback_call(wd->self, SIG_LOAD_ERROR, NULL); } static void -_finished_thumb_cb(void *data, Ethumb_Client *c __UNUSED__, int id, const char *file, const char *key, const char *thumb_path, const char *thumb_key, Eina_Bool success) +_elm_thumb_done(Ethumb_Client *client __UNUSED__, const char *thumb_path, const char *thumb_key, void *data) { Widget_Data *wd = data; - EINA_SAFETY_ON_FALSE_RETURN(wd->thumb.id == id); - wd->thumb.id = -1; + assert(wd->thumb.request); - edje_object_signal_emit(wd->frame, EDJE_SIGNAL_PULSE_STOP, "elm"); + pending_request--; + wd->thumb.request = NULL; - if (success) - { - _finished_thumb(wd, thumb_path, thumb_key); - return; - } + _finished_thumb(wd, thumb_path, thumb_key); +} + +static void +_elm_thumb_error(Ethumb_Client *client __UNUSED__, void *data) +{ + Widget_Data *wd = data; + + assert(wd->thumb.request); + + pending_request--; + wd->thumb.request = NULL; + + ERR("could not generate thumbnail for %s (key: %s)", wd->thumb.file, wd->thumb.key ? wd->thumb.key : ""); - ERR("could not generate thumbnail for %s (key: %s)", file, key ? key : ""); edje_object_signal_emit(wd->frame, EDJE_SIGNAL_GENERATE_ERROR, "elm"); evas_object_smart_callback_call(wd->self, SIG_GENERATE_ERROR, NULL); } @@ -241,39 +372,29 @@ _finished_thumb_cb(void *data, Ethumb_Client *c __UNUSED__, int id, const char * static void _thumb_apply(Widget_Data *wd) { - if (wd->thumb.id > 0) + if (wd->thumb.request) { - ethumb_client_generate_cancel - (_elm_ethumb_client, wd->thumb.id, NULL, NULL, NULL); - wd->thumb.id = -1; + ethumb_client_thumb_async_cancel(_elm_ethumb_client, wd->thumb.request); + wd->thumb.request = NULL; + } + if (wd->thumb.retry) + { + retry = eina_list_remove(retry, wd); + wd->thumb.retry = EINA_FALSE; } if (!wd->file) return; - ethumb_client_file_set(_elm_ethumb_client, wd->file, wd->key); - if (ethumb_client_thumb_exists(_elm_ethumb_client)) - { - const char *thumb_path, *thumb_key; + edje_object_signal_emit(wd->frame, EDJE_SIGNAL_PULSE_START, "elm"); + edje_object_signal_emit(wd->frame, EDJE_SIGNAL_GENERATE_START, "elm"); + evas_object_smart_callback_call(wd->self, SIG_GENERATE_START, NULL); - wd->thumb.id = -1; - ethumb_client_thumb_path_get(_elm_ethumb_client, &thumb_path, - &thumb_key); - _finished_thumb(wd, thumb_path, thumb_key); - return; - } - else if ((wd->thumb.id = ethumb_client_generate - (_elm_ethumb_client, _finished_thumb_cb, wd, NULL)) != -1) - { - edje_object_signal_emit(wd->frame, EDJE_SIGNAL_PULSE_START, "elm"); - edje_object_signal_emit(wd->frame, EDJE_SIGNAL_GENERATE_START, "elm"); - evas_object_smart_callback_call(wd->self, SIG_GENERATE_START, NULL); - } - else - { - wd->thumb.id = -1; - edje_object_signal_emit(wd->frame, EDJE_SIGNAL_GENERATE_ERROR, "elm"); - evas_object_smart_callback_call(wd->self, SIG_GENERATE_ERROR, NULL); - } + pending_request++; + ethumb_client_file_set(_elm_ethumb_client, wd->file, wd->key); + wd->thumb.request = ethumb_client_thumb_async_get(_elm_ethumb_client, + _elm_thumb_done, + _elm_thumb_error, + wd); } static Eina_Bool @@ -288,7 +409,7 @@ _thumb_show(Widget_Data *wd) { evas_object_show(wd->frame); - if (elm_thumb_ethumb_client_connected()) + if (elm_thumb_ethumb_client_connected_get()) { _thumb_apply(wd); return; @@ -312,16 +433,21 @@ _thumb_hide_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void evas_object_hide(wd->frame); - if (wd->thumb.id >= 0) + if (wd->thumb.request) { - ethumb_client_generate_cancel - (_elm_ethumb_client, wd->thumb.id, NULL, NULL, NULL); - wd->thumb.id = -1; + ethumb_client_thumb_async_cancel(_elm_ethumb_client, wd->thumb.request); + wd->thumb.request = NULL; edje_object_signal_emit(wd->frame, EDJE_SIGNAL_GENERATE_STOP, "elm"); evas_object_smart_callback_call(wd->self, SIG_GENERATE_STOP, NULL); } + if (wd->thumb.retry) + { + retry = eina_list_remove(retry, wd); + wd->thumb.retry = EINA_FALSE; + } + if (wd->eeh) { ecore_event_handler_del(wd->eeh); @@ -380,12 +506,6 @@ _elm_thumb_dropcb(void *data __UNUSED__, Evas_Object *o, Elm_Selection_Data *dro return EINA_TRUE; } -/** - * This must be called before any other function that handle with - * elm_thumb objects or ethumb_client instances. - * - * @ingroup Thumb - */ EAPI Eina_Bool elm_need_ethumb(void) { @@ -400,17 +520,6 @@ elm_need_ethumb(void) #endif } -/** - * Add a new thumb object to the parent. - * - * @param parent The parent object. - * @return The new object or NULL if it cannot be created. - * - * @see elm_thumb_file_set() - * @see elm_thumb_ethumb_client_get() - * - * @ingroup Thumb - */ EAPI Evas_Object * elm_thumb_add(Evas_Object *parent) { @@ -441,12 +550,14 @@ elm_thumb_add(Evas_Object *parent) wd->file = NULL; wd->key = NULL; wd->eeh = NULL; - wd->thumb.id = -1; wd->on_hold = EINA_FALSE; wd->is_video = EINA_FALSE; wd->was_video = EINA_FALSE; #ifdef HAVE_ELEMENTARY_ETHUMB + wd->thumb.thumb_path = NULL; + wd->thumb.thumb_key = NULL; + wd->thumb.request = NULL; evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_DOWN, _mouse_down_cb, wd); evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_UP, @@ -463,19 +574,6 @@ elm_thumb_add(Evas_Object *parent) return obj; } -/** - * Reload thumbnail if it was generated before. - * - * This is useful if the ethumb client configuration changed, like its - * size, aspect or any other property one set in the handle returned - * by elm_thumb_ethumb_client_get(). - * - * @param obj The thumb object to reload - * - * @see elm_thumb_file_set() - * - * @ingroup Thumb - */ EAPI void elm_thumb_reload(Evas_Object *obj) { @@ -491,23 +589,6 @@ elm_thumb_reload(Evas_Object *obj) #endif } -/** - * Set the file that will be used as thumbnail. - * - * The file can be an image or a video (in that case, acceptable extensions are: - * avi, mp4, ogv, mov, mpg and wmv). To start the video animation, use the - * function elm_thumb_animate(). - * - * @param obj The thumb object. - * @param file The path to file that will be used as thumb. - * @param key The key used in case of an EET file. - * - * @see elm_thumb_file_get() - * @see elm_thumb_reload() - * @see elm_thumb_animate() - * - * @ingroup Thumb - */ EAPI void elm_thumb_file_set(Evas_Object *obj, const char *file, const char *key) { @@ -547,22 +628,11 @@ elm_thumb_file_set(Evas_Object *obj, const char *file, const char *key) #ifdef HAVE_ELEMENTARY_ETHUMB if (((file_replaced) || (key_replaced)) && (evas_object_visible_get(obj))) _thumb_show(wd); +#else + (void)key_replaced; #endif } -/** - * Get the image or video path and key used to generate the thumbnail. - * - * @param obj The thumb object. - * @param file Pointer to filename. - * @param key Pointer to key. - * - * @see elm_thumb_file_set() - * @see elm_thumb_path_get() - * @see elm_thumb_animate() - * - * @ingroup Thumb - */ EAPI void elm_thumb_file_get(const Evas_Object *obj, const char **file, const char **key) { @@ -575,21 +645,6 @@ elm_thumb_file_get(const Evas_Object *obj, const char **file, const char **key) *key = wd->key; } -/** - * Get the path and key to the image or video generated by ethumb. - * - * One just need to make sure that the thumbnail was generated before getting - * its path; otherwise, the path will be NULL. One way to do that is by asking - * for the path when/after the "generate,stop" smart callback is called. - * - * @param obj The thumb object. - * @param file Pointer to thumb path. - * @param key Pointer to thumb key. - * - * @see elm_thumb_file_get() - * - * @ingroup Thumb - */ EAPI void elm_thumb_path_get(const Evas_Object *obj, const char **file, const char **key) { @@ -602,18 +657,6 @@ elm_thumb_path_get(const Evas_Object *obj, const char **file, const char **key) *key = wd->thumb.key; } -/** - * Set the animation state for the thumb object. If its content is an animated - * video, you may start/stop the animation or tell it to play continuously and - * looping. - * - * @param obj The thumb object. - * @param setting The animation setting. - * - * @see elm_thumb_file_set() - * - * @ingroup Thumb - */ EAPI void elm_thumb_animate_set(Evas_Object *obj, Elm_Thumb_Animation_Setting setting) { @@ -631,17 +674,6 @@ elm_thumb_animate_set(Evas_Object *obj, Elm_Thumb_Animation_Setting setting) edje_object_signal_emit(wd->view, "animate_stop", ""); } -/** - * Get the animation state for the thumb object. - * - * @param obj The thumb object. - * @return getting The animation setting or @c ELM_THUMB_ANIMATION_LAST, - * on errors. - * - * @see elm_thumb_file_get() - * - * @ingroup Thumb - */ EAPI Elm_Thumb_Animation_Setting elm_thumb_animate_get(const Evas_Object *obj) { @@ -651,63 +683,14 @@ elm_thumb_animate_get(const Evas_Object *obj) return wd->anim_setting; } -/** - * Get the ethumb_client handle so custom configuration can be made. - * This must be called before the objects are created to be sure no object is - * visible and no generation started. - * - * @return Ethumb_Client instance or NULL. - * - * Example of usage: - * - * @code - * #include - * #ifndef ELM_LIB_QUICKLAUNCH - * EAPI int - * elm_main(int argc, char **argv) - * { - * Ethumb_Client *client; - * - * elm_need_ethumb(); - * - * // ... your code - * - * client = elm_thumb_ethumb_client_get(); - * if (!client) - * { - * ERR("could not get ethumb_client"); - * return 1; - * } - * ethumb_client_size_set(client, 100, 100); - * ethumb_client_crop_align_set(client, 0.5, 0.5); - * // ... your code - * - * // Create elm_thumb objects here - * - * elm_run(); - * elm_shutdown(); - * return 0; - * } - * #endif - * ELM_MAIN() - * @endcode - * - * @ingroup Thumb - */ EAPI void * elm_thumb_ethumb_client_get(void) { return _elm_ethumb_client; } -/** - * Get the ethumb_client connection state. - * - * @return EINA_TRUE if the client is connected to the server or - * EINA_FALSE otherwise. - */ EAPI Eina_Bool -elm_thumb_ethumb_client_connected(void) +elm_thumb_ethumb_client_connected_get(void) { return _elm_ethumb_connected; } @@ -742,4 +725,4 @@ elm_thumb_editable_get(const Evas_Object *obj) return wd->edit; } -/* vim:set ts=8 sw=3 sts=3 expandtab cino=>5n-2f0^-2{2(0W1st0 :*/ +/* vim:set ts=8 sw=3 sts=3 expandtab cino=>5n-3f0^-2{2(0W1st0 :*/