Elementary thumb: Fixed warnings.
[framework/uifw/elementary.git] / src / lib / elm_thumb.c
1 #include <Elementary.h>
2 #include "elm_priv.h"
3
4 /**
5  * @defgroup Thumb Thumb
6  *
7  * A thumb object is used for displaying the thumbnail of an image or video.
8  * You must have compiled Elementary with Ethumb_Client support and the DBus
9  * service must be present and auto-activated in order to have thumbnails to
10  * be generated.
11  *
12  * Signals that you can add callbacks for are:
13  *
14  * "clicked" - This is called when a user has clicked the thumb without dragging
15  *             around.
16  * "clicked,double" - This is called when a user has double-clicked the thumb.
17  * "press" - This is called when a user has pressed down the thumb.
18  * "generate,start" - The thumbnail generation started.
19  * "generate,stop" - The generation process stopped.
20  * "generate,error" - The generation failed.
21  * "load,error" - The thumbnail image loading failed.
22  */
23
24 typedef struct _Widget_Data Widget_Data;
25
26 struct _Widget_Data
27 {
28    Evas_Object *self;
29    Evas_Object *frame;
30    Evas_Object *view;
31    const char *file;
32    const char *key;
33    struct
34      {
35         int id;
36         const char *file;
37         const char *key;
38 #ifdef HAVE_ELEMENTARY_ETHUMB
39         const char *thumb_path;
40         const char *thumb_key;
41         Ethumb_Exists *exists;
42
43         Ethumb_Thumb_Format format;
44
45         Eina_Bool retry : 1;
46 #endif
47      } thumb;
48    Ecore_Event_Handler *eeh;
49    Elm_Thumb_Animation_Setting anim_setting;
50    Eina_Bool on_hold : 1;
51    Eina_Bool is_video : 1;
52    Eina_Bool was_video : 1;
53    Eina_Bool edit : 1;
54 };
55
56 static const char *widtype = NULL;
57
58 static const char SIG_CLICKED[] = "clicked";
59 static const char SIG_CLICKED_DOUBLE[] = "clicked,double";
60 static const char SIG_GENERATE_ERROR[] = "generate,error";
61 static const char SIG_GENERATE_START[] = "generate,start";
62 static const char SIG_GENERATE_STOP[] = "generate,stop";
63 static const char SIG_LOAD_ERROR[] = "load,error";
64 static const char SIG_PRESS[] = "press";
65
66 static const Evas_Smart_Cb_Description _signals[] =
67 {
68      {SIG_CLICKED, ""},
69      {SIG_CLICKED_DOUBLE, ""},
70      {SIG_GENERATE_ERROR, ""},
71      {SIG_GENERATE_START, ""},
72      {SIG_GENERATE_STOP, ""},
73      {SIG_LOAD_ERROR, ""},
74      {SIG_PRESS, ""},
75      {NULL, NULL}
76 };
77
78 #define EDJE_SIGNAL_GENERATE_START "elm,thumb,generate,start"
79 #define EDJE_SIGNAL_GENERATE_STOP "elm,thumb,generate,stop"
80 #define EDJE_SIGNAL_GENERATE_ERROR "elm,thumb,generate,error"
81 #define EDJE_SIGNAL_LOAD_ERROR "elm,thumb,load,error"
82 #define EDJE_SIGNAL_PULSE_START "elm,state,pulse,start"
83 #define EDJE_SIGNAL_PULSE_STOP "elm,state,pulse,stop"
84
85 struct _Ethumb_Client *_elm_ethumb_client = NULL;
86 Eina_Bool _elm_ethumb_connected = EINA_FALSE;
87 #ifdef HAVE_ELEMENTARY_ETHUMB
88 static Eina_List *retry = NULL;
89 static int pending_request = 0;
90 #endif
91
92 EAPI int ELM_ECORE_EVENT_ETHUMB_CONNECT = 0;
93
94 static void
95 _del_hook(Evas_Object *obj)
96 {
97    Widget_Data *wd = elm_widget_data_get(obj);
98
99 #ifdef HAVE_ELEMENTARY_ETHUMB
100    if (wd->thumb.id >= 0)
101      {
102         ethumb_client_generate_cancel(_elm_ethumb_client, wd->thumb.id,
103                                       NULL, NULL, NULL);
104         wd->thumb.id = -1;
105      }
106    if (wd->thumb.exists)
107      {
108         ethumb_client_thumb_exists_cancel(wd->thumb.exists);
109         wd->thumb.exists = NULL;
110      }
111    if (wd->thumb.retry)
112      {
113         retry = eina_list_remove(retry, wd);
114         wd->thumb.retry = EINA_FALSE;
115      }
116
117    eina_stringshare_del(wd->thumb.thumb_path);
118    eina_stringshare_del(wd->thumb.thumb_key);
119 #endif
120
121    eina_stringshare_del(wd->file);
122    eina_stringshare_del(wd->key);
123    if (wd->eeh) ecore_event_handler_del(wd->eeh);
124    free(wd);
125 }
126
127 static void
128 _theme_hook(Evas_Object *obj)
129 {
130    Widget_Data *wd = elm_widget_data_get(obj);
131    _elm_theme_object_set(obj, wd->frame, "thumb", "base",
132                          elm_widget_style_get(obj));
133 }
134
135 #ifdef HAVE_ELEMENTARY_ETHUMB
136 static void
137 _mouse_down_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info)
138 {
139    Widget_Data *wd = data;
140    Evas_Event_Mouse_Down *ev = event_info;
141
142    if (ev->button != 1)
143      return;
144    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD)
145      wd->on_hold = EINA_TRUE;
146    else
147      wd->on_hold = EINA_FALSE;
148    if (ev->flags & EVAS_BUTTON_DOUBLE_CLICK)
149      evas_object_smart_callback_call(wd->self, SIG_CLICKED_DOUBLE, NULL);
150    else
151      evas_object_smart_callback_call(wd->self, SIG_PRESS, NULL);
152 }
153
154 static void
155 _mouse_up_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info)
156 {
157    Widget_Data *wd = data;
158    Evas_Event_Mouse_Up *ev = event_info;
159
160    if (ev->button != 1)
161      return;
162    if (ev->event_flags & EVAS_EVENT_FLAG_ON_HOLD)
163      wd->on_hold = EINA_TRUE;
164    else
165      wd->on_hold = EINA_FALSE;
166    if (!wd->on_hold)
167      evas_object_smart_callback_call(wd->self, SIG_CLICKED, NULL);
168    wd->on_hold = EINA_FALSE;
169 }
170
171 /* As we do use stat to check if a thumbnail is available, it's possible
172    that we end up accessing before the file is completly written on disk.
173    By retrying each time a thumbnail is finished we should be fine or not.
174 */
175 static Eina_Bool
176 _retry_thumb(Widget_Data *wd)
177 {
178    Evas_Coord mw, mh;
179    int r;
180
181    if ((wd->is_video) && (wd->thumb.format == ETHUMB_THUMB_EET))
182      {
183         edje_object_file_set(wd->view, NULL, NULL);
184         if (!edje_object_file_set(wd->view,
185                                   wd->thumb.thumb_path,
186                                   "movie/thumb"))
187           {
188              if (pending_request == 0)
189                ERR("could not set file=%s key=%s for %s",
190                    wd->thumb.thumb_path,
191                    wd->thumb.thumb_key,
192                    wd->file);
193              goto view_err;
194           }
195      }
196    else
197      {
198         evas_object_image_file_set(wd->view, NULL, NULL);
199         evas_object_image_file_set(wd->view,
200                                    wd->thumb.thumb_path,
201                                    wd->thumb.thumb_key);
202         r = evas_object_image_load_error_get(wd->view);
203         if (r != EVAS_LOAD_ERROR_NONE)
204           {
205              if (pending_request == 0)
206                ERR("%s: %s", wd->thumb.thumb_path, evas_load_error_str(r));
207              goto view_err;
208           }
209      }
210
211    edje_object_part_swallow(wd->frame, "elm.swallow.content", wd->view);
212    edje_object_size_min_get(wd->frame, &mw, &mh);
213    edje_object_size_min_restricted_calc(wd->frame, &mw, &mh, mw, mh);
214    evas_object_size_hint_min_set(wd->self, mw, mh);
215    eina_stringshare_replace(&(wd->thumb.file), wd->thumb.thumb_path);
216    eina_stringshare_replace(&(wd->thumb.key), wd->thumb.thumb_key);
217    edje_object_signal_emit(wd->frame, EDJE_SIGNAL_GENERATE_STOP, "elm");
218    evas_object_smart_callback_call(wd->self, SIG_GENERATE_STOP, NULL);
219
220    eina_stringshare_del(wd->thumb.thumb_path);
221    wd->thumb.thumb_path = NULL;
222
223    eina_stringshare_del(wd->thumb.thumb_key);
224    wd->thumb.thumb_key = NULL;
225
226    return EINA_TRUE;
227
228  view_err:
229    return EINA_FALSE;
230 }
231
232 static void
233 _finished_thumb(Widget_Data *wd,
234                 const char *thumb_path,
235                 const char *thumb_key)
236 {
237    Eina_List *l, *ll;
238    Evas *evas;
239    Evas_Coord mw, mh;
240    int r;
241
242    evas = evas_object_evas_get(wd->self);
243    if ((wd->view) && (wd->is_video ^ wd->was_video))
244      {
245         evas_object_del(wd->view);
246         wd->view = NULL;
247      }
248    wd->was_video = wd->is_video;
249
250    if ((wd->is_video) &&
251        (ethumb_client_format_get(_elm_ethumb_client) == ETHUMB_THUMB_EET))
252      {
253         if (!wd->view)
254           {
255              wd->view = edje_object_add(evas);
256              if (!wd->view)
257                {
258                   ERR("could not create edje object");
259                   goto err;
260                }
261              elm_widget_sub_object_add(wd->self, wd->view);
262           }
263
264         if (!edje_object_file_set(wd->view, thumb_path, "movie/thumb"))
265           {
266              wd->thumb.thumb_path = eina_stringshare_ref(thumb_path);
267              wd->thumb.thumb_key = eina_stringshare_ref(thumb_key);
268              wd->thumb.format = ethumb_client_format_get(_elm_ethumb_client);
269              wd->thumb.retry = EINA_TRUE;
270
271              retry = eina_list_append(retry, wd);
272              return ;
273           }
274      }
275    else
276      {
277         if (!wd->view)
278           {
279              wd->view = evas_object_image_filled_add(evas);
280              if (!wd->view)
281                {
282                   ERR("could not create image object");
283                   goto err;
284                }
285              elm_widget_sub_object_add(wd->self, wd->view);
286           }
287
288         evas_object_image_file_set(wd->view, thumb_path, thumb_key);
289         r = evas_object_image_load_error_get(wd->view);
290         if (r != EVAS_LOAD_ERROR_NONE)
291           {
292              WRN("%s: %s", thumb_path, evas_load_error_str(r));
293              wd->thumb.thumb_path = eina_stringshare_ref(thumb_path);
294              wd->thumb.thumb_key = eina_stringshare_ref(thumb_key);
295              wd->thumb.format = ethumb_client_format_get(_elm_ethumb_client);
296              wd->thumb.retry = EINA_TRUE;
297
298              retry = eina_list_append(retry, wd);
299              return ;
300           }
301      }
302
303    edje_object_part_swallow(wd->frame, "elm.swallow.content", wd->view);
304    edje_object_size_min_get(wd->frame, &mw, &mh);
305    edje_object_size_min_restricted_calc(wd->frame, &mw, &mh, mw, mh);
306    evas_object_size_hint_min_set(wd->self, mw, mh);
307    eina_stringshare_replace(&(wd->thumb.file), thumb_path);
308    eina_stringshare_replace(&(wd->thumb.key), thumb_key);
309    edje_object_signal_emit(wd->frame, EDJE_SIGNAL_GENERATE_STOP, "elm");
310    evas_object_smart_callback_call(wd->self, SIG_GENERATE_STOP, NULL);
311
312    EINA_LIST_FOREACH_SAFE(retry, l, ll, wd)
313      if (_retry_thumb(wd))
314        retry = eina_list_remove_list(retry, l);
315
316    if (pending_request == 0)
317      EINA_LIST_FREE(retry, wd)
318        {
319           eina_stringshare_del(wd->thumb.thumb_path);
320           wd->thumb.thumb_path = NULL;
321
322           eina_stringshare_del(wd->thumb.thumb_key);
323           wd->thumb.thumb_key = NULL;
324
325           evas_object_del(wd->view);
326           wd->view = NULL;
327
328           edje_object_signal_emit(wd->frame, EDJE_SIGNAL_LOAD_ERROR, "elm");
329           evas_object_smart_callback_call(wd->self, SIG_LOAD_ERROR, NULL);
330        }
331
332    return;
333
334 err:
335    edje_object_signal_emit(wd->frame, EDJE_SIGNAL_LOAD_ERROR, "elm");
336    evas_object_smart_callback_call(wd->self, SIG_LOAD_ERROR, NULL);
337 }
338
339 static void
340 _finished_thumb_cb(void *data, Ethumb_Client *c __UNUSED__, int id, const char *file, const char *key, const char *thumb_path, const char *thumb_key, Eina_Bool success)
341 {
342    Widget_Data *wd = data;
343
344    EINA_SAFETY_ON_FALSE_RETURN(wd->thumb.id == id);
345    wd->thumb.id = -1;
346
347    pending_request--;
348
349    edje_object_signal_emit(wd->frame, EDJE_SIGNAL_PULSE_STOP, "elm");
350
351    if (success)
352      {
353         _finished_thumb(wd, thumb_path, thumb_key);
354         return;
355      }
356
357    ERR("could not generate thumbnail for %s (key: %s)", file, key ? key : "");
358    edje_object_signal_emit(wd->frame, EDJE_SIGNAL_GENERATE_ERROR, "elm");
359    evas_object_smart_callback_call(wd->self, SIG_GENERATE_ERROR, NULL);
360 }
361
362 static void
363 _thumb_exists(Ethumb_Client *client __UNUSED__, Ethumb_Exists *thread,
364               Eina_Bool exists, void *data)
365 {
366    Widget_Data *wd = data;
367
368    if (ethumb_client_thumb_exists_check(thread))
369      return ;
370
371    wd->thumb.exists = NULL;
372
373    if (exists)
374      {
375         const char *thumb_path, *thumb_key;
376
377         pending_request--;
378
379         wd->thumb.id = -1;
380         ethumb_client_thumb_path_get(_elm_ethumb_client, &thumb_path,
381                                      &thumb_key);
382         _finished_thumb(wd, thumb_path, thumb_key);
383         return;
384      }
385    else if ((wd->thumb.id = ethumb_client_generate
386              (_elm_ethumb_client, _finished_thumb_cb, wd, NULL)) != -1)
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    else
393      {
394         pending_request--;
395
396         wd->thumb.id = -1;
397         edje_object_signal_emit(wd->frame, EDJE_SIGNAL_GENERATE_ERROR, "elm");
398         evas_object_smart_callback_call(wd->self, SIG_GENERATE_ERROR, NULL);
399      }
400
401 }
402
403 static void
404 _thumb_apply(Widget_Data *wd)
405 {
406    if (wd->thumb.id > 0)
407      {
408         ethumb_client_generate_cancel
409            (_elm_ethumb_client, wd->thumb.id, NULL, NULL, NULL);
410         wd->thumb.id = -1;
411      }
412
413    if (wd->thumb.exists)
414      {
415         ethumb_client_thumb_exists_cancel(wd->thumb.exists);
416         wd->thumb.exists = NULL;
417      }
418
419    if (wd->thumb.retry)
420      {
421         retry = eina_list_remove(retry, wd);
422         wd->thumb.retry = EINA_FALSE;
423      }
424
425    if (!wd->file) return;
426
427    pending_request++;
428    ethumb_client_file_set(_elm_ethumb_client, wd->file, wd->key);
429    wd->thumb.exists = ethumb_client_thumb_exists(_elm_ethumb_client,
430                                                  _thumb_exists,
431                                                  wd);
432 }
433
434 static Eina_Bool
435 _thumb_apply_cb(void *data, int type __UNUSED__, void *ev __UNUSED__)
436 {
437    _thumb_apply(data);
438    return ECORE_CALLBACK_RENEW;
439 }
440
441 static void
442 _thumb_show(Widget_Data *wd)
443 {
444    evas_object_show(wd->frame);
445
446    if (elm_thumb_ethumb_client_connected())
447      {
448         _thumb_apply(wd);
449         return;
450      }
451
452    if (!wd->eeh)
453      wd->eeh = ecore_event_handler_add(ELM_ECORE_EVENT_ETHUMB_CONNECT,
454                                        _thumb_apply_cb, wd);
455 }
456
457 static void
458 _thumb_show_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
459 {
460    _thumb_show(data);
461 }
462
463 static void
464 _thumb_hide_cb(void *data, Evas *e __UNUSED__, Evas_Object *obj __UNUSED__, void *event_info __UNUSED__)
465 {
466    Widget_Data *wd = data;
467
468    evas_object_hide(wd->frame);
469
470    if (wd->thumb.id >= 0)
471      {
472         ethumb_client_generate_cancel
473            (_elm_ethumb_client, wd->thumb.id, NULL, NULL, NULL);
474         wd->thumb.id = -1;
475
476         edje_object_signal_emit(wd->frame, EDJE_SIGNAL_GENERATE_STOP, "elm");
477         evas_object_smart_callback_call(wd->self, SIG_GENERATE_STOP, NULL);
478      }
479
480    if (wd->thumb.exists)
481      {
482         ethumb_client_thumb_exists_cancel(wd->thumb.exists);
483         wd->thumb.exists = NULL;
484      }
485
486    if (wd->thumb.retry)
487      {
488         retry = eina_list_remove(retry, wd);
489         wd->thumb.retry = EINA_FALSE;
490      }
491
492    if (wd->eeh)
493      {
494         ecore_event_handler_del(wd->eeh);
495         wd->eeh = NULL;
496      }
497 }
498
499 #endif
500
501 #ifdef ELM_ETHUMB
502 static int _elm_need_ethumb = 0;
503
504 static void _on_die_cb(void *, Ethumb_Client *);
505
506 static void
507 _connect_cb(void *data __UNUSED__, Ethumb_Client *c, Eina_Bool success)
508 {
509    if (success)
510      {
511         ethumb_client_on_server_die_callback_set(c, _on_die_cb, NULL, NULL);
512         _elm_ethumb_connected = EINA_TRUE;
513         ecore_event_add(ELM_ECORE_EVENT_ETHUMB_CONNECT, NULL, NULL, NULL);
514      }
515    else
516      _elm_ethumb_client = NULL;
517 }
518
519 static void
520 _on_die_cb(void *data __UNUSED__, Ethumb_Client *c __UNUSED__)
521 {
522    ethumb_client_disconnect(_elm_ethumb_client);
523    _elm_ethumb_client = NULL;
524    _elm_ethumb_connected = EINA_FALSE;
525    _elm_ethumb_client = ethumb_client_connect(_connect_cb, NULL, NULL);
526 }
527 #endif
528
529 void
530 _elm_unneed_ethumb(void)
531 {
532 #ifdef ELM_ETHUMB
533    if (--_elm_need_ethumb) return;
534
535    ethumb_client_disconnect(_elm_ethumb_client);
536    _elm_ethumb_client = NULL;
537    ethumb_client_shutdown();
538    ELM_ECORE_EVENT_ETHUMB_CONNECT = 0;
539 #endif
540 }
541
542 static Eina_Bool
543 _elm_thumb_dropcb(void *data __UNUSED__, Evas_Object *o, Elm_Selection_Data *drop)
544 {
545    if ((!o) || (!drop) || (!drop->data)) return EINA_FALSE;
546    elm_thumb_file_set(o, drop->data, NULL);
547    return EINA_TRUE;
548 }
549
550 /**
551  * This must be called before any other function that handle with
552  * elm_thumb objects or ethumb_client instances.
553  *
554  * @ingroup Thumb
555  */
556 EAPI Eina_Bool
557 elm_need_ethumb(void)
558 {
559 #ifdef ELM_ETHUMB
560    if (_elm_need_ethumb++) return EINA_TRUE;
561    ELM_ECORE_EVENT_ETHUMB_CONNECT = ecore_event_type_new();
562    ethumb_client_init();
563    _elm_ethumb_client = ethumb_client_connect(_connect_cb, NULL, NULL);
564    return EINA_TRUE;
565 #else
566    return EINA_FALSE;
567 #endif
568 }
569
570 /**
571  * Add a new thumb object to the parent.
572  *
573  * @param parent The parent object.
574  * @return The new object or NULL if it cannot be created.
575  *
576  * @see elm_thumb_file_set()
577  * @see elm_thumb_ethumb_client_get()
578  *
579  * @ingroup Thumb
580  */
581 EAPI Evas_Object *
582 elm_thumb_add(Evas_Object *parent)
583 {
584    Evas *e;
585    Widget_Data *wd;
586    Evas_Object *obj;
587    Evas_Coord minw, minh;
588
589    ELM_WIDGET_STANDARD_SETUP(wd, Widget_Data, parent, e, obj, NULL);
590
591    ELM_SET_WIDTYPE(widtype, "thumb");
592    elm_widget_type_set(obj, "thumb");
593    elm_widget_sub_object_add(parent, obj);
594    elm_widget_data_set(obj, wd);
595    elm_widget_del_hook_set(obj, _del_hook);
596    elm_widget_theme_hook_set(obj, _theme_hook);
597    elm_widget_can_focus_set(obj, EINA_FALSE);
598
599    wd->frame = edje_object_add(e);
600    _elm_theme_object_set(obj, wd->frame, "thumb", "base", "default");
601    elm_widget_resize_object_set(obj, wd->frame);
602
603    edje_object_size_min_calc(obj, &minw, &minh);
604    evas_object_size_hint_min_set(obj, minw, minh);
605
606    wd->self = obj;
607    wd->view = NULL;
608    wd->file = NULL;
609    wd->key = NULL;
610    wd->eeh = NULL;
611    wd->thumb.id = -1;
612    wd->on_hold = EINA_FALSE;
613    wd->is_video = EINA_FALSE;
614    wd->was_video = EINA_FALSE;
615
616 #ifdef HAVE_ELEMENTARY_ETHUMB
617    wd->thumb.thumb_path = NULL;
618    wd->thumb.thumb_key = NULL;
619    wd->thumb.exists = NULL;
620    evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_DOWN,
621                                   _mouse_down_cb, wd);
622    evas_object_event_callback_add(obj, EVAS_CALLBACK_MOUSE_UP,
623                                   _mouse_up_cb, wd);
624    evas_object_event_callback_add(obj, EVAS_CALLBACK_SHOW,
625                                   _thumb_show_cb, wd);
626    evas_object_event_callback_add(obj, EVAS_CALLBACK_HIDE,
627                                   _thumb_hide_cb, wd);
628 #endif
629
630    // TODO: convert Elementary to subclassing of Evas_Smart_Class
631    // TODO: and save some bytes, making descriptions per-class and not instance!
632    evas_object_smart_callbacks_descriptions_set(obj, _signals);
633    return obj;
634 }
635
636 /**
637  * Reload thumbnail if it was generated before.
638  *
639  * This is useful if the ethumb client configuration changed, like its
640  * size, aspect or any other property one set in the handle returned
641  * by elm_thumb_ethumb_client_get().
642  *
643  * @param obj The thumb object to reload
644  *
645  * @see elm_thumb_file_set()
646  *
647  * @ingroup Thumb
648  */
649 EAPI void
650 elm_thumb_reload(Evas_Object *obj)
651 {
652    ELM_CHECK_WIDTYPE(obj, widtype);
653    Widget_Data *wd = elm_widget_data_get(obj);
654
655    eina_stringshare_replace(&(wd->thumb.file), NULL);
656    eina_stringshare_replace(&(wd->thumb.key), NULL);
657
658 #ifdef HAVE_ELEMENTARY_ETHUMB
659    if (evas_object_visible_get(obj))
660      _thumb_show(wd);
661 #endif
662 }
663
664 /**
665  * Set the file that will be used as thumbnail.
666  *
667  * The file can be an image or a video (in that case, acceptable extensions are:
668  * avi, mp4, ogv, mov, mpg and wmv). To start the video animation, use the
669  * function elm_thumb_animate().
670  *
671  * @param obj The thumb object.
672  * @param file The path to file that will be used as thumb.
673  * @param key The key used in case of an EET file.
674  *
675  * @see elm_thumb_file_get()
676  * @see elm_thumb_reload()
677  * @see elm_thumb_animate()
678  *
679  * @ingroup Thumb
680  */
681 EAPI void
682 elm_thumb_file_set(Evas_Object *obj, const char *file, const char *key)
683 {
684    ELM_CHECK_WIDTYPE(obj, widtype);
685    Eina_Bool file_replaced, key_replaced;
686    Widget_Data *wd = elm_widget_data_get(obj);
687
688    file_replaced = eina_stringshare_replace(&(wd->file), file);
689    key_replaced = eina_stringshare_replace(&(wd->key), key);
690
691    if (file_replaced)
692      {
693         int prefix_size;
694         const char **ext, *ptr;
695         static const char *extensions[] =
696           {
697              ".avi", ".mp4", ".ogv", ".mov", ".mpg", ".wmv", NULL
698           };
699
700         prefix_size = eina_stringshare_strlen(wd->file) - 4;
701         if (prefix_size >= 0)
702           {
703              ptr = wd->file + prefix_size;
704              wd->is_video = EINA_FALSE;
705              for (ext = extensions; *ext; ext++)
706                if (!strcasecmp(ptr, *ext))
707                  {
708                     wd->is_video = EINA_TRUE;
709                     break;
710                  }
711           }
712      }
713
714    eina_stringshare_replace(&(wd->thumb.file), NULL);
715    eina_stringshare_replace(&(wd->thumb.key), NULL);
716
717 #ifdef HAVE_ELEMENTARY_ETHUMB
718    if (((file_replaced) || (key_replaced)) && (evas_object_visible_get(obj)))
719      _thumb_show(wd);
720 #endif
721 }
722
723 /**
724  * Get the image or video path and key used to generate the thumbnail.
725  *
726  * @param obj The thumb object.
727  * @param file Pointer to filename.
728  * @param key Pointer to key.
729  *
730  * @see elm_thumb_file_set()
731  * @see elm_thumb_path_get()
732  * @see elm_thumb_animate()
733  *
734  * @ingroup Thumb
735  */
736 EAPI void
737 elm_thumb_file_get(const Evas_Object *obj, const char **file, const char **key)
738 {
739    ELM_CHECK_WIDTYPE(obj, widtype);
740    Widget_Data *wd = elm_widget_data_get(obj);
741
742    if (file)
743      *file = wd->file;
744    if (key)
745      *key = wd->key;
746 }
747
748 /**
749  * Get the path and key to the image or video generated by ethumb.
750  *
751  * One just need to make sure that the thumbnail was generated before getting
752  * its path; otherwise, the path will be NULL. One way to do that is by asking
753  * for the path when/after the "generate,stop" smart callback is called.
754  *
755  * @param obj The thumb object.
756  * @param file Pointer to thumb path.
757  * @param key Pointer to thumb key.
758  *
759  * @see elm_thumb_file_get()
760  *
761  * @ingroup Thumb
762  */
763 EAPI void
764 elm_thumb_path_get(const Evas_Object *obj, const char **file, const char **key)
765 {
766    ELM_CHECK_WIDTYPE(obj, widtype);
767    Widget_Data *wd = elm_widget_data_get(obj);
768
769    if (file)
770      *file = wd->thumb.file;
771    if (key)
772      *key = wd->thumb.key;
773 }
774
775 /**
776  * Set the animation state for the thumb object. If its content is an animated
777  * video, you may start/stop the animation or tell it to play continuously and
778  * looping.
779  *
780  * @param obj The thumb object.
781  * @param setting The animation setting.
782  *
783  * @see elm_thumb_file_set()
784  *
785  * @ingroup Thumb
786  */
787 EAPI void
788 elm_thumb_animate_set(Evas_Object *obj, Elm_Thumb_Animation_Setting setting)
789 {
790    ELM_CHECK_WIDTYPE(obj, widtype);
791    Widget_Data *wd = elm_widget_data_get(obj);
792
793    EINA_SAFETY_ON_TRUE_RETURN(setting >= ELM_THUMB_ANIMATION_LAST);
794
795    wd->anim_setting = setting;
796    if (setting == ELM_THUMB_ANIMATION_LOOP)
797      edje_object_signal_emit(wd->view, "animate_loop", "");
798    else if (setting == ELM_THUMB_ANIMATION_START)
799      edje_object_signal_emit(wd->view, "animate", "");
800    else if (setting == ELM_THUMB_ANIMATION_STOP)
801      edje_object_signal_emit(wd->view, "animate_stop", "");
802 }
803
804 /**
805  * Get the animation state for the thumb object.
806  *
807  * @param obj The thumb object.
808  * @return getting The animation setting or @c ELM_THUMB_ANIMATION_LAST,
809  * on errors.
810  *
811  * @see elm_thumb_file_get()
812  *
813  * @ingroup Thumb
814  */
815 EAPI Elm_Thumb_Animation_Setting
816 elm_thumb_animate_get(const Evas_Object *obj)
817 {
818    ELM_CHECK_WIDTYPE(obj, widtype) ELM_THUMB_ANIMATION_LAST;
819    Widget_Data *wd = elm_widget_data_get(obj);
820
821    return wd->anim_setting;
822 }
823
824 /**
825  * Get the ethumb_client handle so custom configuration can be made.
826  * This must be called before the objects are created to be sure no object is
827  * visible and no generation started.
828  *
829  * @return Ethumb_Client instance or NULL.
830  *
831  * Example of usage:
832  *
833  * @code
834  * #include <Elementary.h>
835  * #ifndef ELM_LIB_QUICKLAUNCH
836  * EAPI int
837  * elm_main(int argc, char **argv)
838  * {
839  *    Ethumb_Client *client;
840  *
841  *    elm_need_ethumb();
842  *
843  *    // ... your code
844  *
845  *    client = elm_thumb_ethumb_client_get();
846  *    if (!client)
847  *      {
848  *         ERR("could not get ethumb_client");
849  *         return 1;
850  *      }
851  *    ethumb_client_size_set(client, 100, 100);
852  *    ethumb_client_crop_align_set(client, 0.5, 0.5);
853  *    // ... your code
854  *
855  *    // Create elm_thumb objects here
856  *
857  *    elm_run();
858  *    elm_shutdown();
859  *    return 0;
860  * }
861  * #endif
862  * ELM_MAIN()
863  * @endcode
864  *
865  * @ingroup Thumb
866  */
867 EAPI void *
868 elm_thumb_ethumb_client_get(void)
869 {
870    return _elm_ethumb_client;
871 }
872
873 /**
874  * Get the ethumb_client connection state.
875  *
876  * @return EINA_TRUE if the client is connected to the server or
877  *         EINA_FALSE otherwise.
878  */
879 EAPI Eina_Bool
880 elm_thumb_ethumb_client_connected(void)
881 {
882    return _elm_ethumb_connected;
883 }
884
885 EAPI Eina_Bool
886 elm_thumb_editable_set(Evas_Object *obj, Eina_Bool edit)
887 {
888    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
889    Widget_Data *wd = elm_widget_data_get(obj);
890
891    if (!wd) return EINA_FALSE;
892    edit = !!edit;
893    if (wd->edit == edit) return EINA_TRUE;
894
895    wd->edit = edit;
896    if (wd->edit)
897      elm_drop_target_add(obj, ELM_SEL_FORMAT_IMAGE,
898                          _elm_thumb_dropcb, obj);
899    else
900      elm_drop_target_del(obj);
901
902    return EINA_TRUE;
903 }
904
905 EAPI Eina_Bool
906 elm_thumb_editable_get(const Evas_Object *obj)
907 {
908    ELM_CHECK_WIDTYPE(obj, widtype) EINA_FALSE;
909    Widget_Data *wd = elm_widget_data_get(obj);
910
911    if (!wd) return EINA_FALSE;
912    return wd->edit;
913 }
914
915 /* vim:set ts=8 sw=3 sts=3 expandtab cino=>5n-2f0^-2{2(0W1st0 :*/