diff --git a/legacy/elementary/ChangeLog b/legacy/elementary/ChangeLog index 052bd6c73e..00d6f9a357 100644 --- a/legacy/elementary/ChangeLog +++ b/legacy/elementary/ChangeLog @@ -1533,3 +1533,7 @@ * Fix elm to use key not keyname (otherwise xmodmap and friends don't work). + +2013-08-09 Cedric Bail + + * Add support for URL in Elm_Image. diff --git a/legacy/elementary/NEWS b/legacy/elementary/NEWS index ab0d98276f..d639c3c462 100644 --- a/legacy/elementary/NEWS +++ b/legacy/elementary/NEWS @@ -124,6 +124,7 @@ Improvements: * Move cursor when mouse moves with longpress. * Show magnifier when selection handlers are pressed or moved. * Change the method to calculate a distance which be scrolled from linear to sine curve. + * Add support for URL in Elm_Image. Fixes: * Now elm_datetime_field_limit_set() can set year limits wihtout problems. diff --git a/legacy/elementary/src/bin/test.c b/legacy/elementary/src/bin/test.c index 0e2c712155..8e0fddff43 100644 --- a/legacy/elementary/src/bin/test.c +++ b/legacy/elementary/src/bin/test.c @@ -204,6 +204,7 @@ void test_datetime(void *data, Evas_Object *obj, void *event_info); void test_popup(void *data, Evas_Object *obj, void *event_info); void test_dayselector(void *data, Evas_Object *obj, void *event_info); void test_image(void *data, Evas_Object *obj, void *event_info); +void test_remote_image(void *data, Evas_Object *obj, void *event_info); void test_external_button(void *data, Evas_Object *obj, void *event_info); void test_external_slider(void *data, Evas_Object *obj, void *event_info); void test_external_scroller(void *data, Evas_Object *obj, void *event_info); @@ -528,6 +529,7 @@ add_tests: ADD_TEST(NULL, "Images", "Photo", test_photo); ADD_TEST(NULL, "Images", "Thumb", test_thumb); ADD_TEST(NULL, "Images", "Image", test_image); + ADD_TEST(NULL, "Images", "Image Remote", test_remote_image); ADD_TEST(NULL, "Images", "Slideshow", test_slideshow); #ifdef HAVE_EMOTION ADD_TEST(NULL, "Images", "Video", test_video); diff --git a/legacy/elementary/src/bin/test_image.c b/legacy/elementary/src/bin/test_image.c index 4809a6423c..253dda1464 100644 --- a/legacy/elementary/src/bin/test_image.c +++ b/legacy/elementary/src/bin/test_image.c @@ -83,4 +83,54 @@ test_image(void *data __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info evas_object_resize(win, 320, 480); evas_object_show(win); } + +void +test_remote_image(void *data __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__) +{ + Evas_Object *win, *box, *im, *rd, *rdg = NULL; + int i; + + win = elm_win_util_standard_add("image test", "Image Test"); + elm_win_autodel_set(win, EINA_TRUE); + + box = elm_box_add(win); + evas_object_size_hint_weight_set(box, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + elm_win_resize_object_add(win, box); + evas_object_show(box); + + im = elm_image_add(win); + elm_image_file_set(im, "http://31.media.tumblr.com/29f1ecd4f98aaff73fb21f479b450d4c/tumblr_mqsxdciQmB1rrju89o1_1280.jpg", NULL); + elm_image_resizable_set(im, EINA_TRUE, EINA_TRUE); + evas_object_size_hint_weight_set(im, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_size_hint_align_set(im, EVAS_HINT_FILL, EVAS_HINT_FILL); + + elm_box_pack_end(box, im); + evas_object_show(im); + + evas_object_data_set(win, "im", im); + + for (i = 0; images_orient[i].name; ++i) + { + rd = elm_radio_add(win); + evas_object_size_hint_align_set(rd, EVAS_HINT_FILL, EVAS_HINT_FILL); + evas_object_size_hint_weight_set(rd, EVAS_HINT_EXPAND, 0.0); + elm_radio_state_value_set(rd, images_orient[i].orient); + elm_object_text_set(rd, images_orient[i].name); + elm_box_pack_end(box, rd); + evas_object_show(rd); + evas_object_smart_callback_add(rd, "changed", my_im_ch, win); + if (!rdg) + { + rdg = rd; + evas_object_data_set(win, "rdg", rdg); + } + else + { + elm_radio_group_add(rd, rdg); + } + } + + evas_object_resize(win, 320, 480); + evas_object_show(win); +} #endif diff --git a/legacy/elementary/src/lib/Makefile.am b/legacy/elementary/src/lib/Makefile.am index 559a459b7d..e87794b46a 100644 --- a/legacy/elementary/src/lib/Makefile.am +++ b/legacy/elementary/src/lib/Makefile.am @@ -463,6 +463,7 @@ elm_thumb.c \ elm_toolbar.c \ elm_transit.c \ elm_util.c \ +elm_url.c \ elm_video.c \ elm_web.c \ elm_web2.c \ diff --git a/legacy/elementary/src/lib/elm_image.c b/legacy/elementary/src/lib/elm_image.c index da0ca256b9..5e3a0c7c7b 100644 --- a/legacy/elementary/src/lib/elm_image.c +++ b/legacy/elementary/src/lib/elm_image.c @@ -16,9 +16,17 @@ EAPI Eo_Op ELM_OBJ_IMAGE_BASE_ID = EO_NOOP; static const char SIG_DND[] = "drop"; static const char SIG_CLICKED[] = "clicked"; +static const char SIG_DOWNLOAD_START[] = "download,start"; +static const char SIG_DOWNLOAD_PROGRESS[] = "download,progress"; +static const char SIG_DOWNLOAD_DONE[] = "download,done"; +static const char SIG_DOWNLOAD_ERROR[] = "download,error"; static const Evas_Smart_Cb_Description _smart_callbacks[] = { {SIG_DND, ""}, {SIG_CLICKED, ""}, + {SIG_DOWNLOAD_START, ""}, + {SIG_DOWNLOAD_PROGRESS, ""}, + {SIG_DOWNLOAD_DONE, ""}, + {SIG_DOWNLOAD_ERROR, ""}, {NULL, NULL} }; @@ -183,6 +191,7 @@ _elm_image_internal_sizing_eval(Evas_Object *obj, Elm_Image_Smart_Data *sd) static Eina_Bool _elm_image_edje_file_set(Evas_Object *obj, const char *file, + Eina_File *f, const char *group) { Evas_Object *pclip; @@ -207,7 +216,16 @@ _elm_image_edje_file_set(Evas_Object *obj, } sd->edje = EINA_TRUE; - if (!edje_object_file_set(sd->img, file, group)) + if (f) + { + if (!edje_object_mmap_set(sd->img, f, group)) + { + ERR("failed to set edje file '%s', group '%s': %s", file, group, + edje_load_error_str(edje_object_load_error_get(sd->img))); + return EINA_FALSE; + } + } + else if (!edje_object_file_set(sd->img, file, group)) { ERR("failed to set edje file '%s', group '%s': %s", file, group, edje_load_error_str(edje_object_load_error_get(sd->img))); @@ -480,6 +498,9 @@ _elm_image_smart_del(Eo *obj, void *_pd, va_list *list EINA_UNUSED) if (sd->anim_timer) ecore_timer_del(sd->anim_timer); if (sd->img) evas_object_del(sd->img); if (sd->prev_img) evas_object_del(sd->prev_img); + if (sd->remote) elm_url_cancel(sd->remote); + free(sd->remote_data); + eina_stringshare_del(sd->key); eo_do_super(obj, MY_CLASS, evas_obj_smart_del()); } @@ -810,26 +831,24 @@ elm_image_file_set(Evas_Object *obj, } static void -_elm_image_smart_file_set(Eo *obj, void *_pd, va_list *list) +_elm_image_smart_internal_file_set(Eo *obj, Elm_Image_Smart_Data *sd, + const char *file, Eina_File *f, const char *key, Eina_Bool *ret) { - const char *file = va_arg(*list, const char *); - const char *key = va_arg(*list, const char *); - Eina_Bool *ret = va_arg(*list, Eina_Bool *); - Evas_Coord w, h; - Elm_Image_Smart_Data *sd = _pd; - if (eina_str_has_extension(file, ".edj")) { - Eina_Bool int_ret = _elm_image_edje_file_set(obj, file, key); + Eina_Bool int_ret = _elm_image_edje_file_set(obj, file, f, key); if (ret) *ret = int_ret; return; } _elm_image_file_set_do(obj); - evas_object_image_file_set(sd->img, file, key); + if (f) + evas_object_image_mmap_set(sd->img, f, key); + else + evas_object_image_file_set(sd->img, file, key); sd->preloading = EINA_TRUE; evas_object_hide(sd->img); @@ -849,6 +868,108 @@ _elm_image_smart_file_set(Eo *obj, void *_pd, va_list *list) _elm_image_internal_sizing_eval(obj, sd); if (ret) *ret = EINA_TRUE; +} + +static void +_elm_image_smart_download_done(void *data, Elm_Url *url EINA_UNUSED, Eina_Binbuf *download) +{ + Eo *obj = data; + Elm_Image_Smart_Data *sd = eo_data_scope_get(obj, MY_CLASS); + Eina_File *f; + size_t length; + Eina_Bool ret = EINA_FALSE; + + if (sd->remote_data) free(sd->remote_data); + length = eina_binbuf_length_get(download); + sd->remote_data = eina_binbuf_string_steal(download); + f = eina_file_virtualize(elm_url_get(url), + sd->remote_data, length, + EINA_FALSE); + _elm_image_smart_internal_file_set(obj, sd, elm_url_get(url), f, sd->key, &ret); + eina_file_close(f); + + if (!ret) + { + Elm_Image_Error err = { 0, EINA_TRUE }; + + free(sd->remote_data); + sd->remote_data = NULL; + evas_object_smart_callback_call(obj, SIG_DOWNLOAD_ERROR, &err); + } + else + { + evas_object_smart_callback_call(obj, SIG_DOWNLOAD_DONE, NULL); + } + + sd->remote = NULL; + eina_stringshare_del(sd->key); + sd->key = NULL; +} + +static void +_elm_image_smart_download_cancel(void *data, Elm_Url *url EINA_UNUSED, int error) +{ + Eo *obj = data; + Elm_Image_Smart_Data *sd = eo_data_scope_get(obj, MY_CLASS); + Elm_Image_Error err = { error, EINA_FALSE }; + + evas_object_smart_callback_call(obj, SIG_DOWNLOAD_ERROR, &err); + + sd->remote = NULL; + eina_stringshare_del(sd->key); + sd->key = NULL; +} + +static void +_elm_image_smart_download_progress(void *data, Elm_Url *url EINA_UNUSED, double now, double total) +{ + Eo *obj = data; + Elm_Image_Progress progress; + + progress.now = now; + progress.total = total; + evas_object_smart_callback_call(obj, SIG_DOWNLOAD_PROGRESS, &progress); +} + +static const char *remote_uri[] = { + "http://", "https://", "ftp://" +}; + +static void +_elm_image_smart_file_set(Eo *obj, void *_pd, va_list *list) +{ + const char *file = va_arg(*list, const char *); + const char *key = va_arg(*list, const char *); + Eina_Bool *ret = va_arg(*list, Eina_Bool *); + + Elm_Image_Smart_Data *sd = _pd; + + unsigned int i; + + if (sd->remote) elm_url_cancel(sd->remote); + sd->remote = NULL; + + for (i = 0; i < sizeof (remote_uri) / sizeof (remote_uri[0]); ++i) + if (strncmp(remote_uri[i], file, strlen(remote_uri[i])) == 0) + { + // Found a remote target ! + evas_object_hide(sd->img); + sd->remote = elm_url_download(file, + _elm_image_smart_download_done, + _elm_image_smart_download_cancel, + _elm_image_smart_download_progress, + obj); + if (sd->remote) + { + evas_object_smart_callback_call(obj, SIG_DOWNLOAD_START, NULL); + eina_stringshare_replace(&sd->key, key); + if (ret) *ret = EINA_TRUE; + return ; + } + break; + } + + _elm_image_smart_internal_file_set(obj, sd, file, NULL, key, ret); } EAPI void diff --git a/legacy/elementary/src/lib/elm_image_common.h b/legacy/elementary/src/lib/elm_image_common.h index 7651927c7b..6de250cbb3 100644 --- a/legacy/elementary/src/lib/elm_image_common.h +++ b/legacy/elementary/src/lib/elm_image_common.h @@ -19,4 +19,27 @@ typedef enum ELM_IMAGE_FLIP_TRANSVERSE = 7 /**< flip the image along the y = x line (top-left to bottom-right) */ } Elm_Image_Orient; +/** + * Structure associated with smart callback 'download,progress'. + * @since 1.8 + */ +typedef struct _Elm_Image_Progress Elm_Image_Progress; +struct _Elm_Image_Progress +{ + double now; + double total; +}; + + +/** + * Structre associated with smart callback 'download,error' + * @since 1.8 + */ +typedef struct _Elm_Image_Error Elm_Image_Error; +struct _Elm_Image_Error +{ + int status; + + Eina_Bool open_error; +}; diff --git a/legacy/elementary/src/lib/elm_priv.h b/legacy/elementary/src/lib/elm_priv.h index 212e2ef7f2..6d78e8ab94 100644 --- a/legacy/elementary/src/lib/elm_priv.h +++ b/legacy/elementary/src/lib/elm_priv.h @@ -450,6 +450,18 @@ void *_elm_icon_signal_callback_del(Evas_Object *obj, Edje_Signal_Cb func_cb); /* end of DEPRECATED */ + +/* Elm helper to download content */ +typedef struct _Elm_Url Elm_Url; + +typedef void (*Elm_Url_Done)(void *data, Elm_Url *url, Eina_Binbuf *download); +typedef void (*Elm_Url_Cancel)(void *data, Elm_Url *url, int error); +typedef void (*Elm_Url_Progress)(void *data, Elm_Url *url, double now, double total); + +Elm_Url *elm_url_download(const char *url, Elm_Url_Done done_cb, Elm_Url_Cancel cancel_cb, Elm_Url_Progress progress_cb, const void *data); +void elm_url_cancel(Elm_Url *r); +const char *elm_url_get(Elm_Url *r); + extern char *_elm_appname; extern Elm_Config *_elm_config; extern const char *_elm_data_dir; diff --git a/legacy/elementary/src/lib/elm_url.c b/legacy/elementary/src/lib/elm_url.c new file mode 100644 index 0000000000..2d745615b7 --- /dev/null +++ b/legacy/elementary/src/lib/elm_url.c @@ -0,0 +1,147 @@ +#ifdef HAVE_CONFIG_H +# include "elementary_config.h" +#endif + +#include +#include "elm_priv.h" + +struct _Elm_Url +{ + const char *url; + + struct { + Elm_Url_Done done; + Elm_Url_Cancel cancel; + Elm_Url_Progress progress; + } cb; + + const void *data; + + Ecore_Con_Url *target; + Eina_Binbuf *download; + + struct { + Ecore_Event_Handler *progress; + Ecore_Event_Handler *done; + Ecore_Event_Handler *data; + } handler; +}; + +static void +_elm_url_free(Elm_Url *r) +{ + ecore_con_url_free(r->target); + eina_binbuf_free(r->download); + ecore_event_handler_del(r->handler.progress); + ecore_event_handler_del(r->handler.done); + ecore_event_handler_del(r->handler.data); + eina_stringshare_del(r->url); + free(r); +} + +static Eina_Bool +_elm_url_progress(void *data, int type EINA_UNUSED, void *event) +{ + Ecore_Con_Event_Url_Progress *url_progress = event; + Elm_Url *r = data; + + if (url_progress->url_con != r->target) return EINA_TRUE; + + r->cb.progress((void*) r->data, r, url_progress->down.now, url_progress->down.total); + + return EINA_TRUE; +} + +static Eina_Bool +_elm_url_done(void *data, int type EINA_UNUSED, void *event) +{ + Ecore_Con_Event_Url_Complete *url_complete = event; + Elm_Url *r = data; + + if (url_complete->url_con != r->target) return EINA_TRUE; + + if (url_complete->status == 200) + { + r->cb.done((void*) r->data, r, r->download); + } + else + { + r->cb.cancel((void*) r->data, r, url_complete->status); + } + + _elm_url_free(r); + + return EINA_TRUE; +} + +static Eina_Bool +_elm_url_data(void *data, int type EINA_UNUSED, void *event) +{ + Ecore_Con_Event_Url_Data *url_data = event; + Elm_Url *r = data; + + if (url_data->url_con != r->target) return EINA_TRUE; + + eina_binbuf_append_length(r->download, url_data->data, url_data->size); + + return EINA_TRUE; +} + +Elm_Url * +elm_url_download(const char *url, Elm_Url_Done done_cb, Elm_Url_Cancel cancel_cb, Elm_Url_Progress progress_cb, const void *data) +{ + Ecore_Con_Url *target; + Elm_Url *r; + + ecore_con_url_init(); + + target = ecore_con_url_new(url); + if (!target) goto on_error; + + if (getenv("http_proxy")) ecore_con_url_proxy_set(target, getenv("http_proxy")); + if (getenv("https_proxy")) ecore_con_url_proxy_set(target, getenv("https_proxy")); + if (getenv("ftp_proxy")) ecore_con_url_proxy_set(target, getenv("ftp_proxy")); + + r = malloc(sizeof (Elm_Url)); + if (!r) goto on_error; + + r->url = eina_stringshare_add(url); + r->cb.done = done_cb; + r->cb.cancel = cancel_cb; + r->cb.progress = progress_cb; + r->data = data; + + r->download = eina_binbuf_new(); + r->target = target; + r->handler.progress = ecore_event_handler_add(ECORE_CON_EVENT_URL_PROGRESS, _elm_url_progress, r); + r->handler.done = ecore_event_handler_add(ECORE_CON_EVENT_URL_COMPLETE, _elm_url_done, r); + r->handler.data = ecore_event_handler_add(ECORE_CON_EVENT_URL_DATA, _elm_url_data, r); + + if (!ecore_con_url_get(r->target)) + { + _elm_url_free(r); + cancel_cb((void*) data, NULL, -1); + return NULL; + } + + return r; + + on_error: + ecore_con_url_shutdown(); + + cancel_cb((void*) data, NULL, -1); + return NULL; +} + +void +elm_url_cancel(Elm_Url *r) +{ + r->cb.cancel((void*) r->data, r, 0); + _elm_url_free(r); +} + +const char * +elm_url_get(Elm_Url *r) +{ + return r->url; +} diff --git a/legacy/elementary/src/lib/elm_widget_image.h b/legacy/elementary/src/lib/elm_widget_image.h index cb4b11e8b9..16ec392398 100644 --- a/legacy/elementary/src/lib/elm_widget_image.h +++ b/legacy/elementary/src/lib/elm_widget_image.h @@ -33,6 +33,10 @@ struct _Elm_Image_Smart_Data Evas_Object *prev_img; Ecore_Timer *anim_timer; + Elm_Url *remote; + const char *key; + void *remote_data; + double scale; double frame_duration;