1 #ifdef HAVE_CONFIG_H
2 # include "elementary_config.h"
3 #endif
4 
5 #define EFL_ACCESS_OBJECT_PROTECTED
6 
7 #include <Elementary.h>
8 
9 #include "elm_priv.h"
10 #include "elm_thumb_eo.h"
11 #include "elm_widget_thumb.h"
12 
13 #define MY_CLASS_NAME "Elm_Thumb"
14 #define MY_CLASS_NAME_LEGACY "elm_thumb"
15 
16 #define MY_CLASS ELM_THUMB_CLASS
17 
18 static const char SIG_CLICKED[] = "clicked";
19 static const char SIG_CLICKED_DOUBLE[] = "clicked,double";
20 static const char SIG_GENERATE_ERROR[] = "generate,error";
21 static const char SIG_GENERATE_START[] = "generate,start";
22 static const char SIG_GENERATE_STOP[] = "generate,stop";
23 static const char SIG_LOAD_ERROR[] = "load,error";
24 static const char SIG_PRESS[] = "press";
25 static const Evas_Smart_Cb_Description _smart_callbacks[] =
26 {
27    {SIG_CLICKED, ""},
28    {SIG_CLICKED_DOUBLE, ""},
29    {SIG_GENERATE_ERROR, ""},
30    {SIG_GENERATE_START, ""},
31    {SIG_GENERATE_STOP, ""},
32    {SIG_LOAD_ERROR, ""},
33    {SIG_PRESS, ""},
34    {NULL, NULL}
35 };
36 
37 #define EDJE_SIGNAL_GENERATE_START "elm,thumb,generate,start"
38 #define EDJE_SIGNAL_GENERATE_STOP  "elm,thumb,generate,stop"
39 #define EDJE_SIGNAL_GENERATE_ERROR "elm,thumb,generate,error"
40 #define EDJE_SIGNAL_LOAD_ERROR     "elm,thumb,load,error"
41 #define EDJE_SIGNAL_PULSE_START    "elm,state,pulse,start"
42 #define EDJE_SIGNAL_PULSE_STOP     "elm,state,pulse,stop"
43 
44 static struct _Ethumb_Client *_elm_ethumb_client = NULL;
45 static Eina_Bool _elm_ethumb_connected = EINA_FALSE;
46 
47 static Eina_List *retry = NULL;
48 static int pending_request = 0;
49 
50 EAPI int ELM_ECORE_EVENT_ETHUMB_CONNECT = 0;
51 
52 static void
_mouse_down_cb(void * data,Evas * e EINA_UNUSED,Evas_Object * obj,void * event_info)53 _mouse_down_cb(void *data,
54                Evas *e EINA_UNUSED,
55                Evas_Object *obj,
56                void *event_info)
57 {
58    ELM_THUMB_DATA_GET(data, sd);
59    Evas_Event_Mouse_Down *ev = event_info;
60 
61    if (ev->button != 1) return;
62    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) sd->on_hold = EINA_TRUE;
63    else sd->on_hold = EINA_FALSE;
64 
65    if (ev->flags & EVAS_BUTTON_DOUBLE_CLICK)
66      evas_object_smart_callback_call(obj, "clicked", NULL);
67    else
68      efl_event_callback_legacy_call(obj, ELM_THUMB_EVENT_PRESS, NULL);
69 }
70 
71 static void
_mouse_up_cb(void * data,Evas * e EINA_UNUSED,Evas_Object * obj,void * event_info)72 _mouse_up_cb(void *data,
73              Evas *e EINA_UNUSED,
74              Evas_Object *obj,
75              void *event_info)
76 {
77    ELM_THUMB_DATA_GET(data, sd);
78    Evas_Event_Mouse_Up *ev = event_info;
79 
80    if (ev->button != 1) return;
81    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD) sd->on_hold = EINA_TRUE;
82    else sd->on_hold = EINA_FALSE;
83 
84    if (!sd->on_hold)
85      evas_object_smart_callback_call(obj, "clicked", NULL);
86 
87    sd->on_hold = EINA_FALSE;
88 }
89 
90 static void
_thumb_ready_inform(Elm_Thumb_Data * sd,const char * thumb_path,const char * thumb_key)91 _thumb_ready_inform(Elm_Thumb_Data *sd,
92                     const char *thumb_path,
93                     const char *thumb_key)
94 {
95    Evas_Coord mw, mh;
96    Evas_Coord aw, ah;
97    ELM_WIDGET_DATA_GET_OR_RETURN(sd->obj, wd);
98 
99    if ((sd->is_video) && (sd->thumb.format == ETHUMB_THUMB_EET))
100      {
101         edje_object_size_min_get(sd->view, &mw, &mh);
102         edje_object_size_min_restricted_calc(sd->view, &mw, &mh, mw, mh);
103         evas_object_size_hint_min_set(sd->view, mw, mh);
104      }
105    else
106      {
107         evas_object_image_size_get(sd->view, &aw, &ah);
108         evas_object_size_hint_aspect_set(sd->view, EVAS_ASPECT_CONTROL_BOTH,
109                                          aw, ah);
110      }
111 
112    edje_object_part_swallow(wd->resize_obj, "elm.swallow.content", sd->view);
113    eina_stringshare_replace(&(sd->thumb.file), thumb_path);
114    eina_stringshare_replace(&(sd->thumb.key), thumb_key);
115    edje_object_signal_emit(wd->resize_obj, EDJE_SIGNAL_PULSE_STOP, "elm");
116    edje_object_signal_emit(wd->resize_obj, EDJE_SIGNAL_GENERATE_STOP, "elm");
117    efl_event_callback_legacy_call(sd->obj, ELM_THUMB_EVENT_GENERATE_STOP, NULL);
118 }
119 
120 static void
_on_thumb_preloaded(void * data,Evas * e EINA_UNUSED,Evas_Object * obj EINA_UNUSED,void * event_info EINA_UNUSED)121 _on_thumb_preloaded(void *data,
122                     Evas *e EINA_UNUSED,
123                     Evas_Object *obj EINA_UNUSED,
124                     void *event_info EINA_UNUSED)
125 {
126    ELM_THUMB_DATA_GET(data, sd);
127    const char *thumb_path;
128    const char *thumb_key;
129 
130    evas_object_image_file_get(sd->view, &thumb_path, &thumb_key);
131 
132    _thumb_ready_inform(sd, thumb_path, thumb_key);
133 }
134 
135 /* As we do use stat to check if a thumbnail is available, it's
136  * possible that we end up accessing it before the file is completely
137  * written on disk. By retrying each time a thumbnail is finished we
138  * should be fine or not.
139  */
140 static Eina_Bool
_thumb_retry(Elm_Thumb_Data * sd)141 _thumb_retry(Elm_Thumb_Data *sd)
142 {
143    int r;
144 
145    if ((sd->is_video) && (sd->thumb.format == ETHUMB_THUMB_EET))
146      {
147         edje_object_file_set(sd->view, NULL, NULL);
148         if (!edje_object_file_set
149               (sd->view, sd->thumb.thumb_path, "movie/thumb"))
150           {
151              if (pending_request == 0)
152                ERR("could not set file=%s key=%s for %s",
153                    sd->thumb.thumb_path,
154                    sd->thumb.thumb_key,
155                    sd->file);
156              goto view_err;
157           }
158         /* FIXME: Do we want to reload a thumbnail when the file
159            changes? I think not at the moment, as this may increase
160            the presure on the system a lot when using it in a file
161            browser */
162      }
163    else
164      {
165         evas_object_image_file_set(sd->view, NULL, NULL);
166         evas_object_image_file_set
167           (sd->view, sd->thumb.thumb_path, sd->thumb.thumb_key);
168         r = evas_object_image_load_error_get(sd->view);
169         if (r != EVAS_LOAD_ERROR_NONE)
170           {
171              if (pending_request == 0)
172                ERR("%s: %s", sd->thumb.thumb_path, evas_load_error_str(r));
173              goto view_err;
174           }
175 
176         evas_object_event_callback_add
177           (sd->view, EVAS_CALLBACK_IMAGE_PRELOADED, _on_thumb_preloaded, sd->obj);
178         evas_object_image_preload(sd->view, EINA_TRUE);
179 
180         return EINA_TRUE;
181      }
182 
183    _thumb_ready_inform(sd, sd->thumb.thumb_path, sd->thumb.thumb_key);
184 
185    ELM_SAFE_FREE(sd->thumb.thumb_path, eina_stringshare_del);
186    ELM_SAFE_FREE(sd->thumb.thumb_key, eina_stringshare_del);
187 
188    return EINA_TRUE;
189 
190 view_err:
191    return EINA_FALSE;
192 }
193 
194 static void
_thumb_finish(Elm_Thumb_Data * sd,const char * thumb_path,const char * thumb_key)195 _thumb_finish(Elm_Thumb_Data *sd,
196               const char *thumb_path,
197               const char *thumb_key)
198 {
199    Eina_List *l, *ll;
200    Evas *evas;
201    int r;
202    ELM_WIDGET_DATA_GET_OR_RETURN(sd->obj, wd);
203 
204    evas = evas_object_evas_get(sd->obj);
205    if ((sd->view) && (sd->is_video ^ sd->was_video))
206      {
207         ELM_SAFE_FREE(sd->view, evas_object_del);
208      }
209    sd->was_video = sd->is_video;
210 
211    if ((sd->is_video) &&
212        (ethumb_client_format_get(_elm_ethumb_client) == ETHUMB_THUMB_EET))
213      {
214         if (!sd->view)
215           {
216              sd->view = edje_object_add(evas);
217              if (!sd->view)
218                {
219                   ERR("could not create edje object");
220                   goto err;
221                }
222           }
223 
224         if (!edje_object_file_set(sd->view, thumb_path, thumb_key))
225           {
226              sd->thumb.thumb_path = eina_stringshare_ref(thumb_path);
227              sd->thumb.thumb_key = eina_stringshare_ref(thumb_key);
228              sd->thumb.format = ethumb_client_format_get(_elm_ethumb_client);
229              sd->thumb.retry = EINA_TRUE;
230 
231              retry = eina_list_append(retry, sd);
232              efl_data_ref(sd->obj, MY_CLASS);
233              return;
234           }
235      }
236    else
237      {
238         if (!sd->view)
239           {
240              sd->view = evas_object_image_filled_add(evas);
241              if (!sd->view)
242                {
243                   ERR("could not create image object");
244                   goto err;
245                }
246              evas_object_event_callback_add(sd->view, EVAS_CALLBACK_IMAGE_PRELOADED,
247                                             _on_thumb_preloaded, sd->obj);
248              evas_object_hide(sd->view);
249           }
250 
251         evas_object_image_file_set(sd->view, thumb_path, thumb_key);
252         r = evas_object_image_load_error_get(sd->view);
253         if (r != EVAS_LOAD_ERROR_NONE)
254           {
255              WRN("%s: %s", thumb_path, evas_load_error_str(r));
256              sd->thumb.thumb_path = eina_stringshare_ref(thumb_path);
257              sd->thumb.thumb_key = eina_stringshare_ref(thumb_key);
258              sd->thumb.format = ethumb_client_format_get(_elm_ethumb_client);
259              sd->thumb.retry = EINA_TRUE;
260 
261              retry = eina_list_append(retry, sd);
262              efl_data_ref(sd->obj, MY_CLASS);
263              return;
264           }
265 
266         evas_object_image_preload(sd->view, EINA_FALSE);
267         return;
268      }
269 
270    _thumb_ready_inform(sd, thumb_path, thumb_key);
271 
272    EINA_LIST_FOREACH_SAFE(retry, l, ll, sd)
273      {
274         if (_thumb_retry(sd))
275           {
276              retry = eina_list_remove_list(retry, l);
277              efl_data_unref(sd->obj, sd);
278           }
279 
280      }
281 
282    if (pending_request == 0)
283      EINA_LIST_FREE(retry, sd)
284        {
285           efl_data_unref(sd->obj, sd);
286           ELM_SAFE_FREE(sd->thumb.thumb_path, eina_stringshare_del);
287           ELM_SAFE_FREE(sd->thumb.thumb_key, eina_stringshare_del);
288           ELM_SAFE_FREE(sd->view, evas_object_del);
289 
290           wd = efl_data_scope_get(sd->obj, EFL_UI_WIDGET_CLASS);
291           edje_object_signal_emit(wd->resize_obj, EDJE_SIGNAL_LOAD_ERROR, "elm");
292           efl_event_callback_legacy_call(sd->obj, ELM_THUMB_EVENT_LOAD_ERROR, NULL);
293        }
294 
295    return;
296 
297 err:
298    edje_object_signal_emit(wd->resize_obj, EDJE_SIGNAL_LOAD_ERROR, "elm");
299    efl_event_callback_legacy_call(sd->obj, ELM_THUMB_EVENT_LOAD_ERROR, NULL);
300 }
301 
302 static void
_on_ethumb_thumb_done(Ethumb_Client * client EINA_UNUSED,const char * thumb_path,const char * thumb_key,void * data)303 _on_ethumb_thumb_done(Ethumb_Client *client EINA_UNUSED,
304                       const char *thumb_path,
305                       const char *thumb_key,
306                       void *data)
307 {
308    ELM_THUMB_DATA_GET(data, sd);
309 
310    if (EINA_UNLIKELY(!sd->thumb.request))
311      {
312         ERR("Something odd happened with a thumbnail request");
313         return;
314      }
315 
316    pending_request--;
317    sd->thumb.request = NULL;
318 
319    _thumb_finish(sd, thumb_path, thumb_key);
320 }
321 
322 static void
_on_ethumb_thumb_error(Ethumb_Client * client EINA_UNUSED,void * data)323 _on_ethumb_thumb_error(Ethumb_Client *client EINA_UNUSED,
324                        void *data)
325 {
326    ELM_THUMB_DATA_GET(data, sd);
327 
328    if (EINA_UNLIKELY(!sd->thumb.request))
329      {
330         ERR("Something odd happened with a thumbnail request");
331         return;
332      }
333    evas_object_event_callback_del_full(sd->view, EVAS_CALLBACK_IMAGE_PRELOADED,
334                                        _on_thumb_preloaded, sd);
335 
336    pending_request--;
337    sd->thumb.request = NULL;
338 
339    ERR("could not generate thumbnail for %s (key: %s)",
340        sd->thumb.file, sd->thumb.key ? sd->thumb.key : "");
341 
342    ELM_WIDGET_DATA_GET_OR_RETURN(data, wd);
343    edje_object_signal_emit(wd->resize_obj, EDJE_SIGNAL_GENERATE_ERROR, "elm");
344    edje_object_signal_emit(wd->resize_obj, EDJE_SIGNAL_PULSE_STOP, "elm");
345    efl_event_callback_legacy_call(sd->obj, ELM_THUMB_EVENT_GENERATE_ERROR, NULL);
346 }
347 
348 static void
_thumb_start(Elm_Thumb_Data * sd)349 _thumb_start(Elm_Thumb_Data *sd)
350 {
351    if (sd->thumb.aspect)
352      ethumb_client_aspect_set(_elm_ethumb_client, sd->thumb.aspect);
353    if (sd->thumb.size)
354      ethumb_client_fdo_set(_elm_ethumb_client, sd->thumb.size);
355    if (sd->thumb.format)
356      ethumb_client_format_set(_elm_ethumb_client, sd->thumb.format);
357    if (sd->thumb.orient)
358      ethumb_client_orientation_set(_elm_ethumb_client, sd->thumb.orient);
359    if (sd->thumb.tw && sd->thumb.th)
360      ethumb_client_size_set(_elm_ethumb_client, sd->thumb.tw, sd->thumb.th);
361    if (!EINA_DBL_EQ(sd->thumb.cropx, 0) && !EINA_DBL_EQ(sd->thumb.cropy, 0))
362      ethumb_client_crop_align_set(_elm_ethumb_client, sd->thumb.cropx, sd->thumb.cropy);
363    if (sd->thumb.quality)
364      ethumb_client_quality_set(_elm_ethumb_client, sd->thumb.quality);
365    if (sd->thumb.compress)
366      ethumb_client_compress_set(_elm_ethumb_client, sd->thumb.compress);
367    if (sd->thumb.request)
368      {
369         ethumb_client_thumb_async_cancel(_elm_ethumb_client, sd->thumb.request);
370         sd->thumb.request = NULL;
371      }
372    if (sd->thumb.retry)
373      {
374         retry = eina_list_remove(retry, sd);
375         efl_data_unref(sd->obj, sd);
376         sd->thumb.retry = EINA_FALSE;
377      }
378 
379    if (!sd->file) return;
380 
381    ELM_WIDGET_DATA_GET_OR_RETURN(sd->obj, wd);
382    edje_object_signal_emit(wd->resize_obj, EDJE_SIGNAL_PULSE_START, "elm");
383    edje_object_signal_emit(wd->resize_obj, EDJE_SIGNAL_GENERATE_START, "elm");
384    efl_event_callback_legacy_call(sd->obj, ELM_THUMB_EVENT_GENERATE_START, NULL);
385 
386    pending_request++;
387    ethumb_client_file_set(_elm_ethumb_client, sd->file, sd->key);
388    sd->thumb.request = ethumb_client_thumb_async_get(_elm_ethumb_client,
389                                                      _on_ethumb_thumb_done,
390                                                      _on_ethumb_thumb_error,
391                                                      sd->obj);
392 }
393 
394 static Eina_Bool
_thumbnailing_available_cb(void * data,int type EINA_UNUSED,void * ev EINA_UNUSED)395 _thumbnailing_available_cb(void *data,
396                            int type EINA_UNUSED,
397                            void *ev EINA_UNUSED)
398 {
399    ELM_THUMB_DATA_GET(data, sd);
400    _thumb_start(sd);
401 
402    return ECORE_CALLBACK_RENEW;
403 }
404 
405 static Eina_Bool _elm_need_ethumb = EINA_FALSE;
406 static void _on_die_cb(void *, Ethumb_Client *);
407 
408 static void
_connect_cb(void * data EINA_UNUSED,Ethumb_Client * c,Eina_Bool success)409 _connect_cb(void *data EINA_UNUSED,
410             Ethumb_Client *c,
411             Eina_Bool success)
412 {
413    if (success)
414      {
415         ethumb_client_on_server_die_callback_set(c, _on_die_cb, NULL, NULL);
416         _elm_ethumb_connected = EINA_TRUE;
417         ecore_event_add(ELM_ECORE_EVENT_ETHUMB_CONNECT, NULL, NULL, NULL);
418      }
419    else
420      _elm_ethumb_client = NULL;
421 }
422 
423 static void
_on_die_cb(void * data EINA_UNUSED,Ethumb_Client * c EINA_UNUSED)424 _on_die_cb(void *data EINA_UNUSED,
425            Ethumb_Client *c EINA_UNUSED)
426 {
427    if (_elm_ethumb_client)
428      {
429         ethumb_client_disconnect(_elm_ethumb_client);
430         _elm_ethumb_client = NULL;
431      }
432    _elm_ethumb_connected = EINA_FALSE;
433    if (pending_request > 0)
434      _elm_ethumb_client = ethumb_client_connect(_connect_cb, NULL, NULL);
435 }
436 
437 static void
_thumb_show(Elm_Thumb_Data * sd)438 _thumb_show(Elm_Thumb_Data *sd)
439 {
440    ELM_WIDGET_DATA_GET_OR_RETURN(sd->obj, wd);
441    evas_object_show(wd->resize_obj);
442 
443    if (!_elm_ethumb_client)
444      _elm_ethumb_client = ethumb_client_connect(_connect_cb, NULL, NULL);
445    else if (elm_thumb_ethumb_client_connected_get())
446      {
447         _thumb_start(sd);
448         return;
449      }
450 
451    if (!sd->eeh)
452      sd->eeh = ecore_event_handler_add(ELM_ECORE_EVENT_ETHUMB_CONNECT,
453                                        _thumbnailing_available_cb, sd->obj);
454 }
455 
456 EOLIAN static void
_elm_thumb_efl_gfx_entity_visible_set(Eo * obj,Elm_Thumb_Data * sd,Eina_Bool vis)457 _elm_thumb_efl_gfx_entity_visible_set(Eo *obj, Elm_Thumb_Data *sd, Eina_Bool vis)
458 {
459    if (_evas_object_intercept_call(obj, EVAS_OBJECT_INTERCEPT_CB_VISIBLE, 0, vis))
460      return;
461 
462    efl_gfx_entity_visible_set(efl_super(obj, MY_CLASS), vis);
463 
464    if (vis)
465      {
466         _thumb_show(sd);
467         return;
468      }
469 
470    ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd);
471 
472    if (sd->thumb.request)
473      {
474         ethumb_client_thumb_async_cancel(_elm_ethumb_client, sd->thumb.request);
475         sd->thumb.request = NULL;
476 
477         edje_object_signal_emit(wd->resize_obj, EDJE_SIGNAL_GENERATE_STOP, "elm");
478         efl_event_callback_legacy_call(sd->obj, ELM_THUMB_EVENT_GENERATE_STOP, NULL);
479      }
480 
481    if (sd->thumb.retry)
482      {
483         retry = eina_list_remove(retry, sd);
484         efl_data_unref(sd->obj, sd);
485         sd->thumb.retry = EINA_FALSE;
486      }
487 
488    ELM_SAFE_FREE(sd->eeh, ecore_event_handler_del);
489 }
490 
491 void
_elm_unneed_ethumb(void)492 _elm_unneed_ethumb(void)
493 {
494    if (!_elm_need_ethumb) return;
495    _elm_need_ethumb = EINA_FALSE;
496 
497    if (_elm_ethumb_client)
498      {
499         ethumb_client_disconnect(_elm_ethumb_client);
500         _elm_ethumb_client = NULL;
501      }
502    ethumb_client_shutdown();
503 
504    ecore_event_type_flush(ELM_ECORE_EVENT_ETHUMB_CONNECT);
505 }
506 
507 static Eina_Bool
_elm_thumb_dnd_cb(void * data EINA_UNUSED,Evas_Object * o,Elm_Selection_Data * drop)508 _elm_thumb_dnd_cb(void *data EINA_UNUSED,
509                   Evas_Object *o,
510                   Elm_Selection_Data *drop)
511 {
512    if ((!o) || (!drop) || (!drop->data)) return EINA_FALSE;
513    elm_thumb_file_set(o, drop->data, NULL);
514    return EINA_TRUE;
515 }
516 
517 EAPI Eina_Bool
elm_need_ethumb(void)518 elm_need_ethumb(void)
519 {
520    if (_elm_need_ethumb) return EINA_TRUE;
521    _elm_need_ethumb = EINA_TRUE;
522 
523    ELM_ECORE_EVENT_ETHUMB_CONNECT = ecore_event_type_new();
524    ethumb_client_init();
525 
526    return EINA_TRUE;
527 }
528 
529 EOLIAN static void
_elm_thumb_efl_canvas_group_group_add(Eo * obj,Elm_Thumb_Data * _pd EINA_UNUSED)530 _elm_thumb_efl_canvas_group_group_add(Eo *obj, Elm_Thumb_Data *_pd EINA_UNUSED)
531 {
532    ELM_WIDGET_DATA_GET_OR_RETURN(obj, wd);
533 
534    efl_canvas_group_add(efl_super(obj, MY_CLASS));
535 
536    if (!elm_layout_theme_set(obj, "thumb", "base", elm_widget_style_get(obj)))
537      CRI("Failed to set layout!");
538 
539    evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_DOWN,
540                                   _mouse_down_cb, obj);
541    evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_UP,
542                                   _mouse_up_cb, obj);
543 
544    elm_widget_can_focus_set(obj, EINA_FALSE);
545 }
546 
547 EOLIAN static void
_elm_thumb_efl_canvas_group_group_del(Eo * obj,Elm_Thumb_Data * sd)548 _elm_thumb_efl_canvas_group_group_del(Eo *obj, Elm_Thumb_Data *sd)
549 {
550    if (sd->thumb.request)
551      {
552         ethumb_client_thumb_async_cancel(_elm_ethumb_client, sd->thumb.request);
553         sd->thumb.request = NULL;
554      }
555    if (sd->thumb.retry)
556      {
557         retry = eina_list_remove(retry, sd);
558         efl_data_unref(sd->obj, sd);
559         sd->thumb.retry = EINA_FALSE;
560      }
561    evas_object_event_callback_del_full(sd->view, EVAS_CALLBACK_IMAGE_PRELOADED,
562                                        _on_thumb_preloaded, sd);
563 
564    ELM_SAFE_FREE(sd->view, evas_object_del);
565    eina_stringshare_del(sd->thumb.thumb_path);
566    eina_stringshare_del(sd->thumb.thumb_key);
567 
568    eina_stringshare_del(sd->file);
569    eina_stringshare_del(sd->key);
570 
571    ecore_event_handler_del(sd->eeh);
572 
573    efl_canvas_group_del(efl_super(obj, MY_CLASS));
574 }
575 
576 EAPI Evas_Object *
elm_thumb_add(Evas_Object * parent)577 elm_thumb_add(Evas_Object *parent)
578 {
579    EINA_SAFETY_ON_NULL_RETURN_VAL(parent, NULL);
580    return elm_legacy_add(MY_CLASS, parent);
581 }
582 
583 EOLIAN static Eo *
_elm_thumb_efl_object_finalize(Eo * obj,Elm_Thumb_Data * sd)584 _elm_thumb_efl_object_finalize(Eo *obj, Elm_Thumb_Data *sd)
585 {
586    obj = efl_finalize(efl_super(obj, MY_CLASS));
587    if (sd->file) efl_file_load(obj);
588    return obj;
589 }
590 
591 EOLIAN static Eo *
_elm_thumb_efl_object_constructor(Eo * obj,Elm_Thumb_Data * sd)592 _elm_thumb_efl_object_constructor(Eo *obj, Elm_Thumb_Data *sd)
593 {
594    obj = efl_constructor(efl_super(obj, MY_CLASS));
595    efl_canvas_object_type_set(obj, "Elm_Thumb");
596    evas_object_smart_callbacks_descriptions_set(obj, _smart_callbacks);
597    efl_access_object_role_set(obj, EFL_ACCESS_ROLE_IMAGE);
598 
599    sd->obj = obj;
600 
601    return obj;
602 }
603 
604 EOLIAN static Eina_Error
_elm_thumb_efl_file_file_set(Eo * obj EINA_UNUSED,Elm_Thumb_Data * sd,const char * file)605 _elm_thumb_efl_file_file_set(Eo *obj EINA_UNUSED, Elm_Thumb_Data *sd, const char *file)
606 {
607    if (eina_stringshare_replace(&(sd->file), file))
608      sd->loaded = EINA_FALSE;
609    return 0;
610 }
611 
612 EOLIAN static void
_elm_thumb_efl_file_key_set(Eo * obj EINA_UNUSED,Elm_Thumb_Data * sd,const char * key)613 _elm_thumb_efl_file_key_set(Eo *obj EINA_UNUSED, Elm_Thumb_Data *sd, const char *key)
614 {
615    if (eina_stringshare_replace(&(sd->key), key))
616      sd->loaded = EINA_FALSE;
617 }
618 
619 EOLIAN static const char *
_elm_thumb_efl_file_file_get(const Eo * obj EINA_UNUSED,Elm_Thumb_Data * sd)620 _elm_thumb_efl_file_file_get(const Eo *obj EINA_UNUSED, Elm_Thumb_Data *sd)
621 {
622    return sd->file;
623 }
624 
625 EOLIAN static const char *
_elm_thumb_efl_file_key_get(const Eo * obj EINA_UNUSED,Elm_Thumb_Data * sd)626 _elm_thumb_efl_file_key_get(const Eo *obj EINA_UNUSED, Elm_Thumb_Data *sd)
627 {
628    return sd->key;
629 }
630 
631 EOLIAN static Eina_Bool
_elm_thumb_efl_file_loaded_get(const Eo * obj EINA_UNUSED,Elm_Thumb_Data * sd)632 _elm_thumb_efl_file_loaded_get(const Eo *obj EINA_UNUSED, Elm_Thumb_Data *sd)
633 {
634    return sd->loaded;
635 }
636 
637 EOLIAN static void
_elm_thumb_efl_file_unload(Eo * obj EINA_UNUSED,Elm_Thumb_Data * sd)638 _elm_thumb_efl_file_unload(Eo *obj EINA_UNUSED, Elm_Thumb_Data *sd)
639 {
640    sd->is_video = EINA_FALSE;
641    eina_stringshare_replace(&(sd->thumb.file), NULL);
642    eina_stringshare_replace(&(sd->thumb.key), NULL);
643    sd->loaded = EINA_FALSE;
644 
645    if (sd->thumb.request)
646      {
647         ethumb_client_thumb_async_cancel(_elm_ethumb_client, sd->thumb.request);
648         sd->thumb.request = NULL;
649      }
650    if (sd->thumb.retry)
651      {
652         retry = eina_list_remove(retry, sd);
653         efl_data_unref(sd->obj, sd);
654         sd->thumb.retry = EINA_FALSE;
655      }
656    evas_object_event_callback_del_full(sd->view, EVAS_CALLBACK_IMAGE_PRELOADED,
657                                        _on_thumb_preloaded, sd);
658 
659    ELM_SAFE_FREE(sd->view, evas_object_del);
660    eina_stringshare_replace(&sd->thumb.thumb_path, NULL);
661    eina_stringshare_replace(&sd->thumb.thumb_key, NULL);
662 
663    ELM_SAFE_FREE(sd->eeh, ecore_event_handler_del);
664 
665 }
666 
667 EOLIAN static Eina_Error
_elm_thumb_efl_file_load(Eo * obj,Elm_Thumb_Data * sd)668 _elm_thumb_efl_file_load(Eo *obj, Elm_Thumb_Data *sd)
669 {
670    int prefix_size;
671    const char **ext, *ptr;
672    static const char *extensions[] =
673      {
674         ".asf", ".avi", ".bdm", ".bdmv", ".clpi", ".cpi", ".dv", ".fla",
675         ".flv", ".m1v", ".m2t", ".m2v", ".m4v", ".mkv", ".mov", ".mp2",
676         ".mp2ts", ".mp4", ".mpe", ".mpeg", ".mpg", ".mpl", ".mpls", ".mts",
677         ".mxf", ".nut", ".nuv", ".ogg", ".ogm", ".ogv", ".qt", ".rm", ".rmj",
678         ".rmm", ".rms", ".rmvb", ".rmx", ".rv", ".swf", ".ts", ".weba",
679         ".webm", ".wmv", ".3g2", ".3gp", ".3gp2", ".3gpp", ".3gpp2", ".3p2",
680         ".264",
681         NULL
682      };
683 
684    if (efl_file_loaded_get(obj)) return 0;
685    prefix_size = eina_stringshare_strlen(sd->file) - 4;
686    if (prefix_size >= 0)
687      {
688         ptr = sd->file + prefix_size;
689         sd->is_video = EINA_FALSE;
690         for (ext = extensions; *ext; ext++)
691           if (!strcasecmp(ptr, *ext))
692             {
693                sd->is_video = EINA_TRUE;
694                break;
695             }
696      }
697 
698    eina_stringshare_replace(&(sd->thumb.file), NULL);
699    eina_stringshare_replace(&(sd->thumb.key), NULL);
700    sd->loaded = EINA_TRUE;
701 
702    if (evas_object_visible_get(obj))
703      _thumb_show(sd);
704 
705    return 0;
706 }
707 
708 EAPI void *
elm_thumb_ethumb_client_get(void)709 elm_thumb_ethumb_client_get(void)
710 {
711    return _elm_ethumb_client;
712 }
713 
714 EAPI Eina_Bool
elm_thumb_ethumb_client_connected_get(void)715 elm_thumb_ethumb_client_connected_get(void)
716 {
717    return _elm_ethumb_connected;
718 }
719 
720 EOLIAN static void
_elm_thumb_efl_ui_draggable_drag_target_set(Eo * obj,Elm_Thumb_Data * sd,Eina_Bool edit)721 _elm_thumb_efl_ui_draggable_drag_target_set(Eo *obj, Elm_Thumb_Data *sd, Eina_Bool edit)
722 {
723    edit = !!edit;
724    if (sd->edit == edit) return;
725 
726    sd->edit = edit;
727    if (sd->edit)
728      elm_drop_target_add(obj, ELM_SEL_FORMAT_IMAGE,
729                          NULL, NULL,
730                          NULL, NULL,
731                          NULL, NULL,
732                          _elm_thumb_dnd_cb, obj);
733    else
734      elm_drop_target_del(obj, ELM_SEL_FORMAT_IMAGE,
735                          NULL, NULL,
736                          NULL, NULL,
737                          NULL, NULL,
738                          _elm_thumb_dnd_cb, obj);
739 
740    return;
741 }
742 
743 EOLIAN static Eina_Bool
_elm_thumb_efl_ui_draggable_drag_target_get(const Eo * obj EINA_UNUSED,Elm_Thumb_Data * sd)744 _elm_thumb_efl_ui_draggable_drag_target_get(const Eo *obj EINA_UNUSED, Elm_Thumb_Data *sd)
745 {
746    return sd->edit;
747 }
748 
749 EOLIAN static void
_elm_thumb_class_constructor(Efl_Class * klass)750 _elm_thumb_class_constructor(Efl_Class *klass)
751 {
752    evas_smart_legacy_type_register(MY_CLASS_NAME_LEGACY, klass);
753 }
754 
755 EAPI void
elm_thumb_file_set(Eo * obj,const char * file,const char * key)756 elm_thumb_file_set(Eo *obj, const char *file, const char *key)
757 {
758    efl_file_simple_load((Eo *) obj, file, key);
759 }
760 
761 EAPI void
elm_thumb_file_get(const Eo * obj,const char ** file,const char ** key)762 elm_thumb_file_get(const Eo *obj, const char **file, const char **key)
763 {
764    efl_file_simple_get((Eo *) obj, file, key);
765 }
766 
767 /* Legacy deprecated functions */
768 EAPI Eina_Bool
elm_thumb_editable_set(Evas_Object * obj,Eina_Bool edit)769 elm_thumb_editable_set(Evas_Object *obj, Eina_Bool edit)
770 {
771    efl_ui_draggable_drag_target_set(obj, edit);
772    return EINA_TRUE;
773 }
774 
775 EAPI Eina_Bool
elm_thumb_editable_get(const Evas_Object * obj)776 elm_thumb_editable_get(const Evas_Object *obj)
777 {
778    return efl_ui_draggable_drag_target_get(obj);
779 }
780 
781 EAPI void
elm_thumb_aspect_set(Evas_Object * obj,Ethumb_Thumb_Aspect aspect)782 elm_thumb_aspect_set(Evas_Object *obj, Ethumb_Thumb_Aspect aspect)
783 {
784    ELM_THUMB_CHECK(obj);
785    ELM_THUMB_DATA_GET(obj, sd);
786    sd->thumb.aspect = aspect;
787 }
788 
789 EAPI Ethumb_Thumb_Aspect
elm_thumb_aspect_get(const Evas_Object * obj)790 elm_thumb_aspect_get(const Evas_Object *obj)
791 {
792    ELM_THUMB_CHECK(obj) ETHUMB_THUMB_KEEP_ASPECT;
793    ELM_THUMB_DATA_GET(obj, sd);
794    return sd->thumb.aspect;
795 }
796 
797 EAPI void
elm_thumb_fdo_size_set(Evas_Object * obj,Ethumb_Thumb_FDO_Size size)798 elm_thumb_fdo_size_set(Evas_Object *obj, Ethumb_Thumb_FDO_Size size)
799 {
800    ELM_THUMB_CHECK(obj);
801    ELM_THUMB_DATA_GET(obj, sd);
802    sd->thumb.size = size;
803 }
804 
805 EAPI Ethumb_Thumb_FDO_Size
elm_thumb_fdo_size_get(const Evas_Object * obj)806 elm_thumb_fdo_size_get(const Evas_Object *obj)
807 {
808    ELM_THUMB_CHECK(obj) ETHUMB_THUMB_NORMAL;
809    ELM_THUMB_DATA_GET(obj, sd);
810    return sd->thumb.size;
811 }
812 
813 EAPI void
elm_thumb_format_set(Evas_Object * obj,Ethumb_Thumb_Format format)814 elm_thumb_format_set(Evas_Object *obj, Ethumb_Thumb_Format format)
815 {
816    ELM_THUMB_CHECK(obj);
817    ELM_THUMB_DATA_GET(obj, sd);
818    sd->thumb.format = format;
819 }
820 
821 EAPI Ethumb_Thumb_Format
elm_thumb_format_get(const Evas_Object * obj)822 elm_thumb_format_get(const Evas_Object *obj)
823 {
824    ELM_THUMB_CHECK(obj) ETHUMB_THUMB_FDO;
825    ELM_THUMB_DATA_GET(obj, sd);
826    return sd->thumb.format;
827 }
828 
829 EAPI void
elm_thumb_orientation_set(Evas_Object * obj,Ethumb_Thumb_Orientation orient)830 elm_thumb_orientation_set(Evas_Object *obj, Ethumb_Thumb_Orientation orient)
831 {
832    ELM_THUMB_CHECK(obj);
833    ELM_THUMB_DATA_GET(obj, sd);
834    sd->thumb.orient = orient;
835 }
836 
837 EAPI Ethumb_Thumb_Orientation
elm_thumb_orientation_get(const Evas_Object * obj)838 elm_thumb_orientation_get(const Evas_Object *obj)
839 {
840    ELM_THUMB_CHECK(obj) ETHUMB_THUMB_ORIENT_NONE;
841    ELM_THUMB_DATA_GET(obj, sd);
842    return sd->thumb.orient;
843 }
844 
845 EAPI void
elm_thumb_size_set(Evas_Object * obj,int tw,int th)846 elm_thumb_size_set(Evas_Object *obj, int tw, int th)
847 {
848    ELM_THUMB_CHECK(obj);
849    ELM_THUMB_DATA_GET(obj, sd);
850    sd->thumb.tw = tw;
851    sd->thumb.th = th;
852 }
853 
854 EAPI void
elm_thumb_size_get(const Evas_Object * obj,int * tw,int * th)855 elm_thumb_size_get(const Evas_Object *obj, int *tw, int *th)
856 {
857    ELM_THUMB_CHECK(obj);
858    ELM_THUMB_DATA_GET(obj, sd);
859    if (tw)
860      *tw = sd->thumb.tw;
861    if (th)
862      *th = sd->thumb.th;
863 }
864 
865 EAPI void
elm_thumb_crop_align_set(Evas_Object * obj,double cropx,double cropy)866 elm_thumb_crop_align_set(Evas_Object *obj, double cropx, double cropy)
867 {
868    ELM_THUMB_CHECK(obj);
869    ELM_THUMB_DATA_GET(obj, sd);
870    sd->thumb.cropx = cropx;
871    sd->thumb.cropy = cropy;
872 }
873 
874 EAPI void
elm_thumb_crop_align_get(const Evas_Object * obj,double * cropx,double * cropy)875 elm_thumb_crop_align_get(const Evas_Object *obj, double *cropx, double *cropy)
876 {
877    ELM_THUMB_CHECK(obj);
878    ELM_THUMB_DATA_GET(obj, sd);
879    if (cropx)
880      *cropx = sd->thumb.cropx;
881    if (cropy)
882      *cropy = sd->thumb.cropy;
883 }
884 
885 EAPI void
elm_thumb_compress_set(Evas_Object * obj,int compress)886 elm_thumb_compress_set(Evas_Object *obj, int compress)
887 {
888    ELM_THUMB_CHECK(obj);
889    ELM_THUMB_DATA_GET(obj, sd);
890    sd->thumb.compress = compress;
891 }
892 
893 EAPI void
elm_thumb_compress_get(const Evas_Object * obj,int * compress)894 elm_thumb_compress_get(const Evas_Object *obj, int *compress)
895 {
896    ELM_THUMB_CHECK(obj);
897    ELM_THUMB_DATA_GET(obj, sd);
898    if (compress)
899       *compress = sd->thumb.compress;
900 }
901 
902 EAPI void
elm_thumb_quality_set(Evas_Object * obj,int quality)903 elm_thumb_quality_set(Evas_Object *obj, int quality)
904 {
905    ELM_THUMB_CHECK(obj);
906    ELM_THUMB_DATA_GET(obj, sd);
907    sd->thumb.quality = quality;
908 }
909 
910 EAPI void
elm_thumb_quality_get(const Evas_Object * obj,int * quality)911 elm_thumb_quality_get(const Evas_Object *obj, int *quality)
912 {
913    ELM_THUMB_CHECK(obj);
914    ELM_THUMB_DATA_GET(obj, sd);
915    if (quality)
916       *quality = sd->thumb.quality;
917 }
918 
919 EAPI void
elm_thumb_animate_set(Evas_Object * obj,Elm_Thumb_Animation_Setting setting)920 elm_thumb_animate_set(Evas_Object *obj, Elm_Thumb_Animation_Setting setting)
921 {
922    ELM_THUMB_CHECK(obj);
923    ELM_THUMB_DATA_GET(obj, sd);
924    EINA_SAFETY_ON_TRUE_RETURN(setting >= ELM_THUMB_ANIMATION_LAST);
925 
926    sd->anim_setting = setting;
927 
928    if ((sd->is_video) && (sd->thumb.format == ETHUMB_THUMB_EET))
929      {
930         if (setting == ELM_THUMB_ANIMATION_LOOP)
931           edje_object_signal_emit(sd->view, "elm,action,animate_loop", "elm");
932         else if (setting == ELM_THUMB_ANIMATION_START)
933           edje_object_signal_emit(sd->view, "elm,action,animate", "elm");
934         else if (setting == ELM_THUMB_ANIMATION_STOP)
935           edje_object_signal_emit(sd->view, "elm,action,animate_stop", "elm");
936      }
937 }
938 
939 EAPI Elm_Thumb_Animation_Setting
elm_thumb_animate_get(const Evas_Object * obj)940 elm_thumb_animate_get(const Evas_Object *obj)
941 {
942    ELM_THUMB_CHECK(obj) 0;
943    ELM_THUMB_DATA_GET(obj, sd);
944    return sd->anim_setting;
945 }
946 
947 EAPI void
elm_thumb_path_get(const Evas_Object * obj,const char ** file,const char ** key)948 elm_thumb_path_get(const Evas_Object *obj, const char **file, const char **key)
949 {
950    ELM_THUMB_CHECK(obj);
951    ELM_THUMB_DATA_GET(obj, sd);
952    if (file)
953      *file = sd->thumb.file;
954    if (key)
955      *key = sd->thumb.key;
956 }
957 
958 EAPI void
elm_thumb_reload(Evas_Object * obj)959 elm_thumb_reload(Evas_Object *obj)
960 {
961    ELM_THUMB_CHECK(obj);
962    ELM_THUMB_DATA_GET(obj, sd);
963    eina_stringshare_replace(&(sd->thumb.file), NULL);
964    eina_stringshare_replace(&(sd->thumb.key), NULL);
965 
966    if (evas_object_visible_get(obj))
967      _thumb_show(sd);
968 }
969 
970 /* Internal EO APIs and hidden overrides */
971 
972 #define ELM_THUMB_EXTRA_OPS \
973    EFL_CANVAS_GROUP_ADD_DEL_OPS(elm_thumb)
974 
975 #include "elm_thumb_eo.c"
976