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