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