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