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