efl
2369 строк · 71.8 Кб
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 library is free software; you can redistribute it and/or
10* modify it under the terms of the GNU Lesser General Public
11* License as published by the Free Software Foundation; either
12* version 2.1 of the License, or (at your option) any later version.
13*
14* This library is distributed in the hope that it will be useful,
15* but WITHOUT ANY WARRANTY; without even the implied warranty of
16* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17* Lesser General Public License for more details.
18*
19* You should have received a copy of the GNU Lesser General Public
20* License along with this library;
21* if not, see <http://www.gnu.org/licenses/>.
22*
23* @author Rafael Antognolli <antognolli@profusion.mobi>
24* @author Gustavo Sverzut Barbieri <barbieri@profusion.mobi>
25*/
26
27/**
28* @page tutorial_ethumb_client Client-Server Thumbnailing Tutorial
29*
30* @section tutorial_ethumb_client_intro Introduction
31*
32* Ethumb provides both in process and client-server generation
33* methods. The advantage of the client-server method is that current
34* process will not do the heavy operations that may block, stopping
35* animations and other user interactions. Instead the client library
36* will configure a local #Ethumb instance and mirrors/controls a
37* remote process using DBus. The simple operations like most setters
38* and getters as well as checking for thumbnail existence
39* (ethumb_client_thumb_exists()) is done locally, while expensive
40* (ethumb_client_generate()) are done on server and then reported
41* back to application when it is finished (both success or failure).
42*
43* @section tutorial_ethumb_client_connect Connecting to Server
44*
45* TODO
46*
47* @section tutorial_ethumb_client_generate Requesting Thumbnail Generation
48*
49* TODO
50*
51* @section tutorial_ethumb_client_setup Setup Extra Thumbnail Parameters
52*
53* TODO
54*
55* @section tutorial_ethumb_client_server_died Handle Server Disconnection
56*
57* TODO
58*/
59
60/**
61* @cond LOCAL
62*/
63
64#ifdef HAVE_CONFIG_H65# include "config.h"66#endif67
68#include <stdio.h>69#include <stdlib.h>70#include <limits.h>71#include <string.h>72#include <unistd.h>73#include <errno.h>74#include <sys/types.h>75#include <stdbool.h>76
77#include <Eina.h>78#include <eina_safety_checks.h>79#include <Eldbus.h>80#include <Ethumb.h>81#include <Ecore.h>82
83#include "Ethumb_Client.h"84
85#ifndef PATH_MAX86#define PATH_MAX 409687#endif88
89#define MAX_ID 200000090
91static int _log_dom = -1;92#define DBG(...) EINA_LOG_DOM_DBG(_log_dom, __VA_ARGS__)93#define INF(...) EINA_LOG_DOM_INFO(_log_dom, __VA_ARGS__)94#define WRN(...) EINA_LOG_DOM_WARN(_log_dom, __VA_ARGS__)95#define ERR(...) EINA_LOG_DOM_ERR(_log_dom, __VA_ARGS__)96#define CRI(...) EINA_LOG_DOM_CRIT(_log_dom, __VA_ARGS__)97
98struct _Ethumb_Client99{
100Ethumb *ethumb;101int id_count;102Ethumb *old_ethumb_conf;103Eldbus_Connection *conn;104struct105{106Ethumb_Client_Connect_Cb cb;107void *data;108Eina_Free_Cb free_data;109} connect;110Eina_List *pending_add;111Eina_List *pending_remove;112Eina_List *pending_gen;113Eina_List *dbus_pending;114struct115{116Ethumb_Client_Die_Cb cb;117void *data;118Eina_Free_Cb free_data;119} die;120Eldbus_Proxy *proxy;121Eldbus_Signal_Handler *generated_sig_handler;122EINA_REFCOUNT;123Eina_Bool connected : 1;124Eina_Bool server_started : 1;125Eina_Bool invalid : 1;126};127
128struct _ethumb_pending_add129{
130int32_t id;131const char *file;132const char *key;133const char *thumb;134const char *thumb_key;135Ethumb_Client_Generate_Cb generated_cb;136void *data;137Eina_Free_Cb free_data;138Eldbus_Pending *pending_call;139Ethumb_Client *client;140};141
142struct _ethumb_pending_remove143{
144int32_t id;145Ethumb_Client_Generate_Cancel_Cb cancel_cb;146void *data;147Eina_Free_Cb free_data;148Eldbus_Pending *pending_call;149Ethumb_Client *client;150};151
152struct _ethumb_pending_gen153{
154int32_t id;155const char *file;156const char *key;157const char *thumb;158const char *thumb_key;159Ethumb_Client_Generate_Cb generated_cb;160void *data;161Eina_Free_Cb free_data;162};163
164typedef struct _Ethumb_Async_Exists Ethumb_Async_Exists;165
166struct _Ethumb_Async_Exists167{
168const char *path;169
170Ethumb *dup; /* We will work on that one to prevent race and lock */171
172Eina_List *callbacks;173Ecore_Thread *thread;174};175
176struct _Ethumb_Exists177{
178Ethumb_Async_Exists *parent;179Ethumb_Client *client;180Ethumb *dup; /* We don't want to loose parameters so keep them around */181
182Ethumb_Client_Thumb_Exists_Cb exists_cb;183const void *data;184};185
186static const char _ethumb_dbus_bus_name[] = "org.enlightenment.Ethumb";187static const char _ethumb_dbus_interface[] = "org.enlightenment.Ethumb";188static const char _ethumb_dbus_objects_interface[] = "org.enlightenment.Ethumb.objects";189static const char _ethumb_dbus_path[] = "/org/enlightenment/Ethumb";190
191static int _initcount = 0;192static Eina_Hash *_exists_request = NULL;193
194static void _ethumb_client_generated_cb(void *data, const Eldbus_Message *msg);195static void _ethumb_client_call_new(Ethumb_Client *client);196static void _ethumb_client_name_owner_changed(void *context, const char *bus, const char *old_id, const char *new_id);197
198static void199_ethumb_client_free(Ethumb_Client *client)200{
201void *data;202Eldbus_Object *obj;203
204if (client->invalid)205return;206
207if (client->dbus_pending)208{209Eldbus_Pending *pending;210EINA_LIST_FREE(client->dbus_pending, pending)211eldbus_pending_cancel(pending);212}213
214client->invalid = EINA_TRUE;215EINA_LIST_FREE(client->pending_add, data)216{217struct _ethumb_pending_add *pending = data;218if (pending->pending_call)219{220Eldbus_Pending *call = pending->pending_call;221
222pending->pending_call = NULL;223pending->client = NULL;224eldbus_pending_cancel(call);225}226else227{228pending->client = NULL;229free(pending);230}231}232
233EINA_LIST_FREE(client->pending_gen, data)234{235struct _ethumb_pending_gen *pending = data;236eina_stringshare_del(pending->file);237eina_stringshare_del(pending->key);238eina_stringshare_del(pending->thumb);239eina_stringshare_del(pending->thumb_key);240if (pending->free_data)241pending->free_data(pending->data);242free(pending);243}244
245EINA_LIST_FREE(client->pending_remove, data)246{247struct _ethumb_pending_remove *pending = data;248if (pending->free_data)249pending->free_data(pending->data);250if (pending->pending_call)251{252Eldbus_Pending *call = pending->pending_call;253
254pending->pending_call = NULL;255pending->client = NULL;256eldbus_pending_cancel(call);257}258else259{260pending->client = NULL;261free(pending);262}263}264
265if (client->old_ethumb_conf)266{267ethumb_free(client->old_ethumb_conf);268client->old_ethumb_conf = NULL;269}270
271if (client->ethumb)272{273ethumb_free(client->ethumb);274client->ethumb = NULL;275}276
277if (client->conn)278eldbus_name_owner_changed_callback_del(client->conn,279_ethumb_dbus_bus_name,280_ethumb_client_name_owner_changed,281client);282if (client->generated_sig_handler)283{284eldbus_signal_handler_del(client->generated_sig_handler);285client->generated_sig_handler = NULL;286}287if (client->proxy)288{289obj = eldbus_proxy_object_get(client->proxy);290eldbus_proxy_unref(client->proxy);291client->proxy = NULL;292if (obj) eldbus_object_unref(obj);293}294if (client->conn)295{296eldbus_connection_unref(client->conn);297client->conn = NULL;298}299
300if (client->connect.free_data)301client->connect.free_data(client->connect.data);302if (client->die.free_data)303client->die.free_data(client->die.data);304
305free(client);306}
307
308static void309_ethumb_async_delete(void *data)310{
311Ethumb_Async_Exists *async = data;312
313EINA_SAFETY_ON_FALSE_RETURN(async->callbacks == NULL);314EINA_SAFETY_ON_FALSE_RETURN(async->thread == NULL);315
316ethumb_free(async->dup);317eina_stringshare_del(async->path);318
319free(async);320}
321
322static void323_ethumb_client_name_owner_changed(void *context, const char *bus EINA_UNUSED, const char *old_id, const char *new_id)324{
325Ethumb_Client *client = context;326
327DBG("NameOwnerChanged from=[%s] to=[%s]", old_id, new_id);328if (new_id[0])329{330if (client->connected)331return;332
333client->connected = EINA_TRUE;334INF("Server connected");335_ethumb_client_call_new(client);336return;337}338INF("Server disconnected");339EINA_REFCOUNT_REF(client);340client->connected = EINA_FALSE;341if (client->die.cb)342{343client->die.cb(client->die.data, client);344client->die.cb = NULL;345}346if (client->die.free_data)347{348client->die.free_data(client->die.data);349client->die.free_data = NULL;350client->die.data = NULL;351}352EINA_REFCOUNT_UNREF(client) _ethumb_client_free(client);353}
354
355static void356_ethumb_client_report_connect(Ethumb_Client *client, Eina_Bool success)357{
358if (!client->connect.cb)359{360//ERR("already called?!");361return;362}363
364EINA_REFCOUNT_REF(client);365if (success)366INF("Success connecting to Ethumb server.");367else368ERR("Could not connect to Ethumb server.");369
370client->connect.cb(client->connect.data, client, success);371if (client->connect.free_data)372{373client->connect.free_data(client->connect.data);374client->connect.free_data = NULL;375}376client->connect.cb = NULL;377client->connect.data = NULL;378EINA_REFCOUNT_UNREF(client) _ethumb_client_free(client);379}
380
381static void382_ethumb_client_new_cb(void *data, const Eldbus_Message *msg, Eldbus_Pending *pending)383{
384const char *errname, *errmsg;385const char *opath;386Ethumb_Client *client = data;387Eldbus_Object *obj;388
389client->dbus_pending = eina_list_remove(client->dbus_pending, pending);390if (eldbus_message_error_get(msg, &errname, &errmsg))391{392ERR("Error: %s %s", errname, errmsg);393_ethumb_client_report_connect(client, 0);394return;395}396
397if (!eldbus_message_arguments_get(msg, "o", &opath))398{399ERR("Error: could not get entry contents");400_ethumb_client_report_connect(client, 0);401return;402}403
404if (client->generated_sig_handler)405{406eldbus_signal_handler_del(client->generated_sig_handler);407client->generated_sig_handler = NULL;408}409if (!client->proxy)410{411obj = eldbus_object_get(client->conn, _ethumb_dbus_bus_name, opath);412client->proxy = eldbus_proxy_get(obj, _ethumb_dbus_objects_interface);413}414client->generated_sig_handler =415eldbus_proxy_signal_handler_add(client->proxy, "generated",416_ethumb_client_generated_cb, client);417_ethumb_client_report_connect(client, 1);418}
419
420static void421_ethumb_client_call_new(Ethumb_Client *client)422{
423Eldbus_Message *msg;424Eldbus_Pending *pending;425msg = eldbus_message_method_call_new(_ethumb_dbus_bus_name,426_ethumb_dbus_path,427_ethumb_dbus_interface, "new");428pending = eldbus_connection_send(client->conn, msg,429_ethumb_client_new_cb, client, -1);430if (pending)431client->dbus_pending = eina_list_append(client->dbus_pending, pending);432}
433
434static void435_ethumb_client_exists_heavy(void *data, Ecore_Thread *thread EINA_UNUSED)436{
437Ethumb_Async_Exists *async = data;438
439ethumb_thumb_hash(async->dup);440}
441
442static void443_ethumb_client_exists_end(void *data, Ecore_Thread *thread EINA_UNUSED)444{
445Ethumb_Async_Exists *async = data;446Ethumb_Exists *cb;447
448EINA_LIST_FREE(async->callbacks, cb)449{450Ethumb *tmp;451
452ethumb_thumb_hash_copy(cb->dup, async->dup);453tmp = cb->client->ethumb;454cb->client->ethumb = cb->dup;455
456cb->exists_cb((void *)cb->data,457cb->client, cb,458ethumb_exists(cb->client->ethumb));459
460cb->client->ethumb = tmp;461EINA_REFCOUNT_UNREF(cb->client) _ethumb_client_free(cb->client);462ethumb_free(cb->dup);463free(cb);464}465
466async->thread = NULL;467
468eina_hash_del(_exists_request, async->path, async);469}
470
471/**
472* @endcond
473*/
474
475/**
476* @brief Initialize the Ethumb_Client library.
477*
478* @return 1 or greater on success, 0 on error.
479*
480* This function sets up all the Ethumb_Client module dependencies. It
481* returns 0 on failure (that is, when one of the dependency fails to
482* initialize), otherwise it returns the number of times it has
483* already been called.
484*
485* When Ethumb_Client is not used anymore, call
486* ethumb_client_shutdown() to shut down the Ethumb_Client library.
487*
488* @see ethumb_client_shutdown()
489* @see ethumb_client_connect()
490* @see @ref tutorial_ethumb_client
491*/
492EAPI int493ethumb_client_init(void)494{
495if (_initcount)496return ++_initcount;497
498if (!eina_init())499{500fprintf(stderr, "ERROR: Could not initialize log module.\n");501return 0;502}503_log_dom = eina_log_domain_register("ethumb_client", EINA_COLOR_YELLOW);504if (_log_dom < 0)505{506EINA_LOG_ERR("Could not register log domain: ethumb_client");507eina_shutdown();508return 0;509}510
511ethumb_init();512eldbus_init();513
514_exists_request = eina_hash_stringshared_new(_ethumb_async_delete);515
516return ++_initcount;517}
518
519/**
520* @brief Shut down the Ethumb_Client library.
521*
522* @return 0 when everything is shut down, 1 or greater if there are
523* other users of the Ethumb_Client library pending shutdown.
524*
525* This function shuts down the Ethumb_Client library. It returns 0
526* when it has been called the same number of times than
527* ethumb_client_init(). In that case it shut down all the
528* Ethumb_Client modules dependencies.
529*
530* Once this function succeeds (that is, @c 0 is returned), you must
531* not call any of the Eina function anymore. You must call
532* ethumb_client_init() again to use the Ethumb_Client functions
533* again.
534*/
535EAPI int536ethumb_client_shutdown(void)537{
538_initcount--;539if (_initcount > 0)540return _initcount;541
542/* should find a non racy solution to closing all pending exists request */543eina_hash_free(_exists_request);544_exists_request = NULL;545
546eldbus_shutdown();547ethumb_shutdown();548eina_log_domain_unregister(_log_dom);549_log_dom = -1;550eina_shutdown();551return _initcount;552}
553
554static void555_name_start(void *data EINA_UNUSED, const Eldbus_Message *msg, Eldbus_Pending *pending EINA_UNUSED)556{
557const char *name, *text;558if (eldbus_message_error_get(msg, &name, &text))559{560ERR("Starting ethumb failed %s %s", name, text);561return;562}563}
564
565/**
566* Connects to Ethumb server and return the client instance.
567*
568* This is the "constructor" of Ethumb_Client, where everything
569* starts.
570*
571* If server was down, it is tried to start it using DBus activation,
572* then the connection is retried.
573*
574* This call is asynchronous and will not block, instead it will be in
575* "not connected" state until @a connect_cb is called with either
576* success or failure. On failure, then no methods should be
577* called. On success you're now able to setup and then ask generation
578* of thumbnails.
579*
580* Usually you should listen for server death/disconenction with
581* ethumb_client_on_server_die_callback_set().
582*
583* @param connect_cb function to call to report connection success or
584* failure. Do not call any other ethumb_client method until
585* this function returns. The first received parameter is the
586* given argument @a data. Must @b not be @c NULL. This
587* function will not be called if user explicitly calls
588* ethumb_client_disconnect().
589* @param data context to give back to @a connect_cb. May be @c NULL.
590* @param free_data function used to release @a data resources, if
591* any. May be @c NULL. If this function exists, it will be
592* called immediately after @a connect_cb is called or if user
593* explicitly calls ethumb_client_disconnect() before such
594* (that is, don't rely on @a data after @a connect_cb was
595* called!)
596*
597* @return client instance or NULL if failed. If @a connect_cb is
598* missing it returns @c NULL. If it fail for other
599* conditions, @c NULL is also returned and @a connect_cb is
600* called with @c success=EINA_FALSE. The client instance is
601* not ready to be used until @a connect_cb is called.
602*/
603EAPI Ethumb_Client *604ethumb_client_connect(Ethumb_Client_Connect_Cb connect_cb, const void *data, Eina_Free_Cb free_data)605{
606Ethumb_Client *eclient;607
608EINA_SAFETY_ON_NULL_RETURN_VAL(connect_cb, NULL);609
610eclient = calloc(1, sizeof(*eclient));611if (!eclient)612{613ERR("could not allocate Ethumb_Client structure.");614goto err;615}616
617eclient->old_ethumb_conf = NULL;618eclient->connect.cb = connect_cb;619eclient->connect.data = (void *)data;620eclient->connect.free_data = free_data;621
622eclient->ethumb = ethumb_new();623if (!eclient->ethumb)624{625ERR("could not create ethumb handler.");626goto ethumb_new_err;627}628
629eclient->conn = eldbus_connection_get(ELDBUS_CONNECTION_TYPE_SESSION);630if (!eclient->conn)631{632ERR("could not connect to session bus.");633goto connection_err;634}635
636if (!eldbus_name_start(eclient->conn, _ethumb_dbus_bus_name, 0, _name_start, NULL))637{638ERR("Failed to start ethumb bus");639goto connection_err;640}641
642eldbus_name_owner_changed_callback_add(eclient->conn, _ethumb_dbus_bus_name,643_ethumb_client_name_owner_changed,644eclient, EINA_TRUE);645EINA_REFCOUNT_INIT(eclient);646
647return eclient;648
649connection_err:650ethumb_free(eclient->ethumb);651ethumb_new_err:652free(eclient);653err:654connect_cb((void *)data, NULL, EINA_FALSE);655if (free_data)656free_data((void *)data);657return NULL;658}
659
660/**
661* Disconnect the client, releasing all client resources.
662*
663* This is the destructor of Ethumb_Client, after it's disconnected
664* the client handle is now gone and should not be used.
665*
666* @param client client instance to be destroyed. Must @b not be @c
667* NULL.
668*/
669EAPI void670ethumb_client_disconnect(Ethumb_Client *client)671{
672EINA_SAFETY_ON_NULL_RETURN(client);673
674EINA_REFCOUNT_UNREF(client) _ethumb_client_free(client);675}
676
677/**
678* Sets the callback to report server died.
679*
680* When server dies there is nothing you can do, just release
681* resources with ethumb_client_disconnect() and probably try to
682* connect again.
683*
684* Usually you should set this callback and handle this case, it does
685* happen!
686*
687* @param client the client instance to monitor. Must @b not be @c
688* NULL.
689* @param server_die_cb function to call back when server dies. The
690* first parameter will be the argument @a data. May be @c
691* NULL.
692* @param data context to give back to @a server_die_cb. May be @c
693* NULL.
694* @param free_data used to release @a data resources after @a
695* server_die_cb is called or user calls
696* ethumb_client_disconnect().
697*/
698EAPI void699ethumb_client_on_server_die_callback_set(Ethumb_Client *client, Ethumb_Client_Die_Cb server_die_cb, const void *data, Eina_Free_Cb free_data)700{
701EINA_SAFETY_ON_NULL_RETURN(client);702
703if (client->die.free_data)704client->die.free_data(client->die.data);705
706client->die.cb = server_die_cb;707client->die.data = (void *)data;708client->die.free_data = free_data;709}
710
711/**
712* @cond LOCAL
713*/
714
715static void716_ethumb_client_ethumb_setup_cb(void *data, const Eldbus_Message *msg, Eldbus_Pending *pending)717{
718const char *errname, *errmsg;719Eina_Bool result = 0;720Ethumb_Client *client = data;721
722client->dbus_pending = eina_list_remove(client->dbus_pending, pending);723
724if (eldbus_message_error_get(msg, &errname, &errmsg))725{726ERR("Error: %s %s", errname, errmsg);727return;728}729
730if (!eldbus_message_arguments_get(msg, "b", &result))731{732ERR("Error getting arguments");733return;734}735EINA_SAFETY_ON_FALSE_RETURN(result);736}
737
738static const char *739_ethumb_client_dbus_get_bytearray(Eldbus_Message_Iter *array)740{
741int length;742const char *result;743
744if (eldbus_message_iter_fixed_array_get(array, 'y', &result, &length))745return eina_stringshare_add_length(result, length);746else747{748ERR("Not byte array. Signature: %s",749eldbus_message_iter_signature_get(array));750return NULL;751}752}
753
754static void755_ethumb_client_dbus_append_bytearray(Eldbus_Message_Iter *parent, const char *string)756{
757int i, size;758Eldbus_Message_Iter *array;759
760if (!string)761string = "";762
763array = eldbus_message_iter_container_new(parent, 'a', "y");764size = strlen(string) + 1;765for (i = 0; i < size; i++)766eldbus_message_iter_basic_append(array, 'y', string[i]);767eldbus_message_iter_container_close(parent, array);768}
769
770/**
771* @endcond
772*/
773
774static Eldbus_Message_Iter *775_setup_iterator_open(Eldbus_Message_Iter *array, Eldbus_Message_Iter **entry, const char *key, const char *type)776{
777Eldbus_Message_Iter *variant, *_struct;778eldbus_message_iter_arguments_append(array, "{sv}", &_struct);779eldbus_message_iter_basic_append(_struct, 's', key);780variant = eldbus_message_iter_container_new(_struct, 'v', type);781
782*entry = _struct;783return variant;784}
785
786static void787_setup_iterator_close(Eldbus_Message_Iter *array, Eldbus_Message_Iter *entry, Eldbus_Message_Iter *variant)788{
789eldbus_message_iter_container_close(entry, variant);790eldbus_message_iter_container_close(array, entry);791}
792
793/**
794* Send setup to server.
795*
796* This method is called automatically by ethumb_client_generate() if
797* any property was changed. No need to call it manually.
798*
799* @param client client instance. Must @b not be @c NULL and client
800* must be connected (after connected_cb is called).
801*/
802EAPI void803ethumb_client_ethumb_setup(Ethumb_Client *client)804{
805Eldbus_Message *msg;806Eldbus_Message_Iter *array, *main_iter;807Eldbus_Message_Iter *entry, *variant;808Eldbus_Message_Iter *sub_struct;809Ethumb *e = client->ethumb;810int tw, th, format, aspect, orientation, quality, compress;811float cx, cy;812const char *theme_file, *group, *swallow;813const char *directory, *category;814double video_time, video_start, video_interval;815unsigned int video_ntimes, video_fps, document_page;816Eldbus_Pending *pending;817
818EINA_SAFETY_ON_NULL_RETURN(client);819EINA_SAFETY_ON_FALSE_RETURN(client->connected);820
821msg = eldbus_proxy_method_call_new(client->proxy, "ethumb_setup");822main_iter = eldbus_message_iter_get(msg);823eldbus_message_iter_arguments_append(main_iter, "a{sv}", &array);824
825/* starting array elements */826variant = _setup_iterator_open(array, &entry, "size", "(ii)");827eldbus_message_iter_arguments_append(variant, "(ii)", &sub_struct);828ethumb_thumb_size_get(e, &tw, &th);829eldbus_message_iter_arguments_append(sub_struct, "ii", tw, th);830eldbus_message_iter_container_close(variant, sub_struct);831_setup_iterator_close(array, entry, variant);832
833variant = _setup_iterator_open(array, &entry, "format", "i");834format = ethumb_thumb_format_get(e);835eldbus_message_iter_arguments_append(variant, "i", format);836_setup_iterator_close(array, entry, variant);837
838variant = _setup_iterator_open(array, &entry, "aspect", "i");839aspect = ethumb_thumb_aspect_get(e);840eldbus_message_iter_arguments_append(variant, "i", aspect);841_setup_iterator_close(array, entry, variant);842
843variant = _setup_iterator_open(array, &entry, "orientation", "i");844orientation = ethumb_thumb_orientation_get(e);845eldbus_message_iter_arguments_append(variant, "i", orientation);846_setup_iterator_close(array, entry, variant);847
848variant = _setup_iterator_open(array, &entry, "crop", "(dd)");849eldbus_message_iter_arguments_append(variant, "(dd)", &sub_struct);850ethumb_thumb_crop_align_get(e, &cx, &cy);851eldbus_message_iter_arguments_append(sub_struct, "dd", (double)cx, (double)cy);852eldbus_message_iter_container_close(variant, sub_struct);853_setup_iterator_close(array, entry, variant);854
855variant = _setup_iterator_open(array, &entry, "quality", "i");856quality = ethumb_thumb_quality_get(e);857eldbus_message_iter_arguments_append(variant, "i", quality);858_setup_iterator_close(array, entry, variant);859
860variant = _setup_iterator_open(array, &entry, "compress", "i");861compress = ethumb_thumb_compress_get(e);862eldbus_message_iter_arguments_append(variant, "i", compress);863_setup_iterator_close(array, entry, variant);864
865variant = _setup_iterator_open(array, &entry, "frame", "(ayayay)");866eldbus_message_iter_arguments_append(variant, "(ayayay)", &sub_struct);867ethumb_frame_get(e, &theme_file, &group, &swallow);868_ethumb_client_dbus_append_bytearray(sub_struct, theme_file);869_ethumb_client_dbus_append_bytearray(sub_struct, group);870_ethumb_client_dbus_append_bytearray(sub_struct, swallow);871eldbus_message_iter_container_close(variant, sub_struct);872_setup_iterator_close(array, entry, variant);873
874variant = _setup_iterator_open(array, &entry, "directory", "ay");875directory = ethumb_thumb_dir_path_get(e);876_ethumb_client_dbus_append_bytearray(variant, directory);877_setup_iterator_close(array, entry, variant);878
879variant = _setup_iterator_open(array, &entry, "category", "ay");880category = ethumb_thumb_category_get(e);881_ethumb_client_dbus_append_bytearray(variant, category);882_setup_iterator_close(array, entry, variant);883
884variant = _setup_iterator_open(array, &entry, "video_time", "d");885video_time = ethumb_video_time_get(e);886eldbus_message_iter_arguments_append(variant, "d", video_time);887_setup_iterator_close(array, entry, variant);888
889variant = _setup_iterator_open(array, &entry, "video_start", "d");890video_start = ethumb_video_start_get(e);891eldbus_message_iter_arguments_append(variant, "d", video_start);892_setup_iterator_close(array, entry, variant);893
894variant = _setup_iterator_open(array, &entry, "video_interval", "d");895video_interval = ethumb_video_interval_get(e);896eldbus_message_iter_arguments_append(variant, "d", video_interval);897_setup_iterator_close(array, entry, variant);898
899variant = _setup_iterator_open(array, &entry, "video_ntimes", "u");900video_ntimes = ethumb_video_ntimes_get(e);901eldbus_message_iter_arguments_append(variant, "u", video_ntimes);902_setup_iterator_close(array, entry, variant);903
904variant = _setup_iterator_open(array, &entry, "video_fps", "u");905video_fps = ethumb_video_fps_get(e);906eldbus_message_iter_arguments_append(variant, "u", video_fps);907_setup_iterator_close(array, entry, variant);908
909variant = _setup_iterator_open(array, &entry, "document_page", "u");910document_page = ethumb_document_page_get(e);911eldbus_message_iter_arguments_append(variant, "u", document_page);912_setup_iterator_close(array, entry, variant);913
914eldbus_message_iter_container_close(main_iter, array);915
916pending = eldbus_proxy_send(client->proxy, msg,917_ethumb_client_ethumb_setup_cb, client, -1);918if (pending)919client->dbus_pending = eina_list_append(client->dbus_pending, pending);920}
921
922/**
923* @cond LOCAL
924*/
925static void926_ethumb_client_generated_cb(void *data, const Eldbus_Message *msg)927{
928int id = -1;929Ethumb_Client *client = data;930Eldbus_Message_Iter *thumb_iter;931Eldbus_Message_Iter *thumb_key_iter;932Eina_Bool success;933int found;934struct _ethumb_pending_gen *pending;935Eina_List *l;936
937if (!client) return;938if (!eldbus_message_arguments_get(msg, "iayayb", &id, &thumb_iter,939&thumb_key_iter, &success))940{941ERR("Error getting data from signal.");942return;943}944
945found = 0;946l = client->pending_gen;947while (l)948{949pending = l->data;950if (pending->id == id)951{952found = 1;953break;954}955l = l->next;956}957
958if (found)959{960const char *thumb = _ethumb_client_dbus_get_bytearray(thumb_iter);961const char *thumb_key = _ethumb_client_dbus_get_bytearray(thumb_key_iter);962
963client->pending_gen = eina_list_remove_list(client->pending_gen, l);964if (pending->generated_cb)965pending->generated_cb(pending->data, client, id,966pending->file, pending->key,967thumb, thumb_key,968success);969if (pending->free_data)970pending->free_data(pending->data);971eina_stringshare_del(pending->file);972eina_stringshare_del(pending->key);973eina_stringshare_del(pending->thumb);974eina_stringshare_del(pending->thumb_key);975eina_stringshare_del(thumb);976eina_stringshare_del(thumb_key);977free(pending);978}979}
980
981static void982_ethumb_client_queue_add_cb(void *data, const Eldbus_Message *msg, Eldbus_Pending *eldbus_pending EINA_UNUSED)983{
984const char *errname, *errmsg;985int32_t id;986struct _ethumb_pending_add *pending = data;987struct _ethumb_pending_gen *generating;988Ethumb_Client *client = pending->client;989
990pending->pending_call = NULL;991if (!client) goto end;992client->pending_add = eina_list_remove(client->pending_add, pending);993
994if (eldbus_message_error_get(msg, &errname, &errmsg))995{996ERR("Error: %s %s", errname, errmsg);997goto end;998}999
1000if (!eldbus_message_arguments_get(msg, "i", &id))1001{1002ERR("Error getting arguments.");1003goto end;1004}1005
1006
1007generating = calloc(1, sizeof(*generating));1008generating->id = id;1009generating->file = pending->file;1010generating->key = pending->key;1011generating->thumb = pending->thumb;1012generating->thumb_key = pending->thumb_key;1013generating->generated_cb = pending->generated_cb;1014generating->data = pending->data;1015generating->free_data = pending->free_data;1016client->pending_gen = eina_list_append(client->pending_gen, generating);1017
1018free(pending);1019return;1020
1021end:1022eina_stringshare_del(pending->file);1023eina_stringshare_del(pending->key);1024eina_stringshare_del(pending->thumb);1025eina_stringshare_del(pending->thumb_key);1026if (pending->free_data)1027pending->free_data(pending->data);1028free(pending);1029}
1030
1031static int1032_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)1033{
1034Eldbus_Message *msg;1035Eldbus_Message_Iter *main_itr;1036struct _ethumb_pending_add *pending;1037
1038pending = calloc(1, sizeof(*pending));1039pending->id = client->id_count;1040pending->file = eina_stringshare_add(file);1041pending->key = eina_stringshare_add(key);1042pending->thumb = eina_stringshare_add(thumb);1043pending->thumb_key = eina_stringshare_add(thumb_key);1044pending->generated_cb = generated_cb;1045pending->data = (void *)data;1046pending->free_data = free_data;1047pending->client = client;1048
1049client->id_count = (client->id_count + 1) % MAX_ID;1050
1051msg = eldbus_proxy_method_call_new(client->proxy, "queue_add");1052main_itr = eldbus_message_iter_get(msg);1053eldbus_message_iter_basic_append(main_itr, 'i', pending->id);1054_ethumb_client_dbus_append_bytearray(main_itr, file);1055_ethumb_client_dbus_append_bytearray(main_itr, key);1056_ethumb_client_dbus_append_bytearray(main_itr, thumb);1057_ethumb_client_dbus_append_bytearray(main_itr, thumb_key);1058
1059client->pending_add = eina_list_append(client->pending_add, pending);1060
1061pending->pending_call = eldbus_proxy_send(client->proxy, msg,1062_ethumb_client_queue_add_cb,1063pending, -1);1064
1065return pending->id;1066}
1067
1068static void1069_ethumb_client_queue_remove_cb(void *data, const Eldbus_Message *msg, Eldbus_Pending *eldbus_pending EINA_UNUSED)1070{
1071Eina_Bool success = EINA_FALSE;1072struct _ethumb_pending_remove *pending = data;1073Ethumb_Client *client = pending->client;1074const char *errname, *errmsg;1075
1076pending->pending_call = NULL;1077if (!client) goto end;1078client->pending_remove = eina_list_remove(client->pending_remove, pending);1079
1080if (eldbus_message_error_get(msg, &errname, &errmsg))1081{1082ERR("Error: %s %s", errname, errmsg);1083goto end;1084}1085
1086if (!eldbus_message_arguments_get(msg, "b", &success))1087{1088ERR("Error getting arguments.");1089goto end;1090}1091
1092end:1093if (pending->cancel_cb)1094pending->cancel_cb(pending->data, success);1095if (pending->free_data)1096pending->free_data(pending->data);1097free(pending);1098}
1099
1100/**
1101* @endcond
1102*/
1103
1104/**
1105* Ask server to cancel generation of thumbnail.
1106*
1107* @param client client instance. Must @b not be @c NULL and client
1108* must be connected (after connected_cb is called).
1109* @param id valid id returned by ethumb_client_generate()
1110* @param cancel_cb function to report cancellation results.
1111* @param data context argument to give back to @a cancel_cb. May be
1112* @c NULL.
1113* @param data context to give back to @a cancel_cb. May be @c
1114* NULL.
1115* @param free_data used to release @a data resources after @a
1116* cancel_cb is called or user calls
1117* ethumb_client_disconnect().
1118*/
1119EAPI void1120ethumb_client_generate_cancel(Ethumb_Client *client, int id, Ethumb_Client_Generate_Cancel_Cb cancel_cb, const void *data, Eina_Free_Cb free_data)1121{
1122struct _ethumb_pending_remove *pending;1123Eina_List *l;1124int found;1125int32_t id32 = id;1126EINA_SAFETY_ON_NULL_RETURN(client);1127EINA_SAFETY_ON_FALSE_RETURN(id >= 0);1128
1129pending = calloc(1, sizeof(*pending));1130pending->id = id;1131pending->cancel_cb = cancel_cb;1132pending->data = (void *)data;1133pending->free_data = free_data;1134pending->client = client;1135
1136pending->pending_call =1137eldbus_proxy_call(client->proxy, "queue_remove",1138_ethumb_client_queue_remove_cb, pending, -1,1139"i", pending->id);1140client->pending_remove = eina_list_append(client->pending_remove, pending);1141
1142/*1143* Check if answer was not received yet cancel it
1144* callback of queue_add will be called with a error msg
1145* and data will be freed
1146*/
1147found = 0;1148l = client->pending_add;1149while (l)1150{1151struct _ethumb_pending_add *pending_add = l->data;1152if (pending_add->id != id32)1153{1154l = l->next;1155continue;1156}1157if (pending_add->pending_call)1158{1159Eldbus_Pending *call = pending_add->pending_call;1160
1161pending_add->pending_call = NULL;1162eldbus_pending_cancel(call);1163}1164found = 1;1165break;1166}1167
1168if (found)1169return;1170
1171//if already received answer only free memory1172l = client->pending_gen;1173while (l)1174{1175struct _ethumb_pending_gen *pending_gen = l->data;1176if (pending_gen->id != id32)1177{1178l = l->next;1179continue;1180}1181client->pending_gen = eina_list_remove_list(client->pending_gen, l);1182eina_stringshare_del(pending_gen->file);1183eina_stringshare_del(pending_gen->key);1184eina_stringshare_del(pending_gen->thumb);1185eina_stringshare_del(pending_gen->thumb_key);1186if (pending_gen->free_data)1187pending_gen->free_data(pending_gen->data);1188free(pending_gen);1189break;1190}1191}
1192
1193/**
1194* Ask server to cancel generation of all thumbnails.
1195*
1196* @param client client instance. Must @b not be @c NULL and client
1197* must be connected (after connected_cb is called).
1198*
1199* @see ethumb_client_generate_cancel()
1200*/
1201EAPI void1202ethumb_client_generate_cancel_all(Ethumb_Client *client)1203{
1204void *data;1205EINA_SAFETY_ON_NULL_RETURN(client);1206
1207EINA_LIST_FREE(client->pending_add, data)1208{1209struct _ethumb_pending_add *pending = data;1210if (pending->pending_call)1211eldbus_pending_cancel(pending->pending_call);1212pending->pending_call = NULL;1213pending->client = NULL;1214free(pending);1215}1216
1217EINA_LIST_FREE(client->pending_gen, data)1218{1219struct _ethumb_pending_gen *pending = data;1220eina_stringshare_del(pending->file);1221eina_stringshare_del(pending->key);1222eina_stringshare_del(pending->thumb);1223eina_stringshare_del(pending->thumb_key);1224if (pending->free_data)1225pending->free_data(pending->data);1226free(pending);1227}1228
1229eldbus_proxy_call(client->proxy, "queue_clear", NULL, NULL, -1, "");1230}
1231
1232/**
1233* Configure future requests to use FreeDesktop.Org preset.
1234*
1235* This is a preset to provide freedesktop.org (fdo) standard
1236* compliant thumbnails. That is, files are stored as JPEG under
1237* ~/.thumbnails/SIZE, with size being either normal (128x128) or
1238* large (256x256).
1239*
1240* @param client the client instance to use. Must @b not be @c
1241* NULL. May be pending connected (can be called before @c
1242* connected_cb)
1243* @param s size identifier, either #ETHUMB_THUMB_NORMAL (0) or
1244* #ETHUMB_THUMB_LARGE (1).
1245*
1246* @see ethumb_client_size_set()
1247* @see ethumb_client_aspect_set()
1248* @see ethumb_client_crop_align_set()
1249* @see ethumb_client_category_set()
1250* @see ethumb_client_dir_path_set()
1251*/
1252EAPI void1253ethumb_client_fdo_set(Ethumb_Client *client, Ethumb_Thumb_FDO_Size s)1254{
1255EINA_SAFETY_ON_NULL_RETURN(client);1256
1257if (!client->old_ethumb_conf)1258client->old_ethumb_conf = ethumb_dup(client->ethumb);1259ethumb_thumb_fdo_set(client->ethumb, s);1260}
1261
1262/**
1263* Configure future request to use custom size.
1264*
1265* @param client the client instance to use. Must @b not be @c
1266* NULL. May be pending connected (can be called before @c
1267* connected_cb)
1268* @param tw width, default is 128.
1269* @param th height, default is 128.
1270*/
1271EAPI void1272ethumb_client_size_set(Ethumb_Client *client, int tw, int th)1273{
1274EINA_SAFETY_ON_NULL_RETURN(client);1275
1276if (!client->old_ethumb_conf)1277client->old_ethumb_conf = ethumb_dup(client->ethumb);1278ethumb_thumb_size_set(client->ethumb, tw, th);1279}
1280
1281/**
1282* Retrieve future request to use custom size.
1283*
1284* @param client the client instance to use. Must @b not be @c
1285* NULL. May be pending connected (can be called before @c
1286* connected_cb)
1287* @param tw where to return width. May be @c NULL.
1288* @param th where to return height. May be @c NULL.
1289*/
1290EAPI void1291ethumb_client_size_get(const Ethumb_Client *client, int *tw, int *th)1292{
1293if (tw) *tw = 0;1294if (th) *th = 0;1295EINA_SAFETY_ON_NULL_RETURN(client);1296
1297ethumb_thumb_size_get(client->ethumb, tw, th);1298}
1299
1300/**
1301* Configure format to use for future requests.
1302*
1303* @param client the client instance to use. Must @b not be @c
1304* NULL. May be pending connected (can be called before @c
1305* connected_cb)
1306* @param f format identifier to use, either #ETHUMB_THUMB_FDO (0),
1307* #ETHUMB_THUMB_JPEG (1) or #ETHUMB_THUMB_EET (2). Default is FDO.
1308*/
1309EAPI void1310ethumb_client_format_set(Ethumb_Client *client, Ethumb_Thumb_Format f)1311{
1312EINA_SAFETY_ON_NULL_RETURN(client);1313
1314if (!client->old_ethumb_conf)1315client->old_ethumb_conf = ethumb_dup(client->ethumb);1316ethumb_thumb_format_set(client->ethumb, f);1317}
1318
1319/**
1320* Retrieve format to use for future requests.
1321*
1322* @param client the client instance to use. Must @b not be @c
1323* NULL. May be pending connected (can be called before @c
1324* connected_cb)
1325*
1326* @return format identifier to use, either #ETHUMB_THUMB_FDO (0),
1327* #ETHUMB_THUMB_JPEG (1) or #ETHUMB_THUMB_EET (2).
1328*/
1329EAPI Ethumb_Thumb_Format
1330ethumb_client_format_get(const Ethumb_Client *client)1331{
1332EINA_SAFETY_ON_NULL_RETURN_VAL(client, 0);1333
1334return ethumb_thumb_format_get(client->ethumb);1335}
1336
1337/**
1338* Configure aspect mode to use.
1339*
1340* If aspect is kept (#ETHUMB_THUMB_KEEP_ASPECT), then image will be
1341* rescaled so the largest dimension is not bigger than it's specified
1342* size (see ethumb_client_size_get()) and the other dimension is
1343* resized in the same proportion. Example: size is 256x256, image is
1344* 1000x500, resulting thumbnail is 256x128.
1345*
1346* If aspect is ignored (#ETHUMB_THUMB_IGNORE_ASPECT), then image will
1347* be distorted to match required thumbnail size. Example: size is
1348* 256x256, image is 1000x500, resulting thumbnail is 256x256.
1349*
1350* If crop is required (#ETHUMB_THUMB_CROP), then image will be
1351* cropped so the smallest dimension is not bigger than its specified
1352* size (see ethumb_client_size_get()) and the other dimension will
1353* overflow, not being visible in the final image. How it will
1354* overflow is speficied by ethumb_client_crop_align_set()
1355* alignment. Example: size is 256x256, image is 1000x500, crop
1356* alignment is 0.5, 0.5, resulting thumbnail is 256x256 with 250
1357* pixels from left and 250 pixels from right being lost, that is just
1358* the 500x500 central pixels of image will be considered for scaling.
1359*
1360* @param client the client instance to use. Must @b not be @c
1361* NULL. May be pending connected (can be called before @c
1362* connected_cb)
1363* @param a aspect mode identifier, either #ETHUMB_THUMB_KEEP_ASPECT (0),
1364* #ETHUMB_THUMB_IGNORE_ASPECT (1) or #ETHUMB_THUMB_CROP (2).
1365*/
1366EAPI void1367ethumb_client_aspect_set(Ethumb_Client *client, Ethumb_Thumb_Aspect a)1368{
1369EINA_SAFETY_ON_NULL_RETURN(client);1370
1371if (!client->old_ethumb_conf)1372client->old_ethumb_conf = ethumb_dup(client->ethumb);1373ethumb_thumb_aspect_set(client->ethumb, a);1374}
1375
1376/**
1377* Get current aspect in use for requests.
1378*
1379* @param client the client instance to use. Must @b not be @c
1380* NULL. May be pending connected (can be called before @c
1381* connected_cb)
1382*
1383* @return aspect in use for future requests.
1384*/
1385EAPI Ethumb_Thumb_Aspect
1386ethumb_client_aspect_get(const Ethumb_Client *client)1387{
1388EINA_SAFETY_ON_NULL_RETURN_VAL(client, 0);1389
1390return ethumb_thumb_aspect_get(client->ethumb);1391}
1392
1393/**
1394* Configure orientation to use for future requests.
1395*
1396* Default value is #ETHUMB_THUMB_ORIENT_ORIGINAL: metadata from the file
1397* will be used to orient pixel data.
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 o format identifier to use, either #ETHUMB_THUMB_ORIENT_NONE (0),
1403* #ETHUMB_THUMB_ROTATE_90_CW (1), #ETHUMB_THUMB_ROTATE_180 (2),
1404* #ETHUMB_THUMB_ROTATE_90_CCW (3), #ETHUMB_THUMB_FLIP_HORIZONTAL (4),
1405* #ETHUMB_THUMB_FLIP_VERTICAL (5), #ETHUMB_THUMB_FLIP_TRANSPOSE (6),
1406* #ETHUMB_THUMB_FLIP_TRANSVERSE (7) or #ETHUMB_THUMB_ORIENT_ORIGINAL
1407* (8). Default is ORIGINAL.
1408*/
1409EAPI void1410ethumb_client_orientation_set(Ethumb_Client *client, Ethumb_Thumb_Orientation o)1411{
1412EINA_SAFETY_ON_NULL_RETURN(client);1413
1414if (!client->old_ethumb_conf)1415client->old_ethumb_conf = ethumb_dup(client->ethumb);1416ethumb_thumb_orientation_set(client->ethumb, o);1417}
1418
1419/**
1420* Get current orientation in use for requests.
1421*
1422* @param client the client instance to use. Must @b not be @c
1423* NULL. May be pending connected (can be called before @c
1424* connected_cb)
1425*
1426* @return orientation in use for future requests.
1427*/
1428EAPI Ethumb_Thumb_Orientation
1429ethumb_client_orientation_get(const Ethumb_Client *client)1430{
1431EINA_SAFETY_ON_NULL_RETURN_VAL(client, 0);1432
1433return ethumb_thumb_orientation_get(client->ethumb);1434}
1435
1436/**
1437* Configure crop alignment in use for future requests.
1438*
1439* @param client the client instance to use. Must @b not be @c
1440* NULL. May be pending connected (can be called before @c
1441* connected_cb)
1442* @param x horizontal alignment. 0.0 means left side will be visible
1443* or right side is being lost. 1.0 means right side will be
1444* visible or left side is being lost. 0.5 means just center is
1445* visible, both sides will be lost. Default is 0.5.
1446* @param y vertical alignment. 0.0 is top visible, 1.0 is bottom
1447* visible, 0.5 is center visible. Default is 0.5
1448*/
1449EAPI void1450ethumb_client_crop_align_set(Ethumb_Client *client, float x, float y)1451{
1452EINA_SAFETY_ON_NULL_RETURN(client);1453
1454if (!client->old_ethumb_conf)1455client->old_ethumb_conf = ethumb_dup(client->ethumb);1456ethumb_thumb_crop_align_set(client->ethumb, x, y);1457}
1458
1459/**
1460* Get current crop alignment in use for requests.
1461*
1462* @param client the client instance to use. Must @b not be @c
1463* NULL. May be pending connected (can be called before @c
1464* connected_cb)
1465* @param x where to return horizontal alignment. May be @c NULL.
1466* @param y where to return vertical alignment. May be @c NULL.
1467*/
1468EAPI void1469ethumb_client_crop_align_get(const Ethumb_Client *client, float *x, float *y)1470{
1471if (x) *x = 0.0;1472if (y) *y = 0.0;1473EINA_SAFETY_ON_NULL_RETURN(client);1474
1475ethumb_thumb_crop_align_get(client->ethumb, x, y);1476}
1477
1478/**
1479* Configure quality to be used in thumbnails.
1480*
1481* @param client the client instance to use. Must @b not be @c
1482* NULL. May be pending connected (can be called before @c
1483* connected_cb)
1484* @param quality value from 0 to 100, default is 80. The effect
1485* depends on the format being used, PNG will not use it.
1486*/
1487EAPI void1488ethumb_client_quality_set(Ethumb_Client *client, int quality)1489{
1490EINA_SAFETY_ON_NULL_RETURN(client);1491
1492ethumb_thumb_quality_set(client->ethumb, quality);1493}
1494
1495/**
1496* Get quality to be used in thumbnails.
1497*
1498* @param client the client instance to use. Must @b not be @c
1499* NULL. May be pending connected (can be called before @c
1500* connected_cb)
1501*
1502* @return quality value from 0 to 100, default is 80. The effect
1503* depends on the format being used, PNG will not use it.
1504*/
1505EAPI int1506ethumb_client_quality_get(const Ethumb_Client *client)1507{
1508EINA_SAFETY_ON_NULL_RETURN_VAL(client, 0);1509
1510return ethumb_thumb_quality_get(client->ethumb);1511}
1512
1513/**
1514* Configure compression level used in requests.
1515*
1516* @param client the client instance to use. Must @b not be @c
1517* NULL. May be pending connected (can be called before @c
1518* connected_cb)
1519* @param compress value from 0 to 9, default is 9. The effect
1520* depends on the format being used, JPEG will not use it.
1521*/
1522EAPI void1523ethumb_client_compress_set(Ethumb_Client *client, int compress)1524{
1525EINA_SAFETY_ON_NULL_RETURN(client);1526
1527ethumb_thumb_compress_set(client->ethumb, compress);1528}
1529
1530/**
1531* Get compression level used in requests.
1532*
1533* @param client the client instance to use. Must @b not be @c
1534* NULL. May be pending connected (can be called before @c
1535* connected_cb)
1536*
1537* @return compress value from 0 to 9, default is 9. The effect
1538* depends on the format being used, JPEG will not use it.
1539*/
1540EAPI int1541ethumb_client_compress_get(const Ethumb_Client *client)1542{
1543EINA_SAFETY_ON_NULL_RETURN_VAL(client, 0);1544
1545return ethumb_thumb_compress_get(client->ethumb);1546}
1547
1548/**
1549* Set frame to apply to future thumbnails.
1550*
1551* This will create an edje object that will have image swallowed
1552* in. This can be used to simulate Polaroid or wood frames in the
1553* generated image. Remeber it is bad to modify the original contents
1554* of thumbnails, but sometimes it's useful to have it composited and
1555* avoid runtime overhead.
1556*
1557* @param client the client instance to use. Must @b not be @c
1558* NULL. May be pending connected (can be called before @c
1559* connected_cb)
1560* @param file file path to edje.
1561* @param group group inside edje to use.
1562* @param swallow name of swallow part.
1563*
1564* @return @c EINA_TRUE on success, @c EINA_FALSE on failure.
1565*/
1566EAPI Eina_Bool
1567ethumb_client_frame_set(Ethumb_Client *client, const char *file, const char *group, const char *swallow)1568{
1569EINA_SAFETY_ON_NULL_RETURN_VAL(client, 0);1570
1571if (!client->old_ethumb_conf)1572client->old_ethumb_conf = ethumb_dup(client->ethumb);1573return ethumb_frame_set(client->ethumb, file, group, swallow);1574}
1575
1576/**
1577* Configure where to store thumbnails in future requests.
1578*
1579* This value will be used to generate thumbnail paths, that is, it
1580* will be used when ethumb_client_thumb_path_set() was not called
1581* after last ethumb_client_file_set().
1582*
1583* Note that this is the base, a category is added to this path as a
1584* sub directory. This is not the final directory where files are
1585* stored, the thumbnail system will account @b category as well, see
1586* ethumb_client_category_set().
1587*
1588* As other options, this value will only be applied to future
1589* requests.
1590*
1591* @param client the client instance to use. Must @b not be @c
1592* NULL. May be pending connected (can be called before @c
1593* connected_cb)
1594* @param path base directory where to store thumbnails. Default is
1595* ~/.thumbnails
1596*
1597* @see ethumb_client_category_set()
1598*/
1599EAPI void1600ethumb_client_dir_path_set(Ethumb_Client *client, const char *path)1601{
1602EINA_SAFETY_ON_NULL_RETURN(client);1603
1604if (!client->old_ethumb_conf)1605client->old_ethumb_conf = ethumb_dup(client->ethumb);1606ethumb_thumb_dir_path_set(client->ethumb, path);1607}
1608
1609/**
1610* Get base directory path where to store thumbnails.
1611*
1612* @param client the client instance to use. Must @b not be @c
1613* NULL. May be pending connected (can be called before @c
1614* connected_cb)
1615*
1616* @return pointer to internal string with current path. This string
1617* should not be modified or freed.
1618*
1619* @see ethumb_client_dir_path_set()
1620*/
1621EAPI const char *1622ethumb_client_dir_path_get(const Ethumb_Client *client)1623{
1624EINA_SAFETY_ON_NULL_RETURN_VAL(client, NULL);1625
1626return ethumb_thumb_dir_path_get(client->ethumb);1627}
1628
1629/**
1630* Category directory to store thumbnails.
1631*
1632* This value will be used to generate thumbnail paths, that is, it
1633* will be used when ethumb_client_thumb_path_set() was not called
1634* after last ethumb_client_file_set().
1635*
1636* This is a sub-directory inside base directory
1637* (ethumb_client_dir_path_set()) that creates a namespace to avoid
1638* different options resulting in the same file.
1639*
1640* As other options, this value will only be applied to future
1641* requests.
1642*
1643* @param client the client instance to use. Must @b not be @c
1644* NULL. May be pending connected (can be called before @c
1645* connected_cb)
1646* @param category category sub directory to store thumbnail. Default
1647* is either "normal" or "large" for FDO compliant thumbnails
1648* or WIDTHxHEIGHT-ASPECT[-FRAMED]-FORMAT. It can be a string
1649* or @c NULL to use auto generated names.
1650*
1651* @see ethumb_client_dir_path_set()
1652*/
1653EAPI void1654ethumb_client_category_set(Ethumb_Client *client, const char *category)1655{
1656EINA_SAFETY_ON_NULL_RETURN(client);1657
1658if (!client->old_ethumb_conf)1659client->old_ethumb_conf = ethumb_dup(client->ethumb);1660ethumb_thumb_category_set(client->ethumb, category);1661}
1662
1663/**
1664* Get category sub-directory where to store thumbnails.
1665*
1666* @param client the client instance to use. Must @b not be @c
1667* NULL. May be pending connected (can be called before @c
1668* connected_cb)
1669*
1670* @return pointer to internal string with current path. This string
1671* should not be modified or freed.
1672*
1673* @see ethumb_client_category_set()
1674*/
1675EAPI const char *1676ethumb_client_category_get(const Ethumb_Client *client)1677{
1678EINA_SAFETY_ON_NULL_RETURN_VAL(client, NULL);1679
1680return ethumb_thumb_category_get(client->ethumb);1681}
1682
1683/**
1684* Set the video time (duration) in seconds.
1685*
1686* @param client the client instance to use. Must @b not be @c
1687* NULL. May be pending connected (can be called before @c
1688* connected_cb)
1689* @param t duration (in seconds). Defaults to 3 seconds.
1690*/
1691EAPI void1692ethumb_client_video_time_set(Ethumb_Client *client, float t)1693{
1694EINA_SAFETY_ON_NULL_RETURN(client);1695
1696if (!client->old_ethumb_conf)1697client->old_ethumb_conf = ethumb_dup(client->ethumb);1698ethumb_video_time_set(client->ethumb, t);1699}
1700
1701/**
1702* Set initial video position to start thumbnailing, in percentage.
1703*
1704* This is useful to avoid thumbnailing the company/producer logo or
1705* movie opening.
1706*
1707* @param client the client instance to use. Must @b not be @c
1708* NULL. May be pending connected (can be called before @c
1709* connected_cb)
1710* @param start initial video positon to thumbnail, in percentage (0.0
1711* to 1.0, inclusive). Defaults to 10% (0.1).
1712*/
1713EAPI void1714ethumb_client_video_start_set(Ethumb_Client *client, float start)1715{
1716EINA_SAFETY_ON_NULL_RETURN(client);1717EINA_SAFETY_ON_FALSE_RETURN(start >= 0.0);1718EINA_SAFETY_ON_FALSE_RETURN(start <= 1.0);1719
1720if (!client->old_ethumb_conf)1721client->old_ethumb_conf = ethumb_dup(client->ethumb);1722ethumb_video_start_set(client->ethumb, start);1723}
1724
1725/**
1726* Set the video frame interval, in seconds.
1727*
1728* This is useful for animated thumbnail and will define skip time
1729* before going to the next frame. Note that video backends might not
1730* be able to precisely skip that amount as it will depend on various
1731* factors, including video encoding.
1732*
1733* Although this seems similar to ethumb_client_video_fps_set(), this
1734* one is the time that will be used to seek. The math is simple, for
1735* each new frame the video position will be set to:
1736* ((video_length * start_time) + (interval * current_frame_number)).
1737*
1738* @param client the client instance to use. Must @b not be @c
1739* NULL. May be pending connected (can be called before @c
1740* connected_cb)
1741* @param interval time between frames, in seconds. Defaults to 0.05
1742* seconds.
1743*/
1744EAPI void1745ethumb_client_video_interval_set(Ethumb_Client *client, float interval)1746{
1747EINA_SAFETY_ON_NULL_RETURN(client);1748
1749if (!client->old_ethumb_conf)1750client->old_ethumb_conf = ethumb_dup(client->ethumb);1751ethumb_video_interval_set(client->ethumb, interval);1752}
1753
1754/**
1755* Set the number of frames to thumbnail.
1756*
1757* This is useful for animated thumbnail and will define how many
1758* frames the generated file will have.
1759*
1760* @param client the client instance to use. Must @b not be @c
1761* NULL. May be pending connected (can be called before @c
1762* connected_cb)
1763* @param ntimes number of times, must be greater than zero.
1764* Defaults to 3.
1765*/
1766EAPI void1767ethumb_client_video_ntimes_set(Ethumb_Client *client, unsigned int ntimes)1768{
1769EINA_SAFETY_ON_NULL_RETURN(client);1770EINA_SAFETY_ON_FALSE_RETURN(ntimes > 0);1771
1772if (!client->old_ethumb_conf)1773client->old_ethumb_conf = ethumb_dup(client->ethumb);1774ethumb_video_ntimes_set(client->ethumb, ntimes);1775}
1776
1777/**
1778* Set the number of frames per second to thumbnail the video.
1779*
1780* This configures the number of times per seconds the thumbnail will
1781* use to create thumbnails.
1782*
1783* Although this is similar to ethumb_client_video_interval_set(), it
1784* is the delay used between calling functions thata generates frames,
1785* while the other is the time used to skip inside the video.
1786*
1787* @param client the client instance to use. Must @b not be @c
1788* NULL. May be pending connected (can be called before @c
1789* connected_cb)
1790* @param fps number of frames per second to thumbnail. Must be greater
1791* than zero. Defaults to 10.
1792*/
1793EAPI void1794ethumb_client_video_fps_set(Ethumb_Client *client, unsigned int fps)1795{
1796EINA_SAFETY_ON_NULL_RETURN(client);1797EINA_SAFETY_ON_FALSE_RETURN(fps > 0);1798
1799if (!client->old_ethumb_conf)1800client->old_ethumb_conf = ethumb_dup(client->ethumb);1801ethumb_video_fps_set(client->ethumb, fps);1802}
1803
1804/**
1805* Set the page number to thumbnail in paged documents.
1806*
1807* @param client the client instance to use. Must @b not be @c
1808* NULL. May be pending connected (can be called before @c
1809* connected_cb)
1810* @param page page number, defaults to 0 (first).
1811*/
1812EAPI void1813ethumb_client_document_page_set(Ethumb_Client *client, unsigned int page)1814{
1815EINA_SAFETY_ON_NULL_RETURN(client);1816
1817if (!client->old_ethumb_conf)1818client->old_ethumb_conf = ethumb_dup(client->ethumb);1819ethumb_document_page_set(client->ethumb, page);1820}
1821
1822/**
1823* Set source file to be thumbnailed.
1824*
1825* Calling this function has the side effect of resetting values set
1826* with ethumb_client_thumb_path_set() or auto-generated with
1827* ethumb_client_thumb_exists().
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 path the filesystem path to use. May be @c NULL.
1833* @param key the extra argument/key inside @a path to read image
1834* from. This is only used for formats that allow multiple
1835* resources in one file, like EET or Edje (group name).
1836*
1837* @return @c EINA_TRUE on success, @c EINA_FALSE on failure.
1838*/
1839EAPI Eina_Bool
1840ethumb_client_file_set(Ethumb_Client *client, const char *path, const char *key)1841{
1842EINA_SAFETY_ON_NULL_RETURN_VAL(client, 0);1843
1844return ethumb_file_set(client->ethumb, path, key);1845}
1846
1847/**
1848* Get values set with ethumb_client_file_get()
1849*
1850* @param client the client instance to use. Must @b not be @c
1851* NULL. May be pending connected (can be called before @c
1852* connected_cb)
1853* @param path where to return configured path. May be @c NULL. If
1854* not @c NULL, then it will be a pointer to a stringshared
1855* instance, but @b no references are added (do it with
1856* eina_stringshare_ref())!
1857* @param key where to return configured key. May be @c NULL.If not @c
1858* NULL, then it will be a pointer to a stringshared instance,
1859* but @b no references are added (do it with
1860* eina_stringshare_ref())!
1861*/
1862EAPI void1863ethumb_client_file_get(Ethumb_Client *client, const char **path, const char **key)1864{
1865if (path) *path = NULL;1866if (key) *key = NULL;1867EINA_SAFETY_ON_NULL_RETURN(client);1868
1869ethumb_file_get(client->ethumb, path, key);1870}
1871
1872/**
1873* Reset previously set file to @c NULL.
1874*
1875* @param client the client instance to use. Must @b not be @c
1876* NULL. May be pending connected (can be called before @c
1877* connected_cb)
1878*/
1879EAPI void1880ethumb_client_file_free(Ethumb_Client *client)1881{
1882EINA_SAFETY_ON_NULL_RETURN(client);1883
1884ethumb_file_free(client->ethumb);1885}
1886
1887/**
1888* Set a defined path and key to store the thumbnail.
1889*
1890* If not explicitly given, the thumbnail path will be auto-generated
1891* by ethumb_client_thumb_exists() or server using configured
1892* parameters like size, aspect and category.
1893*
1894* Set these to @c NULL to forget previously given values. After
1895* ethumb_client_file_set() these values will be reset to @c NULL.
1896*
1897* @param client the client instance to use. Must @b not be @c
1898* NULL. May be pending connected (can be called before @c
1899* connected_cb)
1900* @param path force generated thumbnail to the exact given path. If
1901* @c NULL, then reverts back to auto-generation.
1902* @param key force generated thumbnail to the exact given key. If
1903* @c NULL, then reverts back to auto-generation.
1904*/
1905EAPI void1906ethumb_client_thumb_path_set(Ethumb_Client *client, const char *path, const char *key)1907{
1908EINA_SAFETY_ON_NULL_RETURN(client);1909
1910ethumb_thumb_path_set(client->ethumb, path, key);1911}
1912
1913/**
1914* Get the configured thumbnail path.
1915*
1916* This returns the value set with ethumb_client_thumb_path_set() or
1917* auto-generated by ethumb_client_thumb_exists() if it was not set.
1918*
1919* @param client the client instance to use. Must @b not be @c
1920* NULL. May be pending connected (can be called before @c
1921* connected_cb)
1922* @param path where to return configured path. May be @c NULL. If
1923* there was no path configured with
1924* ethumb_client_thumb_path_set() and
1925* ethumb_client_thumb_exists() was not called, then it will
1926* probably return @c NULL. If not @c NULL, then it will be a
1927* pointer to a stringshared instance, but @b no references are
1928* added (do it with eina_stringshare_ref())!
1929* @param key where to return configured key. May be @c NULL. If
1930* there was no key configured with
1931* ethumb_client_thumb_key_set() and
1932* ethumb_client_thumb_exists() was not called, then it will
1933* probably return @c NULL. If not @c NULL, then it will be a
1934* pointer to a stringshared instance, but @b no references are
1935* added (do it with eina_stringshare_ref())!
1936*/
1937EAPI void1938ethumb_client_thumb_path_get(Ethumb_Client *client, const char **path, const char **key)1939{
1940if (path) *path = NULL;1941if (key) *key = NULL;1942EINA_SAFETY_ON_NULL_RETURN(client);1943
1944ethumb_thumb_path_get(client->ethumb, path, key);1945}
1946
1947/**
1948* Checks whenever file already exists (locally!)
1949*
1950* This will check locally (not calling server) if thumbnail already
1951* exists or not, also calculating the thumbnail path. See
1952* ethumb_client_thumb_path_get(). Path must be configured with
1953* ethumb_client_file_set() before using it and the last set file will
1954* be used!
1955*
1956* @param client client instance. Must @b not be @c NULL and client
1957* must be configured with ethumb_client_file_set().
1958*
1959* @return @c NULL on failure, a valid Ethumb_Exists pointer otherwise
1960*/
1961EAPI Ethumb_Exists *1962ethumb_client_thumb_exists(Ethumb_Client *client, Ethumb_Client_Thumb_Exists_Cb exists_cb, const void *data)1963{
1964const char *path = NULL;1965Ethumb_Async_Exists *async = NULL;1966Ethumb_Exists *cb = NULL;1967Ecore_Thread *t;1968
1969EINA_SAFETY_ON_NULL_RETURN_VAL(client, NULL);1970
1971ethumb_file_get(client->ethumb, &path, NULL);1972if (!path) goto on_error;1973
1974async = eina_hash_find(_exists_request, path);1975if (!async)1976{1977async = malloc(sizeof (Ethumb_Async_Exists));1978if (!async) goto on_error;1979
1980async->path = eina_stringshare_ref(path);1981async->callbacks = NULL;1982async->dup = ethumb_dup(client->ethumb);1983
1984if (!async->dup) goto on_error;1985
1986cb = malloc(sizeof (Ethumb_Exists));1987if (!cb) goto on_error;1988
1989EINA_REFCOUNT_REF(client);1990cb->client = client;1991cb->dup = ethumb_dup(client->ethumb);1992cb->exists_cb = exists_cb;1993cb->data = data;1994cb->parent = async;1995
1996async->callbacks = eina_list_append(async->callbacks, cb);1997
1998/* spawn a thread here */1999t = ecore_thread_run(_ethumb_client_exists_heavy,2000_ethumb_client_exists_end,2001_ethumb_client_exists_end,2002async);2003if (!t) return NULL;2004async->thread = t;2005
2006eina_hash_direct_add(_exists_request, async->path, async);2007
2008return cb;2009}2010
2011cb = malloc(sizeof (Ethumb_Exists));2012if (!cb)2013{2014async = NULL;2015goto on_error;2016}2017
2018EINA_REFCOUNT_REF(client);2019cb->client = client;2020cb->dup = ethumb_dup(client->ethumb);2021cb->exists_cb = exists_cb;2022cb->data = data;2023cb->parent = async;2024
2025async->callbacks = eina_list_append(async->callbacks, cb);2026
2027return cb;2028
2029on_error:2030exists_cb((void *)data, client, NULL, EINA_FALSE);2031
2032if (async)2033{2034eina_stringshare_del(async->path);2035if (async->dup) ethumb_free(async->dup);2036free(async);2037}2038return NULL;2039}
2040
2041/**
2042* Cancel an ongoing exists request.
2043*
2044* @param exists the request to cancel.
2045*/
2046EAPI void2047ethumb_client_thumb_exists_cancel(Ethumb_Exists *exists)2048{
2049Ethumb_Async_Exists *async = exists->parent;2050
2051async->callbacks = eina_list_remove(async->callbacks, exists);2052if (eina_list_count(async->callbacks) <= 0)2053ecore_thread_cancel(async->thread);2054
2055ethumb_free(exists->dup);2056EINA_REFCOUNT_UNREF(exists->client) _ethumb_client_free(exists->client);2057free(exists);2058}
2059
2060/**
2061* Check if an exists request was cancelled.
2062*
2063* @param exists the request to check.
2064* @result return EINA_TRUE if the request was cancelled.
2065*/
2066EAPI Eina_Bool
2067ethumb_client_thumb_exists_check(Ethumb_Exists *exists)2068{
2069Ethumb_Async_Exists *async = exists->parent;2070
2071if (!async) return EINA_TRUE;2072
2073if (async->callbacks) return EINA_FALSE;2074
2075return ecore_thread_check(async->thread);2076}
2077
2078/**
2079* Ask server to generate thumbnail.
2080*
2081* This process is asynchronous and will report back from main loop
2082* using @a generated_cb. One can cancel this request by calling
2083* ethumb_client_generate_cancel() or
2084* ethumb_client_generate_cancel_all(), but not that request might be
2085* processed by server already and no generated files will be removed
2086* if that is the case.
2087*
2088* This will not check if file already exists, this should be done by
2089* explicitly calling ethumb_client_thumb_exists(). That is, this
2090* function will override any existing thumbnail.
2091*
2092* @param client client instance. Must @b not be @c NULL and client
2093* must be connected (after connected_cb is called).
2094* @param generated_cb function to report generation results.
2095* @param data context argument to give back to @a generated_cb. May
2096* be @c NULL.
2097* @param data context to give back to @a generate_cb. May be @c
2098* NULL.
2099* @param free_data used to release @a data resources after @a
2100* generated_cb is called or user calls
2101* ethumb_client_disconnect().
2102*
2103* @return identifier or -1 on error. If -1 is returned (error) then
2104* @a free_data is @b not called!
2105*
2106* @see ethumb_client_connect()
2107* @see ethumb_client_file_set()
2108* @see ethumb_client_thumb_exists()
2109* @see ethumb_client_generate_cancel()
2110* @see ethumb_client_generate_cancel_all()
2111*/
2112EAPI int2113ethumb_client_generate(Ethumb_Client *client, Ethumb_Client_Generate_Cb generated_cb, const void *data, Eina_Free_Cb free_data)2114{
2115const char *file, *key, *thumb, *thumb_key;2116int id;2117EINA_SAFETY_ON_NULL_RETURN_VAL(client, -1);2118EINA_SAFETY_ON_FALSE_RETURN_VAL(client->connected, -1);2119
2120ethumb_file_get(client->ethumb, &file, &key);2121if (!file)2122{2123ERR("no file set.");2124return -1;2125}2126
2127ethumb_thumb_path_get(client->ethumb, &thumb, &thumb_key);2128
2129if (client->old_ethumb_conf &&2130ethumb_cmp(client->old_ethumb_conf, client->ethumb))2131{2132ethumb_client_ethumb_setup(client);2133ethumb_free(client->old_ethumb_conf);2134client->old_ethumb_conf = NULL;2135}2136id = _ethumb_client_queue_add(client, file, key, thumb, thumb_key,2137generated_cb, data, free_data);2138return id;2139}
2140
2141struct _Ethumb_Client_Async2142{
2143Ethumb_Exists *exists;2144Ethumb_Client *client;2145Ethumb *dup;2146
2147Ethumb_Client_Async_Done_Cb done;2148Ethumb_Client_Async_Error_Cb error;2149const void *data;2150
2151int id;2152};2153
2154static Ecore_Idler *idler[2] = { NULL, NULL };2155static Eina_List *pending = NULL;2156static Eina_List *idle_tasks[2] = { NULL, NULL };2157
2158static void2159_ethumb_client_async_free(Ethumb_Client_Async *async)2160{
2161Ethumb_Client *client = async->client;2162ethumb_free(async->dup);2163free(async);2164if (client)2165{2166EINA_REFCOUNT_UNREF(client) _ethumb_client_free(client);2167}2168}
2169
2170static void2171_ethumb_client_thumb_finish(void *data,2172Ethumb_Client *client, int id,2173const char *file EINA_UNUSED, const char *key EINA_UNUSED,2174const char *thumb_path, const char *thumb_key,2175Eina_Bool success)2176{
2177Ethumb_Client_Async *async = data;2178
2179EINA_SAFETY_ON_FALSE_RETURN(async->id == id);2180
2181if (success)2182{2183async->done(client, thumb_path, thumb_key, (void *)async->data);2184}2185else2186{2187async->error(client, (void *)async->data);2188}2189
2190pending = eina_list_remove(pending, async);2191_ethumb_client_async_free(async);2192}
2193
2194static Eina_Bool2195_ethumb_client_thumb_generate_idler(void *data EINA_UNUSED)2196{
2197Ethumb_Client_Async *async;2198Eina_List *l1, *l2;2199
2200EINA_LIST_FOREACH_SAFE (idle_tasks[1], l1, l2, async)2201{2202Ethumb *tmp;2203
2204idle_tasks[1] = eina_list_remove_list(idle_tasks[1], l1);2205
2206tmp = async->client->ethumb;2207async->client->ethumb = async->dup;2208
2209async->id = ethumb_client_generate(async->client, _ethumb_client_thumb_finish, async, NULL);2210if (async->id == -1)2211{2212async->error(async->client, (void *)async->data);2213async->client->ethumb = tmp;2214_ethumb_client_async_free(async);2215async = NULL;2216}2217else2218{2219async->client->ethumb = tmp;2220}2221
2222if (async)2223pending = eina_list_append(pending, async);2224
2225if (ecore_time_get() - ecore_loop_time_get() > ecore_animator_frametime_get() * 0.5)2226return EINA_TRUE;2227}2228
2229idler[1] = NULL;2230return EINA_FALSE;2231}
2232
2233static void2234_ethumb_client_thumb_exists(void *data, Ethumb_Client *client, Ethumb_Exists *request, Eina_Bool exists)2235{
2236Ethumb_Client_Async *async = data;2237
2238if (request == NULL)2239return;2240
2241EINA_SAFETY_ON_FALSE_RETURN(async->exists == request);2242
2243async->exists = NULL;2244pending = eina_list_remove(pending, async);2245
2246if (exists)2247{2248const char *thumb_path;2249const char *thumb_key;2250
2251ethumb_client_thumb_path_get(client, &thumb_path, &thumb_key);2252async->done(client, thumb_path, thumb_key, (void *)async->data);2253_ethumb_client_async_free(async);2254}2255else2256{2257idle_tasks[1] = eina_list_append(idle_tasks[1], async);2258
2259if (!idler[1])2260idler[1] = ecore_idler_add(_ethumb_client_thumb_generate_idler, NULL);2261}2262}
2263
2264static Eina_Bool2265_ethumb_client_thumb_exists_idler(void *data EINA_UNUSED)2266{
2267Ethumb_Client_Async *async;2268Eina_List *l1, *l2;2269
2270EINA_LIST_FOREACH_SAFE (idle_tasks[0], l1, l2, async)2271{2272Ethumb *tmp;2273
2274idle_tasks[0] = eina_list_remove_list(idle_tasks[0], l1);2275
2276tmp = async->client->ethumb;2277async->client->ethumb = async->dup;2278
2279async->exists = ethumb_client_thumb_exists(async->client, _ethumb_client_thumb_exists, async);2280if (!async->exists)2281{2282async->error(async->client, (void *)async->data);2283async->client->ethumb = tmp;2284_ethumb_client_async_free(async);2285continue;2286}2287
2288async->client->ethumb = tmp;2289
2290pending = eina_list_append(pending, async);2291
2292if (ecore_time_get() - ecore_loop_time_get() > ecore_animator_frametime_get() * 0.5)2293return EINA_TRUE;2294}2295
2296idler[0] = NULL;2297return EINA_FALSE;2298}
2299
2300EAPI Ethumb_Client_Async *2301ethumb_client_thumb_async_get(Ethumb_Client *client,2302Ethumb_Client_Async_Done_Cb done,2303Ethumb_Client_Async_Error_Cb error,2304const void *data)2305{
2306Ethumb_Client_Async *async;2307
2308EINA_SAFETY_ON_NULL_RETURN_VAL(client, NULL);2309
2310async = malloc(sizeof (Ethumb_Client_Async));2311if (!async)2312{2313error(client, (void *)data);2314return NULL;2315}2316
2317EINA_REFCOUNT_REF(client);2318async->client = client;2319async->dup = ethumb_dup(client->ethumb);2320async->done = done;2321async->error = error;2322async->data = data;2323async->exists = NULL;2324async->id = -1;2325
2326idle_tasks[0] = eina_list_append(idle_tasks[0], async);2327
2328if (!idler[0])2329idler[0] = ecore_idler_add(_ethumb_client_thumb_exists_idler, NULL);2330
2331return async;2332}
2333
2334EAPI void2335ethumb_client_thumb_async_cancel(Ethumb_Client *client, Ethumb_Client_Async *request)2336{
2337const char *path;2338
2339EINA_SAFETY_ON_NULL_RETURN(client);2340EINA_SAFETY_ON_NULL_RETURN(request);2341
2342ethumb_file_get(request->dup, &path, NULL);2343
2344if (request->exists)2345{2346ethumb_client_thumb_exists_cancel(request->exists);2347request->exists = NULL;2348
2349pending = eina_list_remove(pending, request);2350}2351else if (request->id != -1)2352{2353Ethumb *tmp = request->client->ethumb;2354request->client->ethumb = request->dup;2355
2356ethumb_client_generate_cancel(request->client, request->id, NULL, NULL, NULL);2357
2358request->client->ethumb = tmp;2359
2360pending = eina_list_remove(pending, request);2361}2362else2363{2364idle_tasks[0] = eina_list_remove(idle_tasks[0], request);2365idle_tasks[1] = eina_list_remove(idle_tasks[1], request);2366}2367
2368_ethumb_client_async_free(request);2369}
2370