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