EFL migration revision 67547
[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_PULSE_STOP, "elm");
162    edje_object_signal_emit(wd->frame, EDJE_SIGNAL_GENERATE_STOP, "elm");
163    evas_object_smart_callback_call(wd->self, SIG_GENERATE_STOP, NULL);
164 }
165
166 static void
167 _thumb_loaded(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
168 {
169    Widget_Data *wd = data;
170    const char *thumb_path;
171    const char *thumb_key;
172
173    evas_object_image_file_get(wd->view, &thumb_path, &thumb_key);
174
175    _thumb_ready(wd, thumb_path, thumb_key);
176 }
177
178 /* As we do use stat to check if a thumbnail is available, it's possible
179    that we end up accessing before the file is completly written on disk.
180    By retrying each time a thumbnail is finished we should be fine or not.
181 */
182 static Eina_Bool
183 _retry_thumb(Widget_Data *wd)
184 {
185    int r;
186
187    if ((wd->is_video) && (wd->thumb.format == ETHUMB_THUMB_EET))
188      {
189         edje_object_file_set(wd->view, NULL, NULL);
190         if (!edje_object_file_set(wd->view,
191                                   wd->thumb.thumb_path,
192                                   "movie/thumb"))
193           {
194              if (pending_request == 0)
195                ERR("could not set file=%s key=%s for %s",
196                    wd->thumb.thumb_path,
197                    wd->thumb.thumb_key,
198                    wd->file);
199              goto view_err;
200           }
201      }
202    else
203      {
204         evas_object_image_file_set(wd->view, NULL, NULL);
205         evas_object_image_file_set(wd->view,
206                                    wd->thumb.thumb_path,
207                                    wd->thumb.thumb_key);
208         r = evas_object_image_load_error_get(wd->view);
209         if (r != EVAS_LOAD_ERROR_NONE)
210           {
211              if (pending_request == 0)
212                ERR("%s: %s", wd->thumb.thumb_path, evas_load_error_str(r));
213              goto view_err;
214           }
215
216         evas_object_event_callback_add(wd->view,
217                                        EVAS_CALLBACK_IMAGE_PRELOADED,
218                                        _thumb_loaded, wd);
219         evas_object_image_preload(wd->view, EINA_TRUE);
220         return EINA_TRUE;
221      }
222
223    _thumb_ready(wd, wd->thumb.thumb_path, wd->thumb.thumb_key);
224
225    eina_stringshare_del(wd->thumb.thumb_path);
226    wd->thumb.thumb_path = NULL;
227
228    eina_stringshare_del(wd->thumb.thumb_key);
229    wd->thumb.thumb_key = NULL;
230
231    return EINA_TRUE;
232
233  view_err:
234    return EINA_FALSE;
235 }
236
237 static void
238 _finished_thumb(Widget_Data *wd,
239                 const char *thumb_path,
240                 const char *thumb_key)
241 {
242    Eina_List *l, *ll;
243    Evas *evas;
244    int r;
245
246    evas = evas_object_evas_get(wd->self);
247    if ((wd->view) && (wd->is_video ^ wd->was_video))
248      {
249         evas_object_del(wd->view);
250         wd->view = NULL;
251      }
252    wd->was_video = wd->is_video;
253
254    if ((wd->is_video) &&
255        (ethumb_client_format_get(_elm_ethumb_client) == ETHUMB_THUMB_EET))
256      {
257         if (!wd->view)
258           {
259              wd->view = edje_object_add(evas);
260              if (!wd->view)
261                {
262                   ERR("could not create edje object");
263                   goto err;
264                }
265              elm_widget_sub_object_add(wd->self, wd->view);
266           }
267
268         if (!edje_object_file_set(wd->view, thumb_path, thumb_key))
269           {
270              wd->thumb.thumb_path = eina_stringshare_ref(thumb_path);
271              wd->thumb.thumb_key = eina_stringshare_ref(thumb_key);
272              wd->thumb.format = ethumb_client_format_get(_elm_ethumb_client);
273              wd->thumb.retry = EINA_TRUE;
274
275              retry = eina_list_append(retry, wd);
276              return ;
277           }
278      }
279    else
280      {
281         if (!wd->view)
282           {
283              wd->view = evas_object_image_filled_add(evas);
284              if (!wd->view)
285                {
286                   ERR("could not create image object");
287                   goto err;
288                }
289              evas_object_event_callback_add(wd->view,
290                                             EVAS_CALLBACK_IMAGE_PRELOADED,
291                                             _thumb_loaded, wd);
292              elm_widget_sub_object_add(wd->self, wd->view);
293              evas_object_hide(wd->view);
294           }
295
296         evas_object_image_file_set(wd->view, thumb_path, thumb_key);
297         r = evas_object_image_load_error_get(wd->view);
298         if (r != EVAS_LOAD_ERROR_NONE)
299           {
300              WRN("%s: %s", thumb_path, evas_load_error_str(r));
301              wd->thumb.thumb_path = eina_stringshare_ref(thumb_path);
302              wd->thumb.thumb_key = eina_stringshare_ref(thumb_key);
303              wd->thumb.format = ethumb_client_format_get(_elm_ethumb_client);
304              wd->thumb.retry = EINA_TRUE;
305
306              retry = eina_list_append(retry, wd);
307              return ;
308           }
309
310         evas_object_image_preload(wd->view, 0);
311         return ;
312      }
313
314    _thumb_ready(wd, thumb_path, thumb_key);
315
316    EINA_LIST_FOREACH_SAFE(retry, l, ll, wd)
317      if (_retry_thumb(wd))
318        retry = eina_list_remove_list(retry, l);
319
320    if (pending_request == 0)
321      EINA_LIST_FREE(retry, wd)
322        {
323           eina_stringshare_del(wd->thumb.thumb_path);
324           wd->thumb.thumb_path = NULL;
325
326           eina_stringshare_del(wd->thumb.thumb_key);
327           wd->thumb.thumb_key = NULL;
328
329           evas_object_del(wd->view);
330           wd->view = NULL;
331
332           edje_object_signal_emit(wd->frame, EDJE_SIGNAL_LOAD_ERROR, "elm");
333           evas_object_smart_callback_call(wd->self, SIG_LOAD_ERROR, NULL);
334        }
335
336    return;
337
338 err:
339    edje_object_signal_emit(wd->frame, EDJE_SIGNAL_LOAD_ERROR, "elm");
340    evas_object_smart_callback_call(wd->self, SIG_LOAD_ERROR, NULL);
341 }
342
343 static void
344 _elm_thumb_done(Ethumb_Client *client __UNUSED__, const char *thumb_path, const char *thumb_key, void *data)
345 {
346    Widget_Data *wd = data;
347
348    assert(wd->thumb.request);
349
350    pending_request--;
351    wd->thumb.request = NULL;
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 :*/