ethumb: make exists client API async.
[framework/uifw/ethumb.git] / src / lib / client / Ethumb_Client.c
index f41fb83..3e05fac 100644 (file)
@@ -6,20 +6,19 @@
  *
  * 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>
@@ -79,6 +78,7 @@
 #include <eina_safety_checks.h>
 #include <E_DBus.h>
 #include <Ethumb.h>
+#include <Ecore.h>
 
 #include "Ethumb_Client.h"
 
@@ -124,9 +124,12 @@ 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
@@ -165,6 +168,22 @@ struct _ethumb_pending_gen
    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";
@@ -464,6 +483,54 @@ error:
    _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
  */
@@ -653,6 +720,10 @@ ethumb_client_disconnect(Ethumb_Client *client)
 
    EINA_SAFETY_ON_NULL_RETURN(client);
 
+   client->delete_me = EINA_TRUE;
+   if (client->refcount > 0)
+     return ;
+
    if (!client->connected)
      goto end_connection;
 
@@ -845,7 +916,7 @@ ethumb_client_ethumb_setup(Ethumb_Client *client)
    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;
@@ -901,6 +972,11 @@ ethumb_client_ethumb_setup(Ethumb_Client *client)
    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);
@@ -990,8 +1066,8 @@ _ethumb_client_generated_cb(void *data, DBusMessage *msg)
 {
    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;
@@ -1054,8 +1130,8 @@ _ethumb_client_generated_cb(void *data, DBusMessage *msg)
      }
 
 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
@@ -1214,22 +1290,22 @@ ethumb_client_generate_cancel(Ethumb_Client *client, int id, Ethumb_Client_Gener
    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;
      }
@@ -1240,21 +1316,20 @@ ethumb_client_generate_cancel(Ethumb_Client *client, int id, Ethumb_Client_Gener
    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;
      }
 
@@ -1490,6 +1565,48 @@ ethumb_client_aspect_get(const Ethumb_Client *client)
 }
 
 /**
+ * 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
@@ -1736,15 +1853,15 @@ ethumb_client_category_get(const Ethumb_Client *client)
  * @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);
 }
 
 /**
@@ -2002,12 +2119,67 @@ ethumb_client_thumb_path_get(Ethumb_Client *client, const char **path, const cha
  *
  * @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);
 }
 
 /**