logging: remove trailing \n
[framework/uifw/ethumb.git] / src / lib / client / Ethumb_Client.c
1 /**
2  * @file
3  *
4  * This is the client-server thumbnail library, see @ref
5  * tutorial_ethumb_client.
6  *
7  * Copyright (C) 2009 by ProFUSION embedded systems
8  *
9  * This program is free software; you can redistribute it and/or modify it
10  * under the terms of the GNU Lesser General Public License as published by
11  * the Free Software Foundation; either version 3 of the License, or (at your
12  * option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,  but
15  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16  * or FITNESS FOR A PARTICULAR PURPOSE.  See the  GNU General Public License
17  * for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public License
20  * along with this program; if not, write to the Free Software Foundation,
21  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
22  * USA.
23  *
24  * @author Rafael Antognolli <antognolli@profusion.mobi>
25  * @author Gustavo Sverzut Barbieri <barbieri@profusion.mobi>
26  */
27
28 /**
29  * @page tutorial_ethumb_client Client-Server Thumbnailing Tutorial
30  *
31  * @section tutorial_ethumb_client_intro Introduction
32  *
33  * Ethumb provides both in process and client-server generation
34  * methods. The advantage of the client-server method is that current
35  * process will not do the heavy operations that may block, stopping
36  * animations and other user interactions. Instead the client library
37  * will configure a local #Ethumb instance and mirrors/controls a
38  * remote process using DBus. The simple operations like most setters
39  * and getters as well as checking for thumbnail existence
40  * (ethumb_client_thumb_exists()) is done locally, while expensive
41  * (ethumb_client_generate()) are done on server and then reported
42  * back to application when it is finished (both success or failure).
43  *
44  * @section tutorial_ethumb_client_connect Connecting to Server
45  *
46  * TODO
47  *
48  * @section tutorial_ethumb_client_generate Requesting Thumbnail Generation
49  *
50  * TODO
51  *
52  * @section tutorial_ethumb_client_setup Setup Extra Thumbnail Parameters
53  *
54  * TODO
55  *
56  * @section tutorial_ethumb_client_server_died Handle Server Disconnection
57  *
58  * TODO
59  */
60
61 /**
62  * @cond LOCAL
63  */
64
65 #ifdef HAVE_CONFIG_H
66 #include "config.h"
67 #endif
68 #include <Eina.h>
69 #include <eina_safety_checks.h>
70 #include <Ethumb.h>
71 #include "Ethumb_Client.h"
72 #include <stdio.h>
73 #include <stdlib.h>
74 #include <limits.h>
75 #include <string.h>
76 #include <unistd.h>
77 #include <errno.h>
78 #include <sys/types.h>
79 #include <stdbool.h>
80
81 #ifndef PATH_MAX
82 #define PATH_MAX 4096
83 #endif
84
85 #include <E_DBus.h>
86
87 #define MAX_ID 2000000
88
89 static int _log_dom = -1;
90 #define DBG(...) EINA_LOG_DOM_DBG(_log_dom, __VA_ARGS__)
91 #define INF(...) EINA_LOG_DOM_INFO(_log_dom, __VA_ARGS__)
92 #define WRN(...) EINA_LOG_DOM_WARN(_log_dom, __VA_ARGS__)
93 #define ERR(...) EINA_LOG_DOM_ERR(_log_dom, __VA_ARGS__)
94 #define CRITICAL(...) EINA_LOG_DOM_CRIT(_log_dom, __VA_ARGS__)
95
96 struct _Ethumb_Client
97 {
98    Ethumb *ethumb;
99    int id_count;
100
101    E_DBus_Connection *conn;
102    E_DBus_Signal_Handler *name_owner_changed_handler;
103    E_DBus_Signal_Handler *generated_signal;
104    DBusPendingCall *pending_get_name_owner;
105    DBusPendingCall *pending_start_service_by_name;
106    const char *unique_name;
107    DBusPendingCall *pending_new;
108    struct {
109       Ethumb_Client_Connect_Cb cb;
110       void *data;
111       Eina_Free_Cb free_data;
112    } connect;
113    Eina_List *pending_add;
114    Eina_List *pending_remove;
115    Eina_List *pending_gen;
116    DBusPendingCall *pending_clear;
117    DBusPendingCall *pending_setup;
118    struct {
119       Ethumb_Client_Die_Cb cb;
120       void *data;
121       Eina_Free_Cb free_data;
122    } die;
123    const char *object_path;
124
125    Eina_Bool ethumb_dirty : 1;
126    Eina_Bool connected : 1;
127    Eina_Bool server_started : 1;
128 };
129
130 struct _ethumb_pending_add
131 {
132    dbus_int32_t id;
133    const char *file;
134    const char *key;
135    const char *thumb;
136    const char *thumb_key;
137    Ethumb_Client_Generate_Cb generated_cb;
138    void *data;
139    Eina_Free_Cb free_data;
140    DBusPendingCall *pending_call;
141    Ethumb_Client *client;
142 };
143
144 struct _ethumb_pending_remove
145 {
146    dbus_int32_t id;
147    Ethumb_Client_Generate_Cancel_Cb cancel_cb;
148    void *data;
149    Eina_Free_Cb free_data;
150    DBusPendingCall *pending_call;
151    Ethumb_Client *client;
152 };
153
154 struct _ethumb_pending_gen
155 {
156    dbus_int32_t id;
157    const char *file;
158    const char *key;
159    const char *thumb;
160    const char *thumb_key;
161    Ethumb_Client_Generate_Cb generated_cb;
162    void *data;
163    Eina_Free_Cb free_data;
164 };
165
166 static const char _ethumb_dbus_bus_name[] = "org.enlightenment.Ethumb";
167 static const char _ethumb_dbus_interface[] = "org.enlightenment.Ethumb";
168 static const char _ethumb_dbus_objects_interface[] = "org.enlightenment.Ethumb.objects";
169 static const char _ethumb_dbus_path[] = "/org/enlightenment/Ethumb";
170 static const char fdo_interface[] = "org.freedesktop.DBus";
171 static const char fdo_bus_name[] = "org.freedesktop.DBus";
172 static const char fdo_path[] = "/org/freedesktop/DBus";
173
174 static int _initcount = 0;
175
176 static void _ethumb_client_generated_cb(void *data, DBusMessage *msg);
177 static void _ethumb_client_get_name_owner(void *data, DBusMessage *msg, DBusError *err);
178
179 static inline bool
180 __dbus_callback_check_and_init(const char *file, int line, const char *function, DBusMessage *msg, DBusMessageIter *itr, DBusError *err)
181 {
182    if (!msg)
183      {
184         ERR("%s:%d:%s() callback without message arguments!",
185                 file, line, function);
186
187         if (err)
188           ERR("%s:%d:%s() an error was reported by server: "
189                   "name=\"%s\", message=\"%s\"",
190                   file, line, function, err->name, err->message);
191
192         return 0;
193      }
194
195    if (!dbus_message_iter_init(msg, itr))
196      {
197         ERR("%s:%d:%s() could not init iterator.",
198                 file, line, function);
199         return 0;
200      }
201
202    return 1;
203 }
204
205 #define _dbus_callback_check_and_init(msg, itr, err)                    \
206   __dbus_callback_check_and_init(__FILE__, __LINE__, __FUNCTION__,      \
207                                  msg, itr, err)
208
209 static inline bool
210 __dbus_iter_type_check(int type, int expected, const char *expected_name)
211 {
212    if (type == expected)
213      return 1;
214
215    ERR("expected type %s (%c) but got %c instead!",
216            expected_name, expected, type);
217
218    return 0;
219 }
220 #define _dbus_iter_type_check(t, e) __dbus_iter_type_check(t, e, #e)
221
222 #define CHECK_NULL_RETURN(ptr, ...)                                     \
223   do                                                                    \
224     {                                                                   \
225        if ((ptr) == NULL)                                               \
226          {                                                              \
227             CRITICAL("%s == NULL!", #ptr);                              \
228             return __VA_ARGS__;                                         \
229          }                                                              \
230     }                                                                   \
231   while (0)
232
233 static void
234 _ethumb_client_name_owner_changed(void *data, DBusMessage *msg)
235 {
236    DBusError err;
237    const char *name, *from, *to;
238    Ethumb_Client *client = data;
239
240    dbus_error_init(&err);
241    if (!dbus_message_get_args(msg, &err,
242        DBUS_TYPE_STRING, &name,
243        DBUS_TYPE_STRING, &from,
244        DBUS_TYPE_STRING, &to,
245        DBUS_TYPE_INVALID))
246      {
247         ERR("could not get NameOwnerChanged arguments: %s: %s",
248             err.name, err.message);
249         dbus_error_free(&err);
250         return;
251      }
252
253    if (strcmp(name, _ethumb_dbus_bus_name) != 0)
254      return;
255
256    DBG("NameOwnerChanged from=[%s] to=[%s]", from, to);
257
258    if (from[0] != '\0' && to[0] == '\0')
259      {
260         DBG("exit ethumbd at %s", from);
261         if (strcmp(client->unique_name, from) != 0)
262           WRN("%s was not the known name %s, ignored.",
263                from, client->unique_name);
264         else
265           {
266              ERR("server exit!!!");
267              if (client->die.cb)
268                {
269                   client->die.cb(client->die.data, client);
270                   client->die.cb = NULL;
271                }
272              if (client->die.free_data)
273                {
274                   client->die.free_data(client->die.data);
275                   client->die.free_data = NULL;
276                   client->die.data = NULL;
277                }
278           }
279      }
280    else
281      DBG("unknown change from %s to %s", from, to);
282 }
283
284 static void
285 _ethumb_client_report_connect(Ethumb_Client *client, Eina_Bool success)
286 {
287    if (!client->connect.cb)
288      {
289         ERR("already called?!");
290         return;
291      }
292
293    client->connect.cb(client->connect.data, client, success);
294    if (client->connect.free_data)
295      {
296         client->connect.free_data(client->connect.data);
297         client->connect.free_data = NULL;
298      }
299    client->connect.cb = NULL;
300    client->connect.data = NULL;
301 }
302
303 static void
304 _ethumb_client_new_cb(void *data, DBusMessage *msg, DBusError *error)
305 {
306    DBusMessageIter iter;
307    const char *opath;
308    int t;
309    Ethumb_Client *client = data;
310
311    client->pending_new = NULL;
312
313    if (!_dbus_callback_check_and_init(msg, &iter, error))
314      goto end_error;
315    t = dbus_message_iter_get_arg_type(&iter);
316    if (!_dbus_iter_type_check(t, DBUS_TYPE_OBJECT_PATH))
317      goto end_error;
318
319    dbus_message_iter_get_basic(&iter, &opath);
320    if (opath[0] == '\0')
321      goto end_error;
322
323    client->object_path = eina_stringshare_add(opath);
324
325    client->generated_signal = e_dbus_signal_handler_add(
326       client->conn, _ethumb_dbus_bus_name, opath,
327       _ethumb_dbus_objects_interface, "generated",
328       _ethumb_client_generated_cb, client);
329
330    _ethumb_client_report_connect(client, 1);
331    return;
332
333 end_error:
334    _ethumb_client_report_connect(client, 0);
335 }
336
337 static void
338 _ethumb_client_call_new(Ethumb_Client *client)
339 {
340    DBusMessage *msg;
341
342    msg = dbus_message_new_method_call(_ethumb_dbus_bus_name, _ethumb_dbus_path,
343                                       _ethumb_dbus_interface, "new");
344    client->pending_new = e_dbus_message_send(client->conn, msg,
345                                              _ethumb_client_new_cb, -1,
346                                              client);
347    dbus_message_unref(msg);
348 }
349
350 static void
351 _ethumb_client_start_server_cb(void *data, DBusMessage *msg, DBusError *err)
352 {
353    Ethumb_Client *client = data;
354    DBusMessageIter iter;
355    dbus_uint32_t ret;
356    int t;
357
358    client->pending_start_service_by_name = NULL;
359
360    if (!_dbus_callback_check_and_init(msg, &iter, err))
361      goto error;
362
363    t = dbus_message_iter_get_arg_type(&iter);
364    if (!_dbus_iter_type_check(t, DBUS_TYPE_UINT32))
365      goto error;
366
367    dbus_message_iter_get_basic(&iter, &ret);
368    if ((ret != 1) && (ret != 2))
369      {
370         ERR("Error starting Ethumbd DBus service by its name: retcode %u",
371             ret);
372         goto error;
373      }
374
375    client->server_started = 1;
376    DBG("Ethumbd DBus service started successfully (%d), now request its name",
377        ret);
378
379    if (client->pending_get_name_owner)
380      {
381         DBG("already requesting name owner, cancel and try again");
382         dbus_pending_call_cancel(client->pending_get_name_owner);
383      }
384
385    client->pending_get_name_owner = e_dbus_get_name_owner
386      (client->conn, _ethumb_dbus_bus_name, _ethumb_client_get_name_owner,
387       client);
388    if (!client->pending_get_name_owner)
389      {
390         ERR("could not create a get_name_owner request.");
391         goto error;
392      }
393
394    return;
395
396  error:
397    ERR("failed to start Ethumbd DBus service by its name.");
398    _ethumb_client_report_connect(client, 0);
399 }
400
401 static void
402 _ethumb_client_start_server(Ethumb_Client *client)
403 {
404    if (client->pending_start_service_by_name)
405      {
406         DBG("already pending start service by name.");
407         return;
408      }
409
410    client->server_started = 0;
411    client->pending_start_service_by_name = e_dbus_start_service_by_name
412      (client->conn, _ethumb_dbus_bus_name, 0, _ethumb_client_start_server_cb,
413       client);
414    if (!client->pending_start_service_by_name)
415      {
416         ERR("could not start service by name!");
417         _ethumb_client_report_connect(client, 0);
418      }
419 }
420
421 static void
422 _ethumb_client_get_name_owner(void *data, DBusMessage *msg, DBusError *err)
423 {
424    DBusMessageIter iter;
425    const char *uid;
426    Ethumb_Client *client = data;
427    int t;
428
429    client->pending_get_name_owner = NULL;
430
431    if (dbus_error_is_set(err) && (!client->server_started))
432      {
433         DBG("could not find server (%s), try to start it...", err->message);
434         _ethumb_client_start_server(client);
435         return;
436      }
437
438    if (!_dbus_callback_check_and_init(msg, &iter, err))
439      goto error;
440
441    t = dbus_message_iter_get_arg_type(&iter);
442    if (!_dbus_iter_type_check(t, DBUS_TYPE_STRING))
443      goto error;
444
445    dbus_message_iter_get_basic(&iter, &uid);
446    if (!uid)
447      {
448         ERR("no name owner!");
449         goto error;
450      }
451
452    DBG("unique name = %s", uid);
453    client->unique_name = eina_stringshare_add(uid);
454
455    _ethumb_client_call_new(client);
456    client->connected = 1;
457    return;
458
459 error:
460    _ethumb_client_report_connect(client, 0);
461 }
462
463 /**
464  * @endcond
465  */
466
467 /**
468  * @brief Initialize the Ethumb_Client library.
469  *
470  * @return 1 or greater on success, 0 on error.
471  *
472  * This function sets up all the Ethumb_Client module dependencies. It
473  * returns 0 on failure (that is, when one of the dependency fails to
474  * initialize), otherwise it returns the number of times it has
475  * already been called.
476  *
477  * When Ethumb_Client is not used anymore, call
478  * ethumb_client_shutdown() to shut down the Ethumb_Client library.
479  *
480  * @see ethumb_client_shutdown()
481  * @see ethumb_client_connect()
482  * @see @ref tutorial_ethumb_client
483  */
484 EAPI int
485 ethumb_client_init(void)
486 {
487    if (_initcount)
488      return ++_initcount;
489
490    if (!eina_init())
491      {
492         fprintf(stderr, "ERROR: Could not initialize log module.\n");
493         return 0;
494      }
495    _log_dom = eina_log_domain_register("ethumb_client", EINA_COLOR_YELLOW);
496    if (_log_dom < 0)
497      {
498         EINA_LOG_ERR("Could not register log domain: ethumb_client");
499         eina_shutdown();
500         return 0;
501      }
502
503    ethumb_init();
504    e_dbus_init();
505
506    return ++_initcount;
507 }
508
509 /**
510  * @brief Shut down the Ethumb_Client library.
511  *
512  * @return 0 when everything is shut down, 1 or greater if there are
513  *         other users of the Ethumb_Client library pending shutdown.
514  *
515  * This function shuts down the Ethumb_Client library. It returns 0
516  * when it has been called the same number of times than
517  * ethumb_client_init(). In that case it shut down all the
518  * Ethumb_Client modules dependencies.
519  *
520  * Once this function succeeds (that is, @c 0 is returned), you must
521  * not call any of the Eina function anymore. You must call
522  * ethumb_client_init() again to use the Ethumb_Client functions
523  * again.
524  */
525 EAPI int
526 ethumb_client_shutdown(void)
527 {
528    _initcount--;
529    if (_initcount > 0)
530      return _initcount;
531
532    e_dbus_shutdown();
533    ethumb_shutdown();
534    eina_log_domain_unregister(_log_dom);
535    _log_dom = -1;
536    eina_shutdown();
537    return _initcount;
538 }
539
540 /**
541  * Connects to Ethumb server and return the client instance.
542  *
543  * This is the "constructor" of Ethumb_Client, where everything
544  * starts.
545  *
546  * If server was down, it is tried to start it using DBus activation,
547  * then the connection is retried.
548  *
549  * This call is asynchronous and will not block, instead it will be in
550  * "not connected" state until @a connect_cb is called with either
551  * success or failure. On failure, then no methods should be
552  * called. On success you're now able to setup and then ask generation
553  * of thumbnails.
554  *
555  * Usually you should listen for server death/disconenction with
556  * ethumb_client_on_server_die_callback_set().
557  *
558  * @param connect_cb function to call to report connection success or
559  *        failure. Do not call any other ethumb_client method until
560  *        this function returns. The first received parameter is the
561  *        given argument @a data. Must @b not be @c NULL. This
562  *        function will not be called if user explicitly calls
563  *        ethumb_client_disconnect().
564  * @param data context to give back to @a connect_cb. May be @c NULL.
565  * @param free_data function used to release @a data resources, if
566  *        any. May be @c NULL. If this function exists, it will be
567  *        called immediately after @a connect_cb is called or if user
568  *        explicitly calls ethumb_client_disconnect() before such
569  *        (that is, don't rely on @a data after @a connect_cb was
570  *        called!)
571  *
572  * @return client instance or NULL if failed. If @a connect_cb is
573  *         missing it returns @c NULL. If it fail for other
574  *         conditions, @c NULL is also returned and @a connect_cb is
575  *         called with @c success=EINA_FALSE. The client instance is
576  *         not ready to be used until @a connect_cb is called.
577  */
578 EAPI Ethumb_Client *
579 ethumb_client_connect(Ethumb_Client_Connect_Cb connect_cb, const void *data, Eina_Free_Cb free_data)
580 {
581    Ethumb_Client *eclient;
582
583    EINA_SAFETY_ON_NULL_RETURN_VAL(connect_cb, NULL);
584
585    eclient = calloc(1, sizeof(*eclient));
586    if (!eclient)
587      {
588         ERR("could not allocate Ethumb_Client structure.");
589         goto err;
590      }
591
592    eclient->connect.cb = connect_cb;
593    eclient->connect.data = (void *)data;
594    eclient->connect.free_data = free_data;
595
596    eclient->ethumb = ethumb_new();
597    if (!eclient->ethumb)
598      {
599         ERR("could not create ethumb handler.");
600         goto ethumb_new_err;
601      }
602
603    eclient->conn = e_dbus_bus_get(DBUS_BUS_SESSION);
604    if (!eclient->conn)
605      {
606         ERR("could not connect to session bus.");
607         goto connection_err;
608      }
609
610    eclient->name_owner_changed_handler = e_dbus_signal_handler_add(
611          eclient->conn, fdo_bus_name, fdo_path, fdo_interface,
612          "NameOwnerChanged", _ethumb_client_name_owner_changed, eclient);
613
614    eclient->pending_get_name_owner = e_dbus_get_name_owner(
615          eclient->conn, _ethumb_dbus_bus_name, _ethumb_client_get_name_owner,
616          eclient);
617    if (!eclient->pending_get_name_owner)
618      {
619         ERR("could not create a get_name_owner request.");
620         goto connection_err;
621      }
622
623    return eclient;
624
625 connection_err:
626    ethumb_free(eclient->ethumb);
627 ethumb_new_err:
628    free(eclient);
629 err:
630    connect_cb((void *)data, NULL, EINA_FALSE);
631    if (free_data)
632      free_data((void *)data);
633    return NULL;
634 }
635
636 /**
637  * Disconnect the client, releasing all client resources.
638  *
639  * This is the destructor of Ethumb_Client, after it's disconnected
640  * the client handle is now gone and should not be used.
641  *
642  * @param client client instance to be destroyed. Must @b not be @c
643  *        NULL.
644  */
645 EAPI void
646 ethumb_client_disconnect(Ethumb_Client *client)
647 {
648    void *data;
649
650    EINA_SAFETY_ON_NULL_RETURN(client);
651
652    if (!client->connected)
653      goto end_connection;
654
655    EINA_LIST_FREE(client->pending_add, data)
656      {
657         struct _ethumb_pending_add *pending = data;
658         eina_stringshare_del(pending->file);
659         eina_stringshare_del(pending->key);
660         eina_stringshare_del(pending->thumb);
661         eina_stringshare_del(pending->thumb_key);
662         dbus_pending_call_cancel(pending->pending_call);
663         dbus_pending_call_unref(pending->pending_call);
664         if (pending->free_data)
665           pending->free_data(pending->data);
666         free(pending);
667      }
668
669    EINA_LIST_FREE(client->pending_gen, data)
670      {
671         struct _ethumb_pending_gen *pending = data;
672         eina_stringshare_del(pending->file);
673         eina_stringshare_del(pending->key);
674         eina_stringshare_del(pending->thumb);
675         eina_stringshare_del(pending->thumb_key);
676         if (pending->free_data)
677           pending->free_data(pending->data);
678         free(pending);
679      }
680
681    EINA_LIST_FREE(client->pending_remove, data)
682      {
683         struct _ethumb_pending_remove *pending = data;
684         dbus_pending_call_cancel(pending->pending_call);
685         dbus_pending_call_unref(pending->pending_call);
686         if (pending->free_data)
687           pending->free_data(pending->data);
688         free(pending);
689      }
690
691    if (client->pending_clear)
692      {
693         dbus_pending_call_cancel(client->pending_clear);
694         dbus_pending_call_unref(client->pending_clear);
695      }
696
697 end_connection:
698    if (client->object_path)
699      eina_stringshare_del(client->object_path);
700
701    if (client->pending_new)
702      dbus_pending_call_cancel(client->pending_new);
703
704    if (client->unique_name)
705      eina_stringshare_del(client->unique_name);
706
707    if (client->pending_get_name_owner)
708      dbus_pending_call_cancel(client->pending_get_name_owner);
709
710    if (client->pending_start_service_by_name)
711      dbus_pending_call_cancel(client->pending_start_service_by_name);
712
713    ethumb_free(client->ethumb);
714
715    e_dbus_signal_handler_del(client->conn, client->name_owner_changed_handler);
716    if (client->connected)
717      e_dbus_signal_handler_del(client->conn, client->generated_signal);
718    e_dbus_connection_close(client->conn);
719
720    if (client->connect.free_data)
721      client->connect.free_data(client->connect.data);
722    if (client->die.free_data)
723      client->die.free_data(client->die.data);
724
725    free(client);
726 }
727
728 /**
729  * Sets the callback to report server died.
730  *
731  * When server dies there is nothing you can do, just release
732  * resources with ethumb_client_disconnect() and probably try to
733  * connect again.
734  *
735  * Usually you should set this callback and handle this case, it does
736  * happen!
737  *
738  * @param client the client instance to monitor. Must @b not be @c
739  *        NULL.
740  * @param server_die_cb function to call back when server dies. The
741  *        first parameter will be the argument @a data. May be @c
742  *        NULL.
743  * @param data context to give back to @a server_die_cb. May be @c
744  *        NULL.
745  * @param free_data used to release @a data resources after @a
746  *        server_die_cb is called or user calls
747  *        ethumb_client_disconnect().
748  */
749 EAPI void
750 ethumb_client_on_server_die_callback_set(Ethumb_Client *client, Ethumb_Client_Die_Cb server_die_cb, const void *data, Eina_Free_Cb free_data)
751 {
752    EINA_SAFETY_ON_NULL_RETURN(client);
753
754    if (client->die.free_data)
755      client->die.free_data(client->die.data);
756
757    client->die.cb = server_die_cb;
758    client->die.data = (void *)data;
759    client->die.free_data = free_data;
760 }
761
762 /**
763  * @cond LOCAL
764  */
765
766 static void
767 _ethumb_client_ethumb_setup_cb(void *data, DBusMessage *msg, DBusError *error)
768 {
769    DBusMessageIter iter;
770    int t;
771    dbus_bool_t result = 0;
772    Ethumb_Client *client = data;
773
774    client->pending_setup = NULL;
775
776    if (!_dbus_callback_check_and_init(msg, &iter, error))
777      return;
778
779    t = dbus_message_iter_get_arg_type(&iter);
780    if (!_dbus_iter_type_check(t, DBUS_TYPE_BOOLEAN))
781      return;
782
783    dbus_message_iter_get_basic(&iter, &result);
784 }
785
786 static const char *
787 _ethumb_client_dbus_get_bytearray(DBusMessageIter *iter)
788 {
789    int el_type;
790    int length;
791    DBusMessageIter riter;
792    const char *result;
793
794    el_type = dbus_message_iter_get_element_type(iter);
795    if (el_type != DBUS_TYPE_BYTE)
796      {
797         ERR("not an byte array element.");
798         return NULL;
799      }
800
801    dbus_message_iter_recurse(iter, &riter);
802    dbus_message_iter_get_fixed_array(&riter, &result, &length);
803
804    if (result[0] == '\0')
805      return NULL;
806    else
807      return eina_stringshare_add(result);
808 }
809
810 static void
811 _ethumb_client_dbus_append_bytearray(DBusMessageIter *iter, const char *string)
812 {
813    DBusMessageIter viter;
814
815    if (!string)
816      string = "";
817
818    dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "y", &viter);
819    dbus_message_iter_append_fixed_array(&viter, DBUS_TYPE_BYTE, &string,
820                                         strlen(string) + 1);
821    dbus_message_iter_close_container(iter, &viter);
822 }
823
824 /**
825  * @endcond
826  */
827
828 /**
829  * Send setup to server.
830  *
831  * This method is called automatically by ethumb_client_generate() if
832  * any property was changed. No need to call it manually.
833  *
834  * @param client client instance. Must @b not be @c NULL and client
835  *        must be connected (after connected_cb is called).
836  */
837 EAPI void
838 ethumb_client_ethumb_setup(Ethumb_Client *client)
839 {
840    DBusMessage *msg;
841    DBusMessageIter iter, aiter, diter, viter, vaiter;
842    Ethumb *e = client->ethumb;
843    const char *entry;
844    dbus_int32_t tw, th, format, aspect, quality, compress;
845    float cx, cy;
846    double t;
847    const char *theme_file, *group, *swallow;
848    const char *directory, *category;
849    double video_time, video_start, video_interval;
850    dbus_int32_t video_ntimes, video_fps, document_page;
851
852    EINA_SAFETY_ON_NULL_RETURN(client);
853    EINA_SAFETY_ON_FALSE_RETURN(client->connected);
854    client->ethumb_dirty = 0;
855
856    msg = dbus_message_new_method_call(_ethumb_dbus_bus_name,
857                                       client->object_path,
858                                       _ethumb_dbus_objects_interface,
859                                       "ethumb_setup");
860    dbus_message_iter_init_append(msg, &iter);
861    dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &aiter);
862
863 /**
864  * @cond LOCAL
865  */
866 #define _open_variant_iter(str_entry, str_type, end_iter)                  \
867    entry = str_entry;                                                      \
868    dbus_message_iter_open_container(&aiter, DBUS_TYPE_DICT_ENTRY, NULL, &diter); \
869    dbus_message_iter_append_basic(&diter, DBUS_TYPE_STRING, &entry);   \
870    dbus_message_iter_open_container(&diter, DBUS_TYPE_VARIANT, str_type,   \
871                                     &end_iter);
872
873 #define _close_variant_iter(end_iter)                                      \
874    dbus_message_iter_close_container(&diter, &end_iter);                   \
875    dbus_message_iter_close_container(&aiter, &diter);
876 /**
877  * @endcond
878  */
879
880    /* starting array elements */
881
882    _open_variant_iter("size", "(ii)", viter);
883    dbus_message_iter_open_container(&viter, DBUS_TYPE_STRUCT, NULL, &vaiter);
884    ethumb_thumb_size_get(e, &tw, &th);
885    dbus_message_iter_append_basic(&vaiter, DBUS_TYPE_INT32, &tw);
886    dbus_message_iter_append_basic(&vaiter, DBUS_TYPE_INT32, &th);
887    dbus_message_iter_close_container(&viter, &vaiter);
888    _close_variant_iter(viter);
889
890    _open_variant_iter("format", "i", viter);
891    format = ethumb_thumb_format_get(e);
892    dbus_message_iter_append_basic(&viter, DBUS_TYPE_INT32, &format);
893    _close_variant_iter(viter);
894
895    _open_variant_iter("aspect", "i", viter);
896    aspect = ethumb_thumb_aspect_get(e);
897    dbus_message_iter_append_basic(&viter, DBUS_TYPE_INT32, &aspect);
898    _close_variant_iter(viter);
899
900    _open_variant_iter("crop", "(dd)", viter);
901    dbus_message_iter_open_container(&viter, DBUS_TYPE_STRUCT, NULL, &vaiter);
902    ethumb_thumb_crop_align_get(e, &cx, &cy);
903    t = cx;
904    dbus_message_iter_append_basic(&vaiter, DBUS_TYPE_DOUBLE, &t);
905    t = cy;
906    dbus_message_iter_append_basic(&vaiter, DBUS_TYPE_DOUBLE, &t);
907    dbus_message_iter_close_container(&viter, &vaiter);
908    _close_variant_iter(viter);
909
910    _open_variant_iter("quality", "i", viter);
911    quality = ethumb_thumb_quality_get(e);
912    dbus_message_iter_append_basic(&viter, DBUS_TYPE_INT32, &quality);
913    _close_variant_iter(viter);
914
915    _open_variant_iter("compress", "i", viter);
916    compress = ethumb_thumb_compress_get(e);
917    dbus_message_iter_append_basic(&viter, DBUS_TYPE_INT32, &compress);
918    _close_variant_iter(viter);
919
920    _open_variant_iter("frame", "(ayayay)", viter);
921    dbus_message_iter_open_container(&viter, DBUS_TYPE_STRUCT, NULL, &vaiter);
922    ethumb_frame_get(e, &theme_file, &group, &swallow);
923    _ethumb_client_dbus_append_bytearray(&vaiter, theme_file);
924    _ethumb_client_dbus_append_bytearray(&vaiter, group);
925    _ethumb_client_dbus_append_bytearray(&vaiter, swallow);
926    dbus_message_iter_close_container(&viter, &vaiter);
927    _close_variant_iter(viter);
928
929    _open_variant_iter("directory", "ay", viter);
930    directory = ethumb_thumb_dir_path_get(e);
931    _ethumb_client_dbus_append_bytearray(&viter, directory);
932    _close_variant_iter(viter);
933
934    _open_variant_iter("category", "ay", viter);
935    category = ethumb_thumb_category_get(e);
936    _ethumb_client_dbus_append_bytearray(&viter, category);
937    _close_variant_iter(viter);
938
939    _open_variant_iter("video_time", "d", viter);
940    video_time = ethumb_video_time_get(e);
941    dbus_message_iter_append_basic(&viter, DBUS_TYPE_DOUBLE, &video_time);
942    _close_variant_iter(viter);
943
944    _open_variant_iter("video_start", "d", viter);
945    video_start = ethumb_video_start_get(e);
946    dbus_message_iter_append_basic(&viter, DBUS_TYPE_DOUBLE, &video_start);
947    _close_variant_iter(viter);
948
949    _open_variant_iter("video_interval", "d", viter);
950    video_interval = ethumb_video_interval_get(e);
951    dbus_message_iter_append_basic(&viter, DBUS_TYPE_DOUBLE, &video_interval);
952    _close_variant_iter(viter);
953
954    _open_variant_iter("video_ntimes", "u", viter);
955    video_ntimes = ethumb_video_ntimes_get(e);
956    dbus_message_iter_append_basic(&viter, DBUS_TYPE_UINT32, &video_ntimes);
957    _close_variant_iter(viter);
958
959    _open_variant_iter("video_fps", "u", viter);
960    video_fps = ethumb_video_fps_get(e);
961    dbus_message_iter_append_basic(&viter, DBUS_TYPE_UINT32, &video_fps);
962    _close_variant_iter(viter);
963
964    _open_variant_iter("document_page", "u", viter);
965    document_page = ethumb_document_page_get(e);
966    dbus_message_iter_append_basic(&viter, DBUS_TYPE_UINT32, &document_page);
967    _close_variant_iter(viter);
968
969 #undef _open_variant_iter
970 #undef _close_variant_iter
971
972    dbus_message_iter_close_container(&iter, &aiter);
973
974    client->pending_setup = e_dbus_message_send(client->conn, msg,
975                                                _ethumb_client_ethumb_setup_cb,
976                                                -1, client);
977    dbus_message_unref(msg);
978 }
979
980 /**
981  * @cond LOCAL
982  */
983
984 static void
985 _ethumb_client_generated_cb(void *data, DBusMessage *msg)
986 {
987    DBusMessageIter iter;
988    dbus_int32_t id = -1;
989    const char *thumb;
990    const char *thumb_key;
991    Ethumb_Client *client = data;
992    int t;
993    dbus_bool_t success;
994    Eina_List *l;
995    int found;
996    struct _ethumb_pending_gen *pending;
997
998    dbus_message_iter_init(msg, &iter);
999
1000    t = dbus_message_iter_get_arg_type(&iter);
1001    if (!_dbus_iter_type_check(t, DBUS_TYPE_INT32))
1002      goto end;
1003    dbus_message_iter_get_basic(&iter, &id);
1004    dbus_message_iter_next(&iter);
1005
1006    t = dbus_message_iter_get_arg_type(&iter);
1007    if (!_dbus_iter_type_check(t, DBUS_TYPE_ARRAY))
1008      goto end;
1009    thumb = _ethumb_client_dbus_get_bytearray(&iter);
1010    dbus_message_iter_next(&iter);
1011
1012    t = dbus_message_iter_get_arg_type(&iter);
1013    if (!_dbus_iter_type_check(t, DBUS_TYPE_ARRAY))
1014      goto end;
1015    thumb_key = _ethumb_client_dbus_get_bytearray(&iter);
1016    dbus_message_iter_next(&iter);
1017
1018    t = dbus_message_iter_get_arg_type(&iter);
1019    if (!_dbus_iter_type_check(t, DBUS_TYPE_BOOLEAN))
1020      goto end;
1021    dbus_message_iter_get_basic(&iter, &success);
1022
1023    found = 0;
1024    l = client->pending_gen;
1025    while (l)
1026      {
1027         pending = l->data;
1028         if (pending->id == id)
1029           {
1030              found = 1;
1031              break;
1032           }
1033         l = l->next;
1034      }
1035
1036    if (found)
1037      {
1038         client->pending_gen = eina_list_remove_list(client->pending_gen, l);
1039         pending->generated_cb(pending->data, client, id,
1040                               pending->file, pending->key,
1041                               pending->thumb, pending->thumb_key,
1042                               success);
1043         if (pending->free_data)
1044           pending->free_data(pending->data);
1045         eina_stringshare_del(pending->file);
1046         eina_stringshare_del(pending->key);
1047         eina_stringshare_del(pending->thumb);
1048         eina_stringshare_del(pending->thumb_key);
1049         free(pending);
1050      }
1051
1052 end:
1053    eina_stringshare_del(thumb);
1054    eina_stringshare_del(thumb_key);
1055 }
1056
1057 static void
1058 _ethumb_client_queue_add_cb(void *data, DBusMessage *msg, DBusError *error)
1059 {
1060    DBusMessageIter iter;
1061    int t;
1062    dbus_int32_t id = -1;
1063    struct _ethumb_pending_add *pending = data;
1064    struct _ethumb_pending_gen *generating;
1065    Ethumb_Client *client = pending->client;
1066
1067    client->pending_add = eina_list_remove(client->pending_add, pending);
1068
1069    if (!_dbus_callback_check_and_init(msg, &iter, error))
1070      goto end;
1071
1072    t = dbus_message_iter_get_arg_type(&iter);
1073    if (!_dbus_iter_type_check(t, DBUS_TYPE_INT32))
1074      goto end;
1075
1076    dbus_message_iter_get_basic(&iter, &id);
1077
1078    generating = calloc(1, sizeof(*generating));
1079    generating->id = id;
1080    generating->file = pending->file;
1081    generating->key = pending->key;
1082    generating->thumb = pending->thumb;
1083    generating->thumb_key = pending->thumb_key;
1084    generating->generated_cb = pending->generated_cb;
1085    generating->data = pending->data;
1086    generating->free_data = pending->free_data;
1087    client->pending_gen = eina_list_append(client->pending_gen, generating);
1088
1089 end:
1090    free(pending);
1091 }
1092
1093 static int
1094 _ethumb_client_queue_add(Ethumb_Client *client, const char *file, const char *key, const char *thumb, const char *thumb_key, Ethumb_Client_Generate_Cb generated_cb, const void *data, Eina_Free_Cb free_data)
1095 {
1096    DBusMessage *msg;
1097    DBusMessageIter iter;
1098    struct _ethumb_pending_add *pending;
1099
1100    pending = calloc(1, sizeof(*pending));
1101    pending->id = client->id_count;
1102    pending->file = eina_stringshare_add(file);
1103    pending->key = eina_stringshare_add(key);
1104    pending->thumb = eina_stringshare_add(thumb);
1105    pending->thumb_key = eina_stringshare_add(thumb_key);
1106    pending->generated_cb = generated_cb;
1107    pending->data = (void *)data;
1108    pending->free_data = free_data;
1109    pending->client = client;
1110
1111    client->id_count = (client->id_count + 1) % MAX_ID;
1112
1113    msg = dbus_message_new_method_call(_ethumb_dbus_bus_name,
1114                                       client->object_path,
1115                                       _ethumb_dbus_objects_interface,
1116                                       "queue_add");
1117
1118    dbus_message_iter_init_append(msg, &iter);
1119    dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &pending->id);
1120    _ethumb_client_dbus_append_bytearray(&iter, file);
1121    _ethumb_client_dbus_append_bytearray(&iter, key);
1122    _ethumb_client_dbus_append_bytearray(&iter, thumb);
1123    _ethumb_client_dbus_append_bytearray(&iter, thumb_key);
1124
1125    pending->pending_call = e_dbus_message_send(client->conn, msg,
1126                                                _ethumb_client_queue_add_cb,
1127                                                -1, pending);
1128    client->pending_add = eina_list_append(client->pending_add, pending);
1129    dbus_message_unref(msg);
1130
1131    return pending->id;
1132 }
1133
1134 static void
1135 _ethumb_client_queue_remove_cb(void *data, DBusMessage *msg, DBusError *error)
1136 {
1137    DBusMessageIter iter;
1138    int t;
1139    dbus_bool_t success = 0;
1140    struct _ethumb_pending_remove *pending = data;
1141    Ethumb_Client *client = pending->client;
1142
1143    client->pending_remove = eina_list_remove(client->pending_remove, pending);
1144
1145    if (!_dbus_callback_check_and_init(msg, &iter, error))
1146      goto end;
1147
1148    t = dbus_message_iter_get_arg_type(&iter);
1149    if (!_dbus_iter_type_check(t, DBUS_TYPE_BOOLEAN))
1150      goto end;
1151
1152    dbus_message_iter_get_basic(&iter, &success);
1153
1154 end:
1155    if (pending->cancel_cb)
1156      pending->cancel_cb(pending->data, success);
1157    if (pending->free_data)
1158      pending->free_data(pending->data);
1159    free(pending);
1160 }
1161 /**
1162  * @endcond
1163  */
1164
1165 /**
1166  * Ask server to cancel generation of thumbnail.
1167  *
1168  * @param client client instance. Must @b not be @c NULL and client
1169  *        must be connected (after connected_cb is called).
1170  * @param id valid id returned by ethumb_client_generate()
1171  * @param cancel_cb function to report cancellation results.
1172  * @param data context argument to give back to @a cancel_cb. May be
1173  *        @c NULL.
1174  * @param data context to give back to @a cancel_cb. May be @c
1175  *        NULL.
1176  * @param free_data used to release @a data resources after @a
1177  *        cancel_cb is called or user calls
1178  *        ethumb_client_disconnect().
1179  */
1180 EAPI void
1181 ethumb_client_generate_cancel(Ethumb_Client *client, int id, Ethumb_Client_Generate_Cancel_Cb cancel_cb, const void *data, Eina_Free_Cb free_data)
1182 {
1183    DBusMessage *msg;
1184    struct _ethumb_pending_remove *pending;
1185    Eina_List *l;
1186    int found;
1187    dbus_int32_t id32 = id;
1188    EINA_SAFETY_ON_NULL_RETURN(client);
1189    EINA_SAFETY_ON_FALSE_RETURN(id >= 0);
1190
1191    pending = calloc(1, sizeof(*pending));
1192    pending->id = id;
1193    pending->cancel_cb = cancel_cb;
1194    pending->data = (void *)data;
1195    pending->free_data = free_data;
1196    pending->client = client;
1197
1198    msg = dbus_message_new_method_call(_ethumb_dbus_bus_name,
1199                                       client->object_path,
1200                                       _ethumb_dbus_objects_interface,
1201                                       "queue_remove");
1202
1203    dbus_message_append_args(msg, DBUS_TYPE_INT32, &id32, DBUS_TYPE_INVALID);
1204    pending->pending_call = e_dbus_message_send(client->conn, msg,
1205                                                _ethumb_client_queue_remove_cb,
1206                                                -1, pending);
1207    client->pending_remove = eina_list_append(client->pending_remove, pending);
1208
1209    found = 0;
1210    l = client->pending_add;
1211    while (l)
1212      {
1213         struct _ethumb_pending_add *pending = l->data;
1214         if (pending->id != id32)
1215           {
1216              l = l->next;
1217              continue;
1218           }
1219         client->pending_add = eina_list_remove_list(client->pending_add, l);
1220         eina_stringshare_del(pending->file);
1221         eina_stringshare_del(pending->key);
1222         eina_stringshare_del(pending->thumb);
1223         eina_stringshare_del(pending->thumb_key);
1224         dbus_pending_call_cancel(pending->pending_call);
1225         dbus_pending_call_unref(pending->pending_call);
1226         if (pending->free_data)
1227           pending->free_data(pending->data);
1228         free(pending);
1229         found = 1;
1230         break;
1231      }
1232
1233    if (found)
1234      goto end;
1235
1236    l = client->pending_gen;
1237    while (l)
1238      {
1239         struct _ethumb_pending_gen *pending = l->data;
1240         if (pending->id != id32)
1241           {
1242              l = l->next;
1243              continue;
1244           }
1245         client->pending_gen = eina_list_remove_list(client->pending_gen, l);
1246         eina_stringshare_del(pending->file);
1247         eina_stringshare_del(pending->key);
1248         eina_stringshare_del(pending->thumb);
1249         eina_stringshare_del(pending->thumb_key);
1250         if (pending->free_data)
1251           pending->free_data(pending->data);
1252         free(pending);
1253         found = 1;
1254         break;
1255      }
1256
1257 end:
1258    dbus_message_unref(msg);
1259 }
1260
1261 /**
1262  * @cond LOCAL
1263  */
1264 static void
1265 _ethumb_client_queue_clear_cb(void *data, DBusMessage *msg __UNUSED__, DBusError *error __UNUSED__)
1266 {
1267    Ethumb_Client *client = data;
1268
1269    client->pending_clear = NULL;
1270 }
1271 /**
1272  * @endcond
1273  */
1274
1275 /**
1276  * Ask server to cancel generation of all thumbnails.
1277  *
1278  * @param client client instance. Must @b not be @c NULL and client
1279  *        must be connected (after connected_cb is called).
1280  *
1281  * @see ethumb_client_generate_cancel()
1282  */
1283 EAPI void
1284 ethumb_client_generate_cancel_all(Ethumb_Client *client)
1285 {
1286    DBusMessage *msg;
1287    void *data;
1288    EINA_SAFETY_ON_NULL_RETURN(client);
1289
1290    if (client->pending_clear)
1291      return;
1292
1293    EINA_LIST_FREE(client->pending_add, data)
1294      {
1295         struct _ethumb_pending_add *pending = data;
1296         eina_stringshare_del(pending->file);
1297         eina_stringshare_del(pending->key);
1298         eina_stringshare_del(pending->thumb);
1299         eina_stringshare_del(pending->thumb_key);
1300         dbus_pending_call_cancel(pending->pending_call);
1301         dbus_pending_call_unref(pending->pending_call);
1302         if (pending->free_data)
1303           pending->free_data(pending->data);
1304         free(pending);
1305      }
1306
1307    EINA_LIST_FREE(client->pending_gen, data)
1308      {
1309         struct _ethumb_pending_gen *pending = data;
1310         eina_stringshare_del(pending->file);
1311         eina_stringshare_del(pending->key);
1312         eina_stringshare_del(pending->thumb);
1313         eina_stringshare_del(pending->thumb_key);
1314         if (pending->free_data)
1315           pending->free_data(pending->data);
1316         free(pending);
1317      }
1318
1319    msg = dbus_message_new_method_call(_ethumb_dbus_bus_name,
1320                                       client->object_path,
1321                                       _ethumb_dbus_objects_interface,
1322                                       "queue_clear");
1323
1324    client->pending_clear = e_dbus_message_send(client->conn, msg,
1325                                                _ethumb_client_queue_clear_cb,
1326                                                -1, client);
1327
1328    dbus_message_unref(msg);
1329 }
1330
1331 /**
1332  * Configure future requests to use FreeDesktop.Org preset.
1333  *
1334  * This is a preset to provide freedesktop.org (fdo) standard
1335  * compliant thumbnails. That is, files are stored as JPEG under
1336  * ~/.thumbnails/SIZE, with size being either normal (128x128) or
1337  * large (256x256).
1338  *
1339  * @param client the client instance to use. Must @b not be @c
1340  *        NULL. May be pending connected (can be called before @c
1341  *        connected_cb)
1342  * @param s size identifier, either #ETHUMB_THUMB_NORMAL (0) or
1343  *        #ETHUMB_THUMB_LARGE (1).
1344  *
1345  * @see ethumb_client_size_set()
1346  * @see ethumb_client_aspect_set()
1347  * @see ethumb_client_crop_align_set()
1348  * @see ethumb_client_category_set()
1349  * @see ethumb_client_dir_path_set()
1350  */
1351 EAPI void
1352 ethumb_client_fdo_set(Ethumb_Client *client, Ethumb_Thumb_FDO_Size s)
1353 {
1354    EINA_SAFETY_ON_NULL_RETURN(client);
1355
1356    client->ethumb_dirty = 1;
1357    ethumb_thumb_fdo_set(client->ethumb, s);
1358 }
1359
1360 /**
1361  * Configure future request to use custom size.
1362  *
1363  * @param client the client instance to use. Must @b not be @c
1364  *        NULL. May be pending connected (can be called before @c
1365  *        connected_cb)
1366  * @param tw width, default is 128.
1367  * @param th height, default is 128.
1368  */
1369 EAPI void
1370 ethumb_client_size_set(Ethumb_Client *client, int tw, int th)
1371 {
1372    EINA_SAFETY_ON_NULL_RETURN(client);
1373
1374    client->ethumb_dirty = 1;
1375    ethumb_thumb_size_set(client->ethumb, tw, th);
1376 }
1377
1378 /**
1379  * Retrieve future request to use custom size.
1380  *
1381  * @param client the client instance to use. Must @b not be @c
1382  *        NULL. May be pending connected (can be called before @c
1383  *        connected_cb)
1384  * @param tw where to return width. May be @c NULL.
1385  * @param th where to return height. May be @c NULL.
1386  */
1387 EAPI void
1388 ethumb_client_size_get(const Ethumb_Client *client, int *tw, int *th)
1389 {
1390    if (tw) *tw = 0;
1391    if (th) *th = 0;
1392    EINA_SAFETY_ON_NULL_RETURN(client);
1393
1394    ethumb_thumb_size_get(client->ethumb, tw, th);
1395 }
1396
1397 /**
1398  * Configure format to use for future requests.
1399  *
1400  * @param client the client instance to use. Must @b not be @c
1401  *        NULL. May be pending connected (can be called before @c
1402  *        connected_cb)
1403  * @param f format identifier to use, either #ETHUMB_THUMB_FDO (0),
1404  *        #ETHUMB_THUMB_JPEG (1) or #ETHUMB_THUMB_EET (2). Default is FDO.
1405  */
1406 EAPI void
1407 ethumb_client_format_set(Ethumb_Client *client, Ethumb_Thumb_Format f)
1408 {
1409    EINA_SAFETY_ON_NULL_RETURN(client);
1410
1411    client->ethumb_dirty = 1;
1412    ethumb_thumb_format_set(client->ethumb, f);
1413 }
1414
1415 /**
1416  * Retrieve format to use for future requests.
1417  *
1418  * @param client the client instance to use. Must @b not be @c
1419  *        NULL. May be pending connected (can be called before @c
1420  *        connected_cb)
1421  *
1422  * @return format identifier to use, either #ETHUMB_THUMB_FDO (0),
1423  *         #ETHUMB_THUMB_JPEG (1) or #ETHUMB_THUMB_EET (2).
1424  */
1425 EAPI Ethumb_Thumb_Format
1426 ethumb_client_format_get(const Ethumb_Client *client)
1427 {
1428    EINA_SAFETY_ON_NULL_RETURN_VAL(client, 0);
1429
1430    return ethumb_thumb_format_get(client->ethumb);
1431 }
1432
1433 /**
1434  * Configure aspect mode to use.
1435  *
1436  * If aspect is kept (#ETHUMB_THUMB_KEEP_ASPECT), then image will be
1437  * rescaled so the largest dimension is not bigger than it's specified
1438  * size (see ethumb_client_size_get()) and the other dimension is
1439  * resized in the same proportion. Example: size is 256x256, image is
1440  * 1000x500, resulting thumbnail is 256x128.
1441  *
1442  * If aspect is ignored (#ETHUMB_THUMB_IGNORE_ASPECT), then image will
1443  * be distorted to match required thumbnail size. Example: size is
1444  * 256x256, image is 1000x500, resulting thumbnail is 256x256.
1445  *
1446  * If crop is required (#ETHUMB_THUMB_CROP), then image will be
1447  * cropped so the smallest dimension is not bigger than its specified
1448  * size (see ethumb_client_size_get()) and the other dimension will
1449  * overflow, not being visible in the final image. How it will
1450  * overflow is speficied by ethumb_client_crop_align_set()
1451  * alignment. Example: size is 256x256, image is 1000x500, crop
1452  * alignment is 0.5, 0.5, resulting thumbnail is 256x256 with 250
1453  * pixels from left and 250 pixels from right being lost, that is just
1454  * the 500x500 central pixels of image will be considered for scaling.
1455  *
1456  * @param client the client instance to use. Must @b not be @c
1457  *        NULL. May be pending connected (can be called before @c
1458  *        connected_cb)
1459  * @param a aspect mode identifier, either #ETHUMB_THUMB_KEEP_ASPECT (0),
1460  *        #ETHUMB_THUMB_IGNORE_ASPECT (1) or #ETHUMB_THUMB_CROP (2).
1461  */
1462 EAPI void
1463 ethumb_client_aspect_set(Ethumb_Client *client, Ethumb_Thumb_Aspect a)
1464 {
1465    EINA_SAFETY_ON_NULL_RETURN(client);
1466
1467    client->ethumb_dirty = 1;
1468    ethumb_thumb_aspect_set(client->ethumb, a);
1469 }
1470
1471 /**
1472  * Get current aspect in use for requests.
1473  *
1474  * @param client the client instance to use. Must @b not be @c
1475  *        NULL. May be pending connected (can be called before @c
1476  *        connected_cb)
1477  *
1478  * @return aspect in use for future requests.
1479  */
1480 EAPI Ethumb_Thumb_Aspect
1481 ethumb_client_aspect_get(const Ethumb_Client *client)
1482 {
1483    EINA_SAFETY_ON_NULL_RETURN_VAL(client, 0);
1484
1485    return ethumb_thumb_aspect_get(client->ethumb);
1486 }
1487
1488 /**
1489  * Configure crop alignment in use for future requests.
1490  *
1491  * @param client the client instance to use. Must @b not be @c
1492  *        NULL. May be pending connected (can be called before @c
1493  *        connected_cb)
1494  * @param x horizontal alignment. 0.0 means left side will be visible
1495  *        or right side is being lost. 1.0 means right side will be
1496  *        visible or left side is being lost. 0.5 means just center is
1497  *        visible, both sides will be lost.  Default is 0.5.
1498  * @param y vertical alignment. 0.0 is top visible, 1.0 is bottom
1499  *        visible, 0.5 is center visible. Default is 0.5
1500  */
1501 EAPI void
1502 ethumb_client_crop_align_set(Ethumb_Client *client, float x, float y)
1503 {
1504    EINA_SAFETY_ON_NULL_RETURN(client);
1505
1506    client->ethumb_dirty = 1;
1507    ethumb_thumb_crop_align_set(client->ethumb, x, y);
1508 }
1509
1510 /**
1511  * Get current crop alignment in use for requests.
1512  *
1513  * @param client the client instance to use. Must @b not be @c
1514  *        NULL. May be pending connected (can be called before @c
1515  *        connected_cb)
1516  * @param x where to return horizontal alignment. May be @c NULL.
1517  * @param y where to return vertical alignment. May be @c NULL.
1518  */
1519 EAPI void
1520 ethumb_client_crop_align_get(const Ethumb_Client *client, float *x, float *y)
1521 {
1522    if (x) *x = 0.0;
1523    if (y) *y = 0.0;
1524    EINA_SAFETY_ON_NULL_RETURN(client);
1525
1526    ethumb_thumb_crop_align_get(client->ethumb, x, y);
1527 }
1528
1529 /**
1530  * Configure quality to be used in thumbnails.
1531  *
1532  * @param client the client instance to use. Must @b not be @c
1533  *        NULL. May be pending connected (can be called before @c
1534  *        connected_cb)
1535  * @param quality value from 0 to 100, default is 80. The effect
1536  *        depends on the format being used, PNG will not use it.
1537  */
1538 EAPI void
1539 ethumb_client_quality_set(Ethumb_Client *client, int quality)
1540 {
1541    EINA_SAFETY_ON_NULL_RETURN(client);
1542
1543    ethumb_thumb_quality_set(client->ethumb, quality);
1544 }
1545
1546 /**
1547  * Get quality to be used in thumbnails.
1548  *
1549  * @param client the client instance to use. Must @b not be @c
1550  *        NULL. May be pending connected (can be called before @c
1551  *        connected_cb)
1552  *
1553  * @return quality value from 0 to 100, default is 80. The effect
1554  *         depends on the format being used, PNG will not use it.
1555  */
1556 EAPI int
1557 ethumb_client_quality_get(const Ethumb_Client *client)
1558 {
1559    EINA_SAFETY_ON_NULL_RETURN_VAL(client, 0);
1560
1561    return ethumb_thumb_quality_get(client->ethumb);
1562 }
1563
1564 /**
1565  * Configure compression level used in requests.
1566  *
1567  * @param client the client instance to use. Must @b not be @c
1568  *        NULL. May be pending connected (can be called before @c
1569  *        connected_cb)
1570  * @param compress value from 0 to 9, default is 9. The effect
1571  *        depends on the format being used, JPEG will not use it.
1572  */
1573 EAPI void
1574 ethumb_client_compress_set(Ethumb_Client *client, int compress)
1575 {
1576    EINA_SAFETY_ON_NULL_RETURN(client);
1577
1578    ethumb_thumb_compress_set(client->ethumb, compress);
1579 }
1580
1581 /**
1582  * Get compression level used in requests.
1583  *
1584  * @param client the client instance to use. Must @b not be @c
1585  *        NULL. May be pending connected (can be called before @c
1586  *        connected_cb)
1587  *
1588  * @return compress value from 0 to 9, default is 9. The effect
1589  *         depends on the format being used, JPEG will not use it.
1590  */
1591 EAPI int
1592 ethumb_client_compress_get(const Ethumb_Client *client)
1593 {
1594    EINA_SAFETY_ON_NULL_RETURN_VAL(client, 0);
1595
1596    return ethumb_thumb_compress_get(client->ethumb);
1597 }
1598
1599 /**
1600  * Set frame to apply to future thumbnails.
1601  *
1602  * This will create an edje object that will have image swallowed
1603  * in. This can be used to simulate Polaroid or wood frames in the
1604  * generated image. Remeber it is bad to modify the original contents
1605  * of thumbnails, but sometimes it's useful to have it composited and
1606  * avoid runtime overhead.
1607  *
1608  * @param client the client instance to use. Must @b not be @c
1609  *        NULL. May be pending connected (can be called before @c
1610  *        connected_cb)
1611  * @param file file path to edje.
1612  * @param group group inside edje to use.
1613  * @param swallow name of swallow part.
1614  */
1615 EAPI Eina_Bool
1616 ethumb_client_frame_set(Ethumb_Client *client, const char *file, const char *group, const char *swallow)
1617 {
1618    EINA_SAFETY_ON_NULL_RETURN_VAL(client, 0);
1619
1620    client->ethumb_dirty = 1;
1621    return ethumb_frame_set(client->ethumb, file, group, swallow);
1622 }
1623
1624 /**
1625  * Configure where to store thumbnails in future requests.
1626  *
1627  * This value will be used to generate thumbnail paths, that is, it
1628  * will be used when ethumb_client_thumb_path_set() was not called
1629  * after last ethumb_client_file_set().
1630  *
1631  * Note that this is the base, a category is added to this path as a
1632  * sub directory. This is not the final directory where files are
1633  * stored, the thumbnail system will account @b category as well, see
1634  * ethumb_client_category_set().
1635  *
1636  * As other options, this value will only be applied to future
1637  * requests.
1638  *
1639  * @param client the client instance to use. Must @b not be @c
1640  *        NULL. May be pending connected (can be called before @c
1641  *        connected_cb)
1642  * @param path base directory where to store thumbnails. Default is
1643  *        ~/.thumbnails
1644  *
1645  * @see ethumb_client_category_set()
1646  */
1647 EAPI void
1648 ethumb_client_dir_path_set(Ethumb_Client *client, const char *path)
1649 {
1650    EINA_SAFETY_ON_NULL_RETURN(client);
1651
1652    client->ethumb_dirty = 1;
1653    ethumb_thumb_dir_path_set(client->ethumb, path);
1654 }
1655
1656 /**
1657  * Get base directory path where to store thumbnails.
1658  *
1659  * @param client the client instance to use. Must @b not be @c
1660  *        NULL. May be pending connected (can be called before @c
1661  *        connected_cb)
1662  *
1663  * @return pointer to internal string with current path. This string
1664  *         should not be modified or freed.
1665  *
1666  * @see ethumb_client_dir_path_set()
1667  */
1668 EAPI const char *
1669 ethumb_client_dir_path_get(const Ethumb_Client *client)
1670 {
1671    EINA_SAFETY_ON_NULL_RETURN_VAL(client, NULL);
1672
1673    return ethumb_thumb_dir_path_get(client->ethumb);
1674 }
1675
1676 /**
1677  * Category directory to store thumbnails.
1678  *
1679  * This value will be used to generate thumbnail paths, that is, it
1680  * will be used when ethumb_client_thumb_path_set() was not called
1681  * after last ethumb_client_file_set().
1682  *
1683  * This is a sub-directory inside base directory
1684  * (ethumb_client_dir_path_set()) that creates a namespace to avoid
1685  * different options resulting in the same file.
1686  *
1687  * As other options, this value will only be applied to future
1688  * requests.
1689  *
1690  * @param client the client instance to use. Must @b not be @c
1691  *        NULL. May be pending connected (can be called before @c
1692  *        connected_cb)
1693  * @param category category sub directory to store thumbnail. Default
1694  *        is either "normal" or "large" for FDO compliant thumbnails
1695  *        or WIDTHxHEIGHT-ASPECT[-FRAMED]-FORMAT. It can be a string
1696  *        or @c NULL to use auto generated names.
1697  *
1698  * @see ethumb_client_dir_path_set()
1699  */
1700 EAPI void
1701 ethumb_client_category_set(Ethumb_Client *client, const char *category)
1702 {
1703    EINA_SAFETY_ON_NULL_RETURN(client);
1704
1705    client->ethumb_dirty = 1;
1706    ethumb_thumb_category_set(client->ethumb, category);
1707 }
1708
1709 /**
1710  * Get category sub-directory  where to store thumbnails.
1711  *
1712  * @param client the client instance to use. Must @b not be @c
1713  *        NULL. May be pending connected (can be called before @c
1714  *        connected_cb)
1715  *
1716  * @return pointer to internal string with current path. This string
1717  *         should not be modified or freed.
1718  *
1719  * @see ethumb_client_category_set()
1720  */
1721 EAPI const char *
1722 ethumb_client_category_get(const Ethumb_Client *client)
1723 {
1724    EINA_SAFETY_ON_NULL_RETURN_VAL(client, NULL);
1725
1726    return ethumb_thumb_category_get(client->ethumb);
1727 }
1728
1729 /**
1730  * Set the video time (duration) in seconds.
1731  *
1732  * @param client the client instance to use. Must @b not be @c
1733  *        NULL. May be pending connected (can be called before @c
1734  *        connected_cb)
1735  * @param time duration (in seconds). Defaults to 3 seconds.
1736  */
1737 EAPI void
1738 ethumb_client_video_time_set(Ethumb_Client *client, float time)
1739 {
1740    EINA_SAFETY_ON_NULL_RETURN(client);
1741
1742    client->ethumb_dirty = 1;
1743    ethumb_video_time_set(client->ethumb, time);
1744 }
1745
1746 /**
1747  * Set initial video position to start thumbnailing, in percentage.
1748  *
1749  * This is useful to avoid thumbnailing the company/producer logo or
1750  * movie opening.
1751  *
1752  * @param client the client instance to use. Must @b not be @c
1753  *        NULL. May be pending connected (can be called before @c
1754  *        connected_cb)
1755  * @param start initial video positon to thumbnail, in percentage (0.0
1756  *        to 1.0, inclusive). Defaults to 10% (0.1).
1757  */
1758 EAPI void
1759 ethumb_client_video_start_set(Ethumb_Client *client, float start)
1760 {
1761    EINA_SAFETY_ON_NULL_RETURN(client);
1762    EINA_SAFETY_ON_FALSE_RETURN(start >= 0.0);
1763    EINA_SAFETY_ON_FALSE_RETURN(start <= 1.0);
1764
1765    client->ethumb_dirty = 1;
1766    ethumb_video_start_set(client->ethumb, start);
1767 }
1768
1769 /**
1770  * Set the video frame interval, in seconds.
1771  *
1772  * This is useful for animated thumbnail and will define skip time
1773  * before going to the next frame. Note that video backends might not
1774  * be able to precisely skip that amount as it will depend on various
1775  * factors, including video encoding.
1776  *
1777  * Although this seems similar to ethumb_client_video_fps_set(), this
1778  * one is the time that will be used to seek. The math is simple, for
1779  * each new frame the video position will be set to:
1780  * ((video_length * start_time) + (interval * current_frame_number)).
1781  *
1782  * @param client the client instance to use. Must @b not be @c
1783  *        NULL. May be pending connected (can be called before @c
1784  *        connected_cb)
1785  * @param interval time between frames, in seconds. Defaults to 0.05
1786  *        seconds.
1787  */
1788 EAPI void
1789 ethumb_client_video_interval_set(Ethumb_Client *client, float interval)
1790 {
1791    EINA_SAFETY_ON_NULL_RETURN(client);
1792
1793    client->ethumb_dirty = 1;
1794    ethumb_video_interval_set(client->ethumb, interval);
1795 }
1796
1797 /**
1798  * Set the number of frames to thumbnail.
1799  *
1800  * This is useful for animated thumbnail and will define how many
1801  * frames the generated file will have.
1802  *
1803  * @param client the client instance to use. Must @b not be @c
1804  *        NULL. May be pending connected (can be called before @c
1805  *        connected_cb)
1806  * @param ntimes number of times, must be greater than zero.
1807  *        Defaults to 3.
1808  */
1809 EAPI void
1810 ethumb_client_video_ntimes_set(Ethumb_Client *client, unsigned int ntimes)
1811 {
1812    EINA_SAFETY_ON_NULL_RETURN(client);
1813    EINA_SAFETY_ON_FALSE_RETURN(ntimes > 0);
1814
1815    client->ethumb_dirty = 1;
1816    ethumb_video_ntimes_set(client->ethumb, ntimes);
1817 }
1818
1819 /**
1820  * Set the number of frames per second to thumbnail the video.
1821  *
1822  * This configures the number of times per seconds the thumbnail will
1823  * use to create thumbnails.
1824  *
1825  * Although this is similar to ethumb_client_video_interval_set(), it
1826  * is the delay used between calling functions thata generates frames,
1827  * while the other is the time used to skip inside the video.
1828  *
1829  * @param client the client instance to use. Must @b not be @c
1830  *        NULL. May be pending connected (can be called before @c
1831  *        connected_cb)
1832  * @param fps number of frames per second to thumbnail. Must be greater
1833  *        than zero. Defaults to 10.
1834  */
1835 EAPI void
1836 ethumb_client_video_fps_set(Ethumb_Client *client, unsigned int fps)
1837 {
1838    EINA_SAFETY_ON_NULL_RETURN(client);
1839    EINA_SAFETY_ON_FALSE_RETURN(fps > 0);
1840
1841    client->ethumb_dirty = 1;
1842    ethumb_video_fps_set(client->ethumb, fps);
1843 }
1844
1845 /**
1846  * Set the page number to thumbnail in paged documents.
1847  *
1848  * @param client the client instance to use. Must @b not be @c
1849  *        NULL. May be pending connected (can be called before @c
1850  *        connected_cb)
1851  * @param page page number, defaults to 0 (first).
1852  */
1853 EAPI void
1854 ethumb_client_document_page_set(Ethumb_Client *client, unsigned int page)
1855 {
1856    EINA_SAFETY_ON_NULL_RETURN(client);
1857
1858    client->ethumb_dirty = 1;
1859    ethumb_document_page_set(client->ethumb, page);
1860 }
1861
1862 /**
1863  * Set source file to be thumbnailed.
1864  *
1865  * Calling this function has the side effect of resetting values set
1866  * with ethumb_client_thumb_path_set() or auto-generated with
1867  * ethumb_client_thumb_exists().
1868  *
1869  * @param client the client instance to use. Must @b not be @c
1870  *        NULL. May be pending connected (can be called before @c
1871  *        connected_cb)
1872  * @param path the filesystem path to use. May be @c NULL.
1873  * @param key the extra argument/key inside @a path to read image
1874  *        from. This is only used for formats that allow multiple
1875  *        resources in one file, like EET or Edje (group name).
1876  *
1877  * @return @c EINA_TRUE on success, @c EINA_FALSE on failure.
1878  */
1879 EAPI Eina_Bool
1880 ethumb_client_file_set(Ethumb_Client *client, const char *path, const char *key)
1881 {
1882    EINA_SAFETY_ON_NULL_RETURN_VAL(client, 0);
1883
1884    return ethumb_file_set(client->ethumb, path, key);
1885 }
1886
1887 /**
1888  * Get values set with ethumb_client_file_get()
1889  *
1890  * @param client the client instance to use. Must @b not be @c
1891  *        NULL. May be pending connected (can be called before @c
1892  *        connected_cb)
1893  * @param path where to return configured path. May be @c NULL.  If
1894  *        not @c NULL, then it will be a pointer to a stringshared
1895  *        instance, but @b no references are added (do it with
1896  *        eina_stringshare_ref())!
1897  * @param key where to return configured key. May be @c NULL.If not @c
1898  *        NULL, then it will be a pointer to a stringshared instance,
1899  *        but @b no references are added (do it with
1900  *        eina_stringshare_ref())!
1901  */
1902 EAPI void
1903 ethumb_client_file_get(Ethumb_Client *client, const char **path, const char **key)
1904 {
1905    if (path) *path = NULL;
1906    if (key) *key = NULL;
1907    EINA_SAFETY_ON_NULL_RETURN(client);
1908
1909    ethumb_file_get(client->ethumb, path, key);
1910 }
1911
1912 /**
1913  * Reset previously set file to @c NULL.
1914  *
1915  * @param client the client instance to use. Must @b not be @c
1916  *        NULL. May be pending connected (can be called before @c
1917  *        connected_cb)
1918  */
1919 EAPI void
1920 ethumb_client_file_free(Ethumb_Client *client)
1921 {
1922    EINA_SAFETY_ON_NULL_RETURN(client);
1923
1924    ethumb_file_free(client->ethumb);
1925 }
1926
1927 /**
1928  * Set a defined path and key to store the thumbnail.
1929  *
1930  * If not explicitly given, the thumbnail path will be auto-generated
1931  * by ethumb_client_thumb_exists() or server using configured
1932  * parameters like size, aspect and category.
1933  *
1934  * Set these to @c NULL to forget previously given values. After
1935  * ethumb_client_file_set() these values will be reset to @c NULL.
1936  *
1937  * @param client the client instance to use. Must @b not be @c
1938  *        NULL. May be pending connected (can be called before @c
1939  *        connected_cb)
1940  * @param path force generated thumbnail to the exact given path. If
1941  *        @c NULL, then reverts back to auto-generation.
1942  * @param key force generated thumbnail to the exact given key. If
1943  *        @c NULL, then reverts back to auto-generation.
1944  */
1945 EAPI void
1946 ethumb_client_thumb_path_set(Ethumb_Client *client, const char *path, const char *key)
1947 {
1948    EINA_SAFETY_ON_NULL_RETURN(client);
1949
1950    ethumb_thumb_path_set(client->ethumb, path, key);
1951 }
1952
1953 /**
1954  * Get the configured thumbnail path.
1955  *
1956  * This returns the value set with ethumb_client_thumb_path_set() or
1957  * auto-generated by ethumb_client_thumb_exists() if it was not set.
1958  *
1959  * @param client the client instance to use. Must @b not be @c
1960  *        NULL. May be pending connected (can be called before @c
1961  *        connected_cb)
1962  * @param path where to return configured path. May be @c NULL.  If
1963  *        there was no path configured with
1964  *        ethumb_client_thumb_path_set() and
1965  *        ethumb_client_thumb_exists() was not called, then it will
1966  *        probably return @c NULL. If not @c NULL, then it will be a
1967  *        pointer to a stringshared instance, but @b no references are
1968  *        added (do it with eina_stringshare_ref())!
1969  * @param key where to return configured key. May be @c NULL.  If
1970  *        there was no key configured with
1971  *        ethumb_client_thumb_key_set() and
1972  *        ethumb_client_thumb_exists() was not called, then it will
1973  *        probably return @c NULL. If not @c NULL, then it will be a
1974  *        pointer to a stringshared instance, but @b no references are
1975  *        added (do it with eina_stringshare_ref())!
1976  */
1977 EAPI void
1978 ethumb_client_thumb_path_get(Ethumb_Client *client, const char **path, const char **key)
1979 {
1980    if (path) *path = NULL;
1981    if (key) *key = NULL;
1982    EINA_SAFETY_ON_NULL_RETURN(client);
1983
1984    ethumb_thumb_path_get(client->ethumb, path, key);
1985 }
1986
1987 /**
1988  * Checks whenever file already exists (locally!)
1989  *
1990  * This will check locally (not calling server) if thumbnail already
1991  * exists or not, also calculating the thumbnail path. See
1992  * ethumb_client_thumb_path_get(). Path must be configured with
1993  * ethumb_client_file_set() before using it and the last set file will
1994  * be used!
1995  *
1996  * @param client client instance. Must @b not be @c NULL and client
1997  *        must be configured with ethumb_client_file_set().
1998  *
1999  * @return @c EINA_TRUE if it exists, @c EINA_FALSE otherwise.
2000  */
2001 EAPI Eina_Bool
2002 ethumb_client_thumb_exists(Ethumb_Client *client)
2003 {
2004    EINA_SAFETY_ON_NULL_RETURN_VAL(client, 0);
2005
2006    return ethumb_exists(client->ethumb);
2007 }
2008
2009 /**
2010  * Ask server to generate thumbnail.
2011  *
2012  * This process is asynchronous and will report back from main loop
2013  * using @a generated_cb. One can cancel this request by calling
2014  * ethumb_client_generate_cancel() or
2015  * ethumb_client_generate_cancel_all(), but not that request might be
2016  * processed by server already and no generated files will be removed
2017  * if that is the case.
2018  *
2019  * This will not check if file already exists, this should be done by
2020  * explicitly calling ethumb_client_thumb_exists(). That is, this
2021  * function will override any existing thumbnail.
2022  *
2023  * @param client client instance. Must @b not be @c NULL and client
2024  *        must be connected (after connected_cb is called).
2025  * @param generated_cb function to report generation results.
2026  * @param data context argument to give back to @a generated_cb. May
2027  *        be @c NULL.
2028  * @param data context to give back to @a generate_cb. May be @c
2029  *        NULL.
2030  * @param free_data used to release @a data resources after @a
2031  *        generated_cb is called or user calls
2032  *        ethumb_client_disconnect().
2033  *
2034  * @return identifier or -1 on error. If -1 is returned (error) then
2035  *         @a free_data is @b not called!
2036  *
2037  * @see ethumb_client_connect()
2038  * @see ethumb_client_file_set()
2039  * @see ethumb_client_thumb_exists()
2040  * @see ethumb_client_generate_cancel()
2041  * @see ethumb_client_generate_cancel_all()
2042  */
2043 EAPI int
2044 ethumb_client_generate(Ethumb_Client *client, Ethumb_Client_Generate_Cb generated_cb, const void *data, Eina_Free_Cb free_data)
2045 {
2046    const char *file, *key, *thumb, *thumb_key;
2047    int id;
2048    EINA_SAFETY_ON_NULL_RETURN_VAL(client, -1);
2049    EINA_SAFETY_ON_FALSE_RETURN_VAL(client->connected, -1);
2050
2051    ethumb_file_get(client->ethumb, &file, &key);
2052    if (!file)
2053      {
2054         ERR("no file set.");
2055         return -1;
2056      }
2057
2058    ethumb_thumb_path_get(client->ethumb, &thumb, &thumb_key);
2059
2060    if (client->ethumb_dirty)
2061      ethumb_client_ethumb_setup(client);
2062    id = _ethumb_client_queue_add(client, file, key, thumb, thumb_key,
2063                                  generated_cb, data, free_data);
2064
2065    return id;
2066 }