elementary: use new Ethumb facility.
[framework/uifw/elementary.git] / src / lib / elm_thumb.c
1 #include <Elementary.h>
2 #include "elm_priv.h"
3
4 typedef struct _Widget_Data Widget_Data;
5
6 struct _Widget_Data
7 {
8    Evas_Object *self;
9    Evas_Object *frame;
10    Evas_Object *view;
11    const char *file;
12    const char *key;
13    struct
14      {
15         const char *file;
16         const char *key;
17 #ifdef HAVE_ELEMENTARY_ETHUMB
18         const char *thumb_path;
19         const char *thumb_key;
20         Ethumb_Client_Async *request;
21
22         Ethumb_Thumb_Format format;
23
24         Eina_Bool retry : 1;
25 #endif
26      } thumb;
27    Ecore_Event_Handler *eeh;
28    Elm_Thumb_Animation_Setting anim_setting;
29    Eina_Bool on_hold : 1;
30    Eina_Bool is_video : 1;
31    Eina_Bool was_video : 1;
32    Eina_Bool edit : 1;
33 };
34
35 static const char *widtype = NULL;
36
37 static const char SIG_CLICKED[] = "clicked";
38 static const char SIG_CLICKED_DOUBLE[] = "clicked,double";
39 static const char SIG_GENERATE_ERROR[] = "generate,error";
40 static const char SIG_GENERATE_START[] = "generate,start";
41 static const char SIG_GENERATE_STOP[] = "generate,stop";
42 static const char SIG_LOAD_ERROR[] = "load,error";
43 static const char SIG_PRESS[] = "press";
44
45 static const Evas_Smart_Cb_Description _signals[] =
46 {
47      {SIG_CLICKED, ""},
48      {SIG_CLICKED_DOUBLE, ""},
49      {SIG_GENERATE_ERROR, ""},
50      {SIG_GENERATE_START, ""},
51      {SIG_GENERATE_STOP, ""},
52      {SIG_LOAD_ERROR, ""},
53      {SIG_PRESS, ""},
54      {NULL, NULL}
55 };
56
57 #define EDJE_SIGNAL_GENERATE_START "elm,thumb,generate,start"
58 #define EDJE_SIGNAL_GENERATE_STOP "elm,thumb,generate,stop"
59 #define EDJE_SIGNAL_GENERATE_ERROR "elm,thumb,generate,error"
60 #define EDJE_SIGNAL_LOAD_ERROR "elm,thumb,load,error"
61 #define EDJE_SIGNAL_PULSE_START "elm,state,pulse,start"
62 #define EDJE_SIGNAL_PULSE_STOP "elm,state,pulse,stop"
63
64 struct _Ethumb_Client *_elm_ethumb_client = NULL;
65 Eina_Bool _elm_ethumb_connected = EINA_FALSE;
66 #ifdef HAVE_ELEMENTARY_ETHUMB
67 static Eina_List *retry = NULL;
68 static int pending_request = 0;
69 #endif
70
71 EAPI int ELM_ECORE_EVENT_ETHUMB_CONNECT = 0;
72
73 static void
74 _del_hook(Evas_Object *obj)
75 {
76    Widget_Data *wd = elm_widget_data_get(obj);
77
78 #ifdef HAVE_ELEMENTARY_ETHUMB
79    if (wd->thumb.request)
80      {
81        ethumb_client_thumb_async_cancel(_elm_ethumb_client, wd->thumb.request);
82        wd->thumb.request = NULL;
83      }
84    if (wd->thumb.retry)
85      {
86         retry = eina_list_remove(retry, wd);
87         wd->thumb.retry = EINA_FALSE;
88      }
89
90    eina_stringshare_del(wd->thumb.thumb_path);
91    eina_stringshare_del(wd->thumb.thumb_key);
92 #endif
93
94    eina_stringshare_del(wd->file);
95    eina_stringshare_del(wd->key);
96    if (wd->eeh) ecore_event_handler_del(wd->eeh);
97    free(wd);
98 }
99
100 static void
101 _theme_hook(Evas_Object *obj)
102 {
103    Widget_Data *wd = elm_widget_data_get(obj);
104    _elm_theme_object_set(obj, wd->frame, "thumb", "base",
105                          elm_widget_style_get(obj));
106 }
107
108 #ifdef HAVE_ELEMENTARY_ETHUMB
109 static void
110 _mouse_down_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info)
111 {
112    Widget_Data *wd = data;
113    Evas_Event_Mouse_Down *ev = event_info;
114
115    if (ev->button != 1)
116      return;
117    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD)
118      wd->on_hold = EINA_TRUE;
119    else
120      wd->on_hold = EINA_FALSE;
121    if (ev->flags & EVAS_BUTTON_DOUBLE_CLICK)
122      evas_object_smart_callback_call(wd->self, SIG_CLICKED_DOUBLE, NULL);
123    else
124      evas_object_smart_callback_call(wd->self, SIG_PRESS, NULL);
125 }
126
127 static void
128 _mouse_up_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info)
129 {
130    Widget_Data *wd = data;
131    Evas_Event_Mouse_Up *ev = event_info;
132
133    if (ev->button != 1)
134      return;
135    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD)
136      wd->on_hold = EINA_TRUE;
137    else
138      wd->on_hold = EINA_FALSE;
139    if (!wd->on_hold)
140      evas_object_smart_callback_call(wd->self, SIG_CLICKED, NULL);
141    wd->on_hold = EINA_FALSE;
142 }
143
144 static void
145 _thumb_ready(Widget_Data *wd, const char *thumb_path, const char *thumb_key)
146 {
147    Evas_Coord mw, mh;
148    Evas_Coord aw, ah;
149
150    evas_object_image_size_get(wd->view, &aw, &ah);
151    evas_object_size_hint_aspect_set(wd->view,
152                                     EVAS_ASPECT_CONTROL_BOTH,
153                                     aw, ah);
154    edje_object_part_swallow(wd->frame, "elm.swallow.content", wd->view);
155    edje_object_size_min_get(wd->frame, &mw, &mh);
156    edje_object_size_min_restricted_calc(wd->frame, &mw, &mh, mw, mh);
157    evas_object_size_hint_min_set(wd->self, mw, mh);
158    eina_stringshare_replace(&(wd->thumb.file), thumb_path);
159    eina_stringshare_replace(&(wd->thumb.key), thumb_key);
160    edje_object_signal_emit(wd->frame, EDJE_SIGNAL_GENERATE_STOP, "elm");
161    evas_object_smart_callback_call(wd->self, SIG_GENERATE_STOP, NULL);
162 }
163
164 static void
165 _thumb_loaded(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
166 {
167    Widget_Data *wd = data;
168    const char *thumb_path;
169    const char *thumb_key;
170
171    evas_object_image_file_get(wd->view, &thumb_path, &thumb_key);
172
173    _thumb_ready(wd, thumb_path, thumb_key);
174 }
175
176 /* As we do use stat to check if a thumbnail is available, it's possible
177    that we end up accessing before the file is completly written on disk.
178    By retrying each time a thumbnail is finished we should be fine or not.
179 */
180 static Eina_Bool
181 _retry_thumb(Widget_Data *wd)
182 {
183    int r;
184
185    if ((wd->is_video) && (wd->thumb.format == ETHUMB_THUMB_EET))
186      {
187         edje_object_file_set(wd->view, NULL, NULL);
188         if (!edje_object_file_set(wd->view,
189                                   wd->thumb.thumb_path,
190                                   "movie/thumb"))
191           {
192              if (pending_request == 0)
193                ERR("could not set file=%s key=%s for %s",
194                    wd->thumb.thumb_path,
195                    wd->thumb.thumb_key,
196                    wd->file);
197              goto view_err;
198           }
199      }
200    else
201      {
202         evas_object_image_file_set(wd->view, NULL, NULL);
203         evas_object_image_file_set(wd->view,
204                                    wd->thumb.thumb_path,
205                                    wd->thumb.thumb_key);
206         r = evas_object_image_load_error_get(wd->view);
207         if (r != EVAS_LOAD_ERROR_NONE)
208           {
209              if (pending_request == 0)
210                ERR("%s: %s", wd->thumb.thumb_path, evas_load_error_str(r));
211              goto view_err;
212           }
213
214         evas_object_event_callback_add(wd->view,
215                                        EVAS_CALLBACK_IMAGE_PRELOADED,
216                                        _thumb_loaded, wd);
217         evas_object_image_preload(wd->view, EINA_TRUE);
218         return EINA_TRUE;
219      }
220
221    _thumb_ready(wd, wd->thumb.thumb_path, wd->thumb.thumb_key);
222
223    eina_stringshare_del(wd->thumb.thumb_path);
224    wd->thumb.thumb_path = NULL;
225
226    eina_stringshare_del(wd->thumb.thumb_key);
227    wd->thumb.thumb_key = NULL;
228
229    return EINA_TRUE;
230
231  view_err:
232    return EINA_FALSE;
233 }
234
235 static void
236 _finished_thumb(Widget_Data *wd,
237                 const char *thumb_path,
238                 const char *thumb_key)
239 {
240    Eina_List *l, *ll;
241    Evas *evas;
242    int r;
243
244    evas = evas_object_evas_get(wd->self);
245    if ((wd->view) && (wd->is_video ^ wd->was_video))
246      {
247         evas_object_del(wd->view);
248         wd->view = NULL;
249      }
250    wd->was_video = wd->is_video;
251
252    if ((wd->is_video) &&
253        (ethumb_client_format_get(_elm_ethumb_client) == ETHUMB_THUMB_EET))
254      {
255         if (!wd->view)
256           {
257              wd->view = edje_object_add(evas);
258              if (!wd->view)
259                {
260                   ERR("could not create edje object");
261                   goto err;
262                }
263              elm_widget_sub_object_add(wd->self, wd->view);
264           }
265
266         if (!edje_object_file_set(wd->view, thumb_path, thumb_key))
267           {
268              wd->thumb.thumb_path = eina_stringshare_ref(thumb_path);
269              wd->thumb.thumb_key = eina_stringshare_ref(thumb_key);
270              wd->thumb.format = ethumb_client_format_get(_elm_ethumb_client);
271              wd->thumb.retry = EINA_TRUE;
272
273              retry = eina_list_append(retry, wd);
274              return ;
275           }
276      }
277    else
278      {
279         if (!wd->view)
280           {
281              wd->view = evas_object_image_filled_add(evas);
282              if (!wd->view)
283                {
284                   ERR("could not create image object");
285                   goto err;
286                }
287              evas_object_event_callback_add(wd->view,
288                                             EVAS_CALLBACK_IMAGE_PRELOADED,
289                                             _thumb_loaded, wd);
290              elm_widget_sub_object_add(wd->self, wd->view);
291              evas_object_hide(wd->view);
292           }
293
294         evas_object_image_file_set(wd->view, thumb_path, thumb_key);
295         r = evas_object_image_load_error_get(wd->view);
296         if (r != EVAS_LOAD_ERROR_NONE)
297           {
298              WRN("%s: %s", thumb_path, evas_load_error_str(r));
299              wd->thumb.thumb_path = eina_stringshare_ref(thumb_path);
300              wd->thumb.thumb_key = eina_stringshare_ref(thumb_key);
301              wd->thumb.format = ethumb_client_format_get(_elm_ethumb_client);
302              wd->thumb.retry = EINA_TRUE;
303
304              retry = eina_list_append(retry, wd);
305              return ;
306           }
307
308         evas_object_image_preload(wd->view, 0);
309         return ;
310      }
311
312    _thumb_ready(wd, thumb_path, thumb_key);
313
314    EINA_LIST_FOREACH_SAFE(retry, l, ll, wd)
315      if (_retry_thumb(wd))
316        retry = eina_list_remove_list(retry, l);
317
318    if (pending_request == 0)
319      EINA_LIST_FREE(retry, wd)
320        {
321           eina_stringshare_del(wd->thumb.thumb_path);
322           wd->thumb.thumb_path = NULL;
323
324           eina_stringshare_del(wd->thumb.thumb_key);
325           wd->thumb.thumb_key = NULL;
326
327           evas_object_del(wd->view);
328           wd->view = NULL;
329
330           edje_object_signal_emit(wd->frame, EDJE_SIGNAL_LOAD_ERROR, "elm");
331           evas_object_smart_callback_call(wd->self, SIG_LOAD_ERROR, NULL);
332        }
333
334    return;
335
336 err:
337    edje_object_signal_emit(wd->frame, EDJE_SIGNAL_LOAD_ERROR, "elm");
338    evas_object_smart_callback_call(wd->self, SIG_LOAD_ERROR, NULL);
339 }
340
341 static void
342 _elm_thumb_done(Ethumb_Client *client __UNUSED__, const char *thumb_path, const char *thumb_key, void *data)
343 {
344    Widget_Data *wd = data;
345
346    assert(wd->thumb.request);
347
348    pending_request--;
349    wd->thumb.request = NULL;
350
351    edje_object_signal_emit(wd->frame, EDJE_SIGNAL_PULSE_STOP, "elm");
352
353    _finished_thumb(wd, thumb_path, thumb_key);
354 }
355
356 static void
357 _elm_thumb_error(Ethumb_Client *client __UNUSED__, void *data)
358 {
359    Widget_Data *wd = data;
360
361    assert(wd->thumb.request);
362
363    pending_request--;
364    wd->thumb.request = NULL;
365
366    ERR("could not generate thumbnail for %s (key: %s)", wd->thumb.file, wd->thumb.key ? wd->thumb.key : "");
367
368    edje_object_signal_emit(wd->frame, EDJE_SIGNAL_GENERATE_ERROR, "elm");
369    evas_object_smart_callback_call(wd->self, SIG_GENERATE_ERROR, NULL);
370 }
371
372 static void
373 _thumb_apply(Widget_Data *wd)
374 {
375    if (wd->thumb.request)
376      {
377         ethumb_client_thumb_async_cancel(_elm_ethumb_client, wd->thumb.request);
378         wd->thumb.request = NULL;
379      }
380    if (wd->thumb.retry)
381      {
382         retry = eina_list_remove(retry, wd);
383         wd->thumb.retry = EINA_FALSE;
384      }
385
386    if (!wd->file) return;
387
388    edje_object_signal_emit(wd->frame, EDJE_SIGNAL_PULSE_START, "elm");
389    edje_object_signal_emit(wd->frame, EDJE_SIGNAL_GENERATE_START, "elm");
390    evas_object_smart_callback_call(wd->self, SIG_GENERATE_START, NULL);
391
392    pending_request++;
393    ethumb_client_file_set(_elm_ethumb_client, wd->file, wd->key);
394    wd->thumb.request = ethumb_client_thumb_async_get(_elm_ethumb_client,
395                                                      _elm_thumb_done,
396                                                      _elm_thumb_error,
397                                                      wd);
398 }
399
400 static Eina_Bool
401 _thumb_apply_cb(void *data, int type __UNUSED__, void *ev __UNUSED__)
402 {
403    _thumb_apply(data);
404    return ECORE_CALLBACK_RENEW;
405 }
406
407 static void
408 _thumb_show(Widget_Data *wd)
409 {
410    evas_object_show(wd->frame);
411
412    if (elm_thumb_ethumb_client_connected())
413      {
414         _thumb_apply(wd);
415         return;
416      }
417
418    if (!wd->eeh)
419      wd->eeh = ecore_event_handler_add(ELM_ECORE_EVENT_ETHUMB_CONNECT,
420                                        _thumb_apply_cb, wd);
421 }
422
423 static void
424 _thumb_show_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
425 {
426    _thumb_show(data);
427 }
428
429 static void
430 _thumb_hide_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
431 {
432    Widget_Data *wd = data;
433
434    evas_object_hide(wd->frame);
435
436    if (wd->thumb.request)
437      {
438         ethumb_client_thumb_async_cancel(_elm_ethumb_client, wd->thumb.request);
439         wd->thumb.request = NULL;
440
441         edje_object_signal_emit(wd->frame, EDJE_SIGNAL_GENERATE_STOP, "elm");
442         evas_object_smart_callback_call(wd->self, SIG_GENERATE_STOP, NULL);
443      }
444
445    if (wd->thumb.retry)
446      {
447         retry = eina_list_remove(retry, wd);
448         wd->thumb.retry = EINA_FALSE;
449      }
450
451    if (wd->eeh)
452      {
453         ecore_event_handler_del(wd->eeh);
454         wd->eeh = NULL;
455      }
456 }
457
458 #endif
459
460 #ifdef ELM_ETHUMB
461 static int _elm_need_ethumb = 0;
462
463 static void _on_die_cb(void *, Ethumb_Client *);
464
465 static void
466 _connect_cb(void *data __UNUSED__, Ethumb_Client *c, Eina_Bool success)
467 {
468    if (success)
469      {
470         ethumb_client_on_server_die_callback_set(c, _on_die_cb, NULL, NULL);
471         _elm_ethumb_connected = EINA_TRUE;
472         ecore_event_add(ELM_ECORE_EVENT_ETHUMB_CONNECT, NULL, NULL, NULL);
473      }
474    else
475      _elm_ethumb_client = NULL;
476 }
477
478 static void
479 _on_die_cb(void *data __UNUSED__, Ethumb_Client *c __UNUSED__)
480 {
481    ethumb_client_disconnect(_elm_ethumb_client);
482    _elm_ethumb_client = NULL;
483    _elm_ethumb_connected = EINA_FALSE;
484    _elm_ethumb_client = ethumb_client_connect(_connect_cb, NULL, NULL);
485 }
486 #endif
487
488 void
489 _elm_unneed_ethumb(void)
490 {
491 #ifdef ELM_ETHUMB
492    if (--_elm_need_ethumb) return;
493
494    ethumb_client_disconnect(_elm_ethumb_client);
495    _elm_ethumb_client = NULL;
496    ethumb_client_shutdown();
497    ELM_ECORE_EVENT_ETHUMB_CONNECT = 0;
498 #endif
499 }
500
501 static Eina_Bool
502 _elm_thumb_dropcb(void *data __UNUSED__, Evas_Object *o, Elm_Selection_Data *drop)
503 {
504    if ((!o) || (!drop) || (!drop->data)) return EINA_FALSE;
505    elm_thumb_file_set(o, drop->data, NULL);
506    return EINA_TRUE;
507 }
508
509 EAPI Eina_Bool
510 elm_need_ethumb(void)
511 {
512 #ifdef ELM_ETHUMB
513    if (_elm_need_ethumb++) return EINA_TRUE;
514    ELM_ECORE_EVENT_ETHUMB_CONNECT = ecore_event_type_new();
515    ethumb_client_init();
516    _elm_ethumb_client = ethumb_client_connect(_connect_cb, NULL, NULL);
517    return EINA_TRUE;
518 #else
519    return EINA_FALSE;
520 #endif
521 }
522
523 EAPI Evas_Object *
524 elm_thumb_add(Evas_Object *parent)
525 {
526    Evas *e;
527    Widget_Data *wd;
528    Evas_Object *obj;
529    Evas_Coord minw, minh;
530
531    ELM_WIDGET_STANDARD_SETUP(wd, Widget_Data, parent, e, obj, NULL);
532
533    ELM_SET_WIDTYPE(widtype, "thumb");
534    elm_widget_type_set(obj, "thumb");
535    elm_widget_sub_object_add(parent, obj);
536    elm_widget_data_set(obj, wd);
537    elm_widget_del_hook_set(obj, _del_hook);
538    elm_widget_theme_hook_set(obj, _theme_hook);
539    elm_widget_can_focus_set(obj, EINA_FALSE);
540
541    wd->frame = edje_object_add(e);
542    _elm_theme_object_set(obj, wd->frame, "thumb", "base", "default");
543    elm_widget_resize_object_set(obj, wd->frame);
544
545    edje_object_size_min_calc(obj, &minw, &minh);
546    evas_object_size_hint_min_set(obj, minw, minh);
547
548    wd->self = obj;
549    wd->view = NULL;
550    wd->file = NULL;
551    wd->key = NULL;
552    wd->eeh = NULL;
553    wd->on_hold = EINA_FALSE;
554    wd->is_video = EINA_FALSE;
555    wd->was_video = EINA_FALSE;
556
557 #ifdef HAVE_ELEMENTARY_ETHUMB
558    wd->thumb.thumb_path = NULL;
559    wd->thumb.thumb_key = NULL;
560    wd->thumb.request = NULL;
561    evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_DOWN,
562                                   _mouse_down_cb, wd);
563    evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_UP,
564                                   _mouse_up_cb, wd);
565    evas_object_event_callback_add(obj, EVAS_CALLBACK_SHOW,
566                                   _thumb_show_cb, wd);
567    evas_object_event_callback_add(obj, EVAS_CALLBACK_HIDE,
568                                   _thumb_hide_cb, wd);
569 #endif
570
571    // TODO: convert Elementary to subclassing of Evas_Smart_Class
572    // TODO: and save some bytes, making descriptions per-class and not instance!
573    evas_object_smart_callbacks_descriptions_set(obj, _signals);
574    return obj;
575 }
576
577 EAPI void
578 elm_thumb_reload(Evas_Object *obj)
579 {
580    ELM_CHECK_WIDTYPE(obj, widtype);
581    Widget_Data *wd = elm_widget_data_get(obj);
582
583    eina_stringshare_replace(&(wd->thumb.file), NULL);
584    eina_stringshare_replace(&(wd->thumb.key), NULL);
585
586 #ifdef HAVE_ELEMENTARY_ETHUMB
587    if (evas_object_visible_get(obj))
588      _thumb_show(wd);
589 #endif
590 }
591
592 EAPI void
593 elm_thumb_file_set(Evas_Object *obj, const char *file, const char *key)
594 {
595    ELM_CHECK_WIDTYPE(obj, widtype);
596    Eina_Bool file_replaced, key_replaced;
597    Widget_Data *wd = elm_widget_data_get(obj);
598
599    file_replaced = eina_stringshare_replace(&(wd->file), file);
600    key_replaced = eina_stringshare_replace(&(wd->key), key);
601
602    if (file_replaced)
603      {
604         int prefix_size;
605         const char **ext, *ptr;
606         static const char *extensions[] =
607           {
608              ".avi", ".mp4", ".ogv", ".mov", ".mpg", ".wmv", NULL
609           };
610
611         prefix_size = eina_stringshare_strlen(wd->file) - 4;
612         if (prefix_size >= 0)
613           {
614              ptr = wd->file + prefix_size;
615              wd->is_video = EINA_FALSE;
616              for (ext = extensions; *ext; ext++)
617                if (!strcasecmp(ptr, *ext))
618                  {
619                     wd->is_video = EINA_TRUE;
620                     break;
621                  }
622           }
623      }
624
625    eina_stringshare_replace(&(wd->thumb.file), NULL);
626    eina_stringshare_replace(&(wd->thumb.key), NULL);
627
628 #ifdef HAVE_ELEMENTARY_ETHUMB
629    if (((file_replaced) || (key_replaced)) && (evas_object_visible_get(obj)))
630      _thumb_show(wd);
631 #endif
632 }
633
634 EAPI void
635 elm_thumb_file_get(const Evas_Object *obj, const char **file, const char **key)
636 {
637    ELM_CHECK_WIDTYPE(obj, widtype);
638    Widget_Data *wd = elm_widget_data_get(obj);
639
640    if (file)
641      *file = wd->file;
642    if (key)
643      *key = wd->key;
644 }
645
646 EAPI void
647 elm_thumb_path_get(const Evas_Object *obj, const char **file, const char **key)
648 {
649    ELM_CHECK_WIDTYPE(obj, widtype);
650    Widget_Data *wd = elm_widget_data_get(obj);
651
652    if (file)
653      *file = wd->thumb.file;
654    if (key)
655      *key = wd->thumb.key;
656 }
657
658 EAPI void
659 elm_thumb_animate_set(Evas_Object *obj, Elm_Thumb_Animation_Setting setting)
660 {
661    ELM_CHECK_WIDTYPE(obj, widtype);
662    Widget_Data *wd = elm_widget_data_get(obj);
663
664    EINA_SAFETY_ON_TRUE_RETURN(setting >= ELM_THUMB_ANIMATION_LAST);
665
666    wd->anim_setting = setting;
667    if (setting == ELM_THUMB_ANIMATION_LOOP)
668      edje_object_signal_emit(wd->view, "animate_loop", "");
669    else if (setting == ELM_THUMB_ANIMATION_START)
670      edje_object_signal_emit(wd->view, "animate", "");
671    else if (setting == ELM_THUMB_ANIMATION_STOP)
672      edje_object_signal_emit(wd->view, "animate_stop", "");
673 }
674
675 EAPI Elm_Thumb_Animation_Setting
676 elm_thumb_animate_get(const Evas_Object *obj)
677 {
678    ELM_CHECK_WIDTYPE(obj, widtype) ELM_THUMB_ANIMATION_LAST;
679    Widget_Data *wd = elm_widget_data_get(obj);
680
681    return wd->anim_setting;
682 }
683
684 EAPI void *
685 elm_thumb_ethumb_client_get(void)
686 {
687    return _elm_ethumb_client;
688 }
689
690 EAPI Eina_Bool
691 elm_thumb_ethumb_client_connected(void)
692 {
693    return _elm_ethumb_connected;
694 }
695
696 EAPI Eina_Bool
697 elm_thumb_editable_set(Evas_Object *obj, Eina_Bool edit)
698 {
699    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
700    Widget_Data *wd = elm_widget_data_get(obj);
701
702    if (!wd) return EINA_FALSE;
703    edit = !!edit;
704    if (wd->edit == edit) return EINA_TRUE;
705
706    wd->edit = edit;
707    if (wd->edit)
708      elm_drop_target_add(obj, ELM_SEL_FORMAT_IMAGE,
709                          _elm_thumb_dropcb, obj);
710    else
711      elm_drop_target_del(obj);
712
713    return EINA_TRUE;
714 }
715
716 EAPI Eina_Bool
717 elm_thumb_editable_get(const Evas_Object *obj)
718 {
719    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
720    Widget_Data *wd = elm_widget_data_get(obj);
721
722    if (!wd) return EINA_FALSE;
723    return wd->edit;
724 }
725
726 /* vim:set ts=8 sw=3 sts=3 expandtab cino=>5n-3f0^-2{2(0W1st0 :*/