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