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