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