*
* Copyright (C) 2009 by ProFUSION embedded systems
*
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 3 of the License, or (at your
- * option) any later version.
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
*
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
*
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- * USA.
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
*
* @author Rafael Antognolli <antognolli@profusion.mobi>
* @author Gustavo Sverzut Barbieri <barbieri@profusion.mobi>
*/
#ifdef HAVE_CONFIG_H
-#include "config.h"
+# include "config.h"
#endif
-#include <Eina.h>
-#include <eina_safety_checks.h>
-#include <Ethumb.h>
-#include "Ethumb_Client.h"
+
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <sys/types.h>
#include <stdbool.h>
+#include <Eina.h>
+#include <eina_safety_checks.h>
+#include <E_DBus.h>
+#include <Ethumb.h>
+#include <Ecore.h>
+
+#include "Ethumb_Client.h"
+
#ifndef PATH_MAX
#define PATH_MAX 4096
#endif
-#include <E_DBus.h>
-
#define MAX_ID 2000000
static int _log_dom = -1;
#define INF(...) EINA_LOG_DOM_INFO(_log_dom, __VA_ARGS__)
#define WRN(...) EINA_LOG_DOM_WARN(_log_dom, __VA_ARGS__)
#define ERR(...) EINA_LOG_DOM_ERR(_log_dom, __VA_ARGS__)
+#define CRITICAL(...) EINA_LOG_DOM_CRIT(_log_dom, __VA_ARGS__)
struct _Ethumb_Client
{
} die;
const char *object_path;
+ int refcount;
+
Eina_Bool ethumb_dirty : 1;
Eina_Bool connected : 1;
Eina_Bool server_started : 1;
+ Eina_Bool delete_me : 1;
};
struct _ethumb_pending_add
Eina_Free_Cb free_data;
};
+typedef struct _Ethumb_Async_Exists Ethumb_Async_Exists;
+
+struct _Ethumb_Async_Exists
+{
+ Ethumb *dup;
+ Ethumb_Client *source;
+
+ Ethumb_Client_Thumb_Exists_Cb exists_cb;
+ const void *data;
+
+ Ecore_Thread *thread;
+ int refcount;
+
+ Eina_Bool exists : 1;
+};
+
static const char _ethumb_dbus_bus_name[] = "org.enlightenment.Ethumb";
static const char _ethumb_dbus_interface[] = "org.enlightenment.Ethumb";
static const char _ethumb_dbus_objects_interface[] = "org.enlightenment.Ethumb.objects";
{
if (!msg)
{
- ERR("%s:%d:%s() callback without message arguments!\n",
+ ERR("%s:%d:%s() callback without message arguments!",
file, line, function);
if (err)
ERR("%s:%d:%s() an error was reported by server: "
- "name=\"%s\", message=\"%s\"\n",
+ "name=\"%s\", message=\"%s\"",
file, line, function, err->name, err->message);
return 0;
if (!dbus_message_iter_init(msg, itr))
{
- ERR("%s:%d:%s() could not init iterator.\n",
+ ERR("%s:%d:%s() could not init iterator.",
file, line, function);
return 0;
}
if (type == expected)
return 1;
- ERR("expected type %s (%c) but got %c instead!\n",
+ ERR("expected type %s (%c) but got %c instead!",
expected_name, expected, type);
return 0;
{ \
if ((ptr) == NULL) \
{ \
- ERR("%s == NULL!\n", #ptr); \
+ CRITICAL("%s == NULL!", #ptr); \
return __VA_ARGS__; \
} \
} \
DBUS_TYPE_STRING, &to,
DBUS_TYPE_INVALID))
{
- ERR("could not get NameOwnerChanged arguments: %s: %s\n",
+ ERR("could not get NameOwnerChanged arguments: %s: %s",
err.name, err.message);
dbus_error_free(&err);
return;
}
+ if(!from || !name)
+ return ;
if (strcmp(name, _ethumb_dbus_bus_name) != 0)
return;
- DBG("NameOwnerChanged from=[%s] to=[%s]\n", from, to);
+ DBG("NameOwnerChanged from=[%s] to=[%s]", from, to);
if (from[0] != '\0' && to[0] == '\0')
{
- DBG("exit ethumbd at %s\n", from);
- if (strcmp(client->unique_name, from) != 0)
- WRN("%s was not the known name %s, ignored.\n",
+ DBG("exit ethumbd at %s", from);
+ if (client->unique_name && strcmp(client->unique_name, from) != 0)
+ WRN("%s was not the known name %s, ignored.",
from, client->unique_name);
- else
+ else if(client->unique_name)
{
- ERR("server exit!!!\n");
+ ERR("server exit!!!");
if (client->die.cb)
{
client->die.cb(client->die.data, client);
}
}
else
- DBG("unknown change from %s to %s\n", from, to);
+ DBG("unknown change from %s to %s", from, to);
}
static void
dbus_message_iter_get_basic(&iter, &ret);
if ((ret != 1) && (ret != 2))
{
- ERR("Error starting Ethumbd DBus service by its name: retcode %u\n",
+ ERR("Error starting Ethumbd DBus service by its name: retcode %u",
ret);
goto error;
}
client->server_started = 1;
- DBG("Ethumbd DBus service started successfully (%d), now request its name\n",
+ DBG("Ethumbd DBus service started successfully (%d), now request its name",
ret);
if (client->pending_get_name_owner)
{
- DBG("already requesting name owner, cancel and try again\n");
+ DBG("already requesting name owner, cancel and try again");
dbus_pending_call_cancel(client->pending_get_name_owner);
}
client);
if (!client->pending_get_name_owner)
{
- ERR("could not create a get_name_owner request.\n");
+ ERR("could not create a get_name_owner request.");
goto error;
}
return;
error:
- ERR("failed to start Ethumbd DBus service by its name.\n");
+ ERR("failed to start Ethumbd DBus service by its name.");
_ethumb_client_report_connect(client, 0);
}
{
if (client->pending_start_service_by_name)
{
- DBG("already pending start service by name.\n");
+ DBG("already pending start service by name.");
return;
}
client);
if (!client->pending_start_service_by_name)
{
- ERR("could not start service by name!\n");
+ ERR("could not start service by name!");
_ethumb_client_report_connect(client, 0);
}
}
if (dbus_error_is_set(err) && (!client->server_started))
{
- DBG("could not find server (%s), try to start it...\n", err->message);
+ DBG("could not find server (%s), try to start it...", err->message);
_ethumb_client_start_server(client);
return;
}
dbus_message_iter_get_basic(&iter, &uid);
if (!uid)
{
- ERR("no name owner!\n");
+ ERR("no name owner!");
goto error;
}
- DBG("unique name = %s\n", uid);
+ DBG("unique name = %s", uid);
client->unique_name = eina_stringshare_add(uid);
_ethumb_client_call_new(client);
_ethumb_client_report_connect(client, 0);
}
+static void
+_ethumb_client_exists_heavy(void *data, Ecore_Thread *thread)
+{
+ Ethumb_Async_Exists *async = data;
+
+ async->exists = ethumb_exists(async->dup);
+}
+
+static void
+_ethumb_client_exists_end(void *data, Ecore_Thread *thread)
+{
+ Ethumb_Async_Exists *async = data;
+ Ethumb *tmp = async->source->ethumb;
+
+ async->source->ethumb = async->dup;
+ async->source->ethumb_dirty = ethumb_cmp(tmp, async->dup);
+ async->exists_cb(async->source, (Ethumb_Exists*) async, async->exists, (void*) async->data);
+ async->source->ethumb = tmp;
+
+ ethumb_free(async->dup);
+ async->source->refcount--;
+
+ if (async->source->delete_me == EINA_TRUE)
+ ethumb_client_disconnect(async->source);
+
+ free(async);
+}
+
+static void
+_ethumb_client_exists_cancel(void *data, Ecore_Thread *thread)
+{
+ Ethumb_Async_Exists *async = data;
+ Ethumb *tmp = async->source->ethumb;
+
+ async->source->ethumb = async->dup;
+ async->source->ethumb_dirty = ethumb_cmp(tmp, async->dup);
+ async->exists_cb(async->source, (Ethumb_Exists*) async, EINA_FALSE, (void*) async->data);
+ async->source->ethumb = tmp;
+
+ ethumb_free(async->dup);
+ async->source->refcount--;
+
+ if (async->source->delete_me == EINA_TRUE)
+ ethumb_client_disconnect(async->source);
+
+ free(async);
+}
+
/**
* @endcond
*/
eclient = calloc(1, sizeof(*eclient));
if (!eclient)
{
- ERR("could not allocate Ethumb_Client structure.\n");
+ ERR("could not allocate Ethumb_Client structure.");
goto err;
}
eclient->ethumb = ethumb_new();
if (!eclient->ethumb)
{
- ERR("could not create ethumb handler.\n");
+ ERR("could not create ethumb handler.");
goto ethumb_new_err;
}
eclient->conn = e_dbus_bus_get(DBUS_BUS_SESSION);
if (!eclient->conn)
{
- ERR("could not connect to session bus.\n");
+ ERR("could not connect to session bus.");
goto connection_err;
}
eclient);
if (!eclient->pending_get_name_owner)
{
- ERR("could not create a get_name_owner request.\n");
+ ERR("could not create a get_name_owner request.");
goto connection_err;
}
EINA_SAFETY_ON_NULL_RETURN(client);
+ client->delete_me = EINA_TRUE;
+ if (client->refcount > 0)
+ return ;
+
if (!client->connected)
goto end_connection;
el_type = dbus_message_iter_get_element_type(iter);
if (el_type != DBUS_TYPE_BYTE)
{
- ERR("not an byte array element.\n");
+ ERR("not an byte array element.");
return NULL;
}
DBusMessageIter iter, aiter, diter, viter, vaiter;
Ethumb *e = client->ethumb;
const char *entry;
- dbus_int32_t tw, th, format, aspect, quality, compress;
+ dbus_int32_t tw, th, format, aspect, orientation, quality, compress;
float cx, cy;
double t;
const char *theme_file, *group, *swallow;
dbus_message_iter_append_basic(&viter, DBUS_TYPE_INT32, &aspect);
_close_variant_iter(viter);
+ _open_variant_iter("orientation", "i", viter);
+ orientation = ethumb_thumb_orientation_get(e);
+ dbus_message_iter_append_basic(&viter, DBUS_TYPE_INT32, &orientation);
+ _close_variant_iter(viter);
+
_open_variant_iter("crop", "(dd)", viter);
dbus_message_iter_open_container(&viter, DBUS_TYPE_STRUCT, NULL, &vaiter);
ethumb_thumb_crop_align_get(e, &cx, &cy);
{
DBusMessageIter iter;
dbus_int32_t id = -1;
- const char *thumb;
- const char *thumb_key;
+ const char *thumb = NULL;
+ const char *thumb_key = NULL;
Ethumb_Client *client = data;
int t;
dbus_bool_t success;
}
end:
- eina_stringshare_del(thumb);
- eina_stringshare_del(thumb_key);
+ if (thumb) eina_stringshare_del(thumb);
+ if (thumb_key) eina_stringshare_del(thumb_key);
}
static void
l = client->pending_add;
while (l)
{
- struct _ethumb_pending_add *pending = l->data;
- if (pending->id != id32)
+ struct _ethumb_pending_add *pending_add = l->data;
+ if (pending_add->id != id32)
{
l = l->next;
continue;
}
client->pending_add = eina_list_remove_list(client->pending_add, l);
- eina_stringshare_del(pending->file);
- eina_stringshare_del(pending->key);
- eina_stringshare_del(pending->thumb);
- eina_stringshare_del(pending->thumb_key);
- dbus_pending_call_cancel(pending->pending_call);
- dbus_pending_call_unref(pending->pending_call);
- if (pending->free_data)
- pending->free_data(pending->data);
- free(pending);
+ eina_stringshare_del(pending_add->file);
+ eina_stringshare_del(pending_add->key);
+ eina_stringshare_del(pending_add->thumb);
+ eina_stringshare_del(pending_add->thumb_key);
+ dbus_pending_call_cancel(pending_add->pending_call);
+ dbus_pending_call_unref(pending_add->pending_call);
+ if (pending_add->free_data)
+ pending_add->free_data(pending_add->data);
+ free(pending_add);
found = 1;
break;
}
l = client->pending_gen;
while (l)
{
- struct _ethumb_pending_gen *pending = l->data;
- if (pending->id != id32)
+ struct _ethumb_pending_gen *pending_gen = l->data;
+ if (pending_gen->id != id32)
{
l = l->next;
continue;
}
client->pending_gen = eina_list_remove_list(client->pending_gen, l);
- eina_stringshare_del(pending->file);
- eina_stringshare_del(pending->key);
- eina_stringshare_del(pending->thumb);
- eina_stringshare_del(pending->thumb_key);
- if (pending->free_data)
- pending->free_data(pending->data);
- free(pending);
- found = 1;
+ eina_stringshare_del(pending_gen->file);
+ eina_stringshare_del(pending_gen->key);
+ eina_stringshare_del(pending_gen->thumb);
+ eina_stringshare_del(pending_gen->thumb_key);
+ if (pending_gen->free_data)
+ pending_gen->free_data(pending_gen->data);
+ free(pending_gen);
break;
}
}
/**
+ * Configure orientation to use for future requests.
+ *
+ * Default value is #ETHUMB_THUMB_ORIENT_ORIGINAL: metadata from the file
+ * will be used to orient pixel data.
+ *
+ * @param client the client instance to use. Must @b not be @c
+ * NULL. May be pending connected (can be called before @c
+ * connected_cb)
+ * @param f format identifier to use, either #ETHUMB_THUMB_ORIENT_NONE (0),
+ * #ETHUMB_THUMB_ROTATE_90_CW (1), #ETHUMB_THUMB_ROTATE_180 (2),
+ * #ETHUMB_THUMB_ROTATE_90_CCW (3), #ETHUMB_THUMB_FLIP_HORIZONTAL (4),
+ * #ETHUMB_THUMB_FLIP_VERTICAL (5), #ETHUMB_THUMB_FLIP_TRANSPOSE (6),
+ * #ETHUMB_THUMB_FLIP_TRANSVERSE (7) or #ETHUMB_THUMB_ORIENT_ORIGINAL
+ * (8). Default is ORIGINAL.
+ */
+EAPI void
+ethumb_client_orientation_set(Ethumb_Client *client, Ethumb_Thumb_Orientation o)
+{
+ EINA_SAFETY_ON_NULL_RETURN(client);
+
+ client->ethumb_dirty = 1;
+ ethumb_thumb_orientation_set(client->ethumb, o);
+}
+
+/**
+ * Get current orientation in use for requests.
+ *
+ * @param client the client instance to use. Must @b not be @c
+ * NULL. May be pending connected (can be called before @c
+ * connected_cb)
+ *
+ * @return orientation in use for future requests.
+ */
+EAPI Ethumb_Thumb_Orientation
+ethumb_client_orientation_get(const Ethumb_Client *client)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(client, 0);
+
+ return ethumb_thumb_orientation_get(client->ethumb);
+}
+
+/**
* Configure crop alignment in use for future requests.
*
* @param client the client instance to use. Must @b not be @c
* @param client the client instance to use. Must @b not be @c
* NULL. May be pending connected (can be called before @c
* connected_cb)
- * @param time duration (in seconds). Defaults to 3 seconds.
+ * @param t duration (in seconds). Defaults to 3 seconds.
*/
EAPI void
-ethumb_client_video_time_set(Ethumb_Client *client, float time)
+ethumb_client_video_time_set(Ethumb_Client *client, float t)
{
EINA_SAFETY_ON_NULL_RETURN(client);
client->ethumb_dirty = 1;
- ethumb_video_time_set(client->ethumb, time);
+ ethumb_video_time_set(client->ethumb, t);
}
/**
*
* @return @c EINA_TRUE if it exists, @c EINA_FALSE otherwise.
*/
+EAPI Ethumb_Exists *
+ethumb_client_thumb_exists(Ethumb_Client *client, Ethumb_Client_Thumb_Exists_Cb exists_cb, const void *data)
+{
+ Ethumb_Async_Exists *async;
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(client, NULL);
+
+ async = malloc(sizeof (Ethumb_Async_Exists));
+ if (!async)
+ {
+ exists_cb(client, NULL, EINA_FALSE, (void*) data);
+ return NULL;
+ }
+
+ async->dup = ethumb_dup(client->ethumb);
+ async->source = client;
+ async->source->refcount++;
+ async->exists_cb = exists_cb;
+ async->data = data;
+ async->exists = EINA_FALSE;
+
+ async->refcount = 1;
+ async->thread = ecore_thread_run(_ethumb_client_exists_heavy,
+ _ethumb_client_exists_end,
+ _ethumb_client_exists_cancel,
+ async);
+
+ return (Ethumb_Exists*) async;
+}
+
+/**
+ * Cancel an ongoing exists request.
+ *
+ * @param exists the request to cancel.
+ */
+EAPI void
+ethumb_client_thumb_exists_cancel(Ethumb_Exists *exists)
+{
+ Ethumb_Async_Exists *async = (Ethumb_Async_Exists*) exists;
+
+ async->refcount--;
+
+ if (async->refcount > 0) return ;
+
+ ecore_thread_cancel(async->thread);
+}
+
+/**
+ * Check if an exists request was cancelled.
+ *
+ * @param exists the request to check.
+ * @result return EINA_TRUE if the request was cancelled.
+ */
EAPI Eina_Bool
-ethumb_client_thumb_exists(Ethumb_Client *client)
+ethumb_client_thumb_exists_check(Ethumb_Exists *exists)
{
- EINA_SAFETY_ON_NULL_RETURN_VAL(client, 0);
+ Ethumb_Async_Exists *async = (Ethumb_Async_Exists*) exists;
+
+ if (!async) return EINA_TRUE;
- return ethumb_exists(client->ethumb);
+ return ecore_thread_check(async->thread);
}
/**
ethumb_file_get(client->ethumb, &file, &key);
if (!file)
{
- ERR("no file set.\n");
+ ERR("no file set.");
return -1;
}