From aac69a080f8373a854145b50acd0840caa3420d8 Mon Sep 17 00:00:00 2001 From: Rafael Antognolli Date: Thu, 4 Jun 2009 21:21:43 +0000 Subject: [PATCH] Added ethumbd (ethumb). ethumbd is a server waiting for requests of thumbnails via dbus. A client library is also provided, avoiding dbus burocracy (and with an API similar to ethumb). SVN revision: 40899 --- legacy/ethumb/Makefile.am | 9 + legacy/ethumb/configure.ac | 24 + legacy/ethumb/ethumb_client.pc.in | 11 + .../org.enlightenment.Ethumb.service.in | 3 + legacy/ethumb/src/Makefile.am | 2 +- legacy/ethumb/src/bin/Makefile.am | 16 + legacy/ethumb/src/bin/ethumbd.c | 1672 +++++++++++++++++ legacy/ethumb/src/bin/ethumbd_child.c | 614 ++++++ legacy/ethumb/src/bin/ethumbd_private.h | 34 + legacy/ethumb/src/lib/Makefile.am | 7 + legacy/ethumb/src/lib/client/Ethumb_Client.c | 1080 +++++++++++ legacy/ethumb/src/lib/client/Ethumb_Client.h | 85 + legacy/ethumb/src/lib/client/Makefile.am | 21 + legacy/ethumb/src/tests/Makefile.am | 22 + legacy/ethumb/src/tests/ethumb_dbus.c | 135 ++ 15 files changed, 3734 insertions(+), 1 deletion(-) create mode 100644 legacy/ethumb/ethumb_client.pc.in create mode 100644 legacy/ethumb/org.enlightenment.Ethumb.service.in create mode 100644 legacy/ethumb/src/bin/ethumbd.c create mode 100644 legacy/ethumb/src/bin/ethumbd_child.c create mode 100644 legacy/ethumb/src/bin/ethumbd_private.h create mode 100644 legacy/ethumb/src/lib/client/Ethumb_Client.c create mode 100644 legacy/ethumb/src/lib/client/Ethumb_Client.h create mode 100644 legacy/ethumb/src/lib/client/Makefile.am create mode 100644 legacy/ethumb/src/tests/Makefile.am create mode 100644 legacy/ethumb/src/tests/ethumb_dbus.c diff --git a/legacy/ethumb/Makefile.am b/legacy/ethumb/Makefile.am index 9115d31c94..ab97c5f2a7 100644 --- a/legacy/ethumb/Makefile.am +++ b/legacy/ethumb/Makefile.am @@ -21,6 +21,15 @@ pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = \ ethumb.pc + +if USE_MODULE_ETHUMBD + +pkgconfig_DATA += ethumb_client.pc +servicedir = $(dbusservicedir) +service_DATA = org.enlightenment.Ethumb.service + +endif + SUBDIRS = m4 src data ACLOCAL_AMFLAGS = -I m4 diff --git a/legacy/ethumb/configure.ac b/legacy/ethumb/configure.ac index ea6359dab8..1e53358e68 100644 --- a/legacy/ethumb/configure.ac +++ b/legacy/ethumb/configure.ac @@ -47,6 +47,7 @@ PKG_CHECK_MODULES(ECORE_FILE, [ecore-file]) PKG_CHECK_MODULES(EDJE, [edje]) requirement_ethumb="eina-0 evas ecore ecore-evas ecore-file edje" +requirement_ethumb_client="ethumb edbus" AM_CONDITIONAL(HAVE_EMOTION, false) define([CHECK_MODULE_EMOTION], @@ -71,17 +72,40 @@ if $USE_MODULE_EPDF ; then requirement_ethumb="$requirement_ethumb epdf" fi +AM_CONDITIONAL(HAVE_EDBUS, false) +define([CHECK_MODULE_ETHUMBD], +[ + AC_ETH_CHECK_PKG(EDBUS, edbus, [], [ETHUMBD=false]) +]) + +AC_ETH_OPTIONAL_MODULE([ethumbd], true, [CHECK_MODULE_ETHUMBD]) +if $USE_MODULE_ETHUMBD ; then + dbusservicedir=`$PKG_CONFIG --variable=session_bus_services_dir dbus-1` + AC_ARG_WITH([dbus-services], + AC_HELP_STRING([--with-dbus-services=DBUS_SERVICES], [specify a directory to store dbus service files.]), + [ + dbusservicedir=$withval + ] + ) +fi + AC_SUBST(requirement_ethumb) +AC_SUBST(requirement_ethumb_client) +AC_SUBST(dbusservicedir) AC_OUTPUT([ ethumb.pc +ethumb_client.pc +org.enlightenment.Ethumb.service Makefile src/Makefile src/bin/Makefile src/lib/Makefile +src/lib/client/Makefile src/plugins/Makefile src/plugins/emotion/Makefile src/plugins/epdf/Makefile +src/tests/Makefile data/Makefile data/frames/Makefile m4/Makefile diff --git a/legacy/ethumb/ethumb_client.pc.in b/legacy/ethumb/ethumb_client.pc.in new file mode 100644 index 0000000000..b1e44b79e2 --- /dev/null +++ b/legacy/ethumb/ethumb_client.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: ethumb_client +Description: Thumbnail Client Library +Requires: @requirement_ethumb_client@ +Version: @VERSION@ +Libs: -L${libdir} -lethumb_client +Cflags: -I${includedir} diff --git a/legacy/ethumb/org.enlightenment.Ethumb.service.in b/legacy/ethumb/org.enlightenment.Ethumb.service.in new file mode 100644 index 0000000000..ece2e031c4 --- /dev/null +++ b/legacy/ethumb/org.enlightenment.Ethumb.service.in @@ -0,0 +1,3 @@ +[D-BUS Service] +Name=org.enlightenment.Ethumb +Exec=@prefix@/bin/ethumbd diff --git a/legacy/ethumb/src/Makefile.am b/legacy/ethumb/src/Makefile.am index e55545e4cf..31c7f284ec 100644 --- a/legacy/ethumb/src/Makefile.am +++ b/legacy/ethumb/src/Makefile.am @@ -1,3 +1,3 @@ MAINTAINERCLEANFILES = Makefile.in -SUBDIRS = lib bin plugins +SUBDIRS = lib bin plugins tests diff --git a/legacy/ethumb/src/bin/Makefile.am b/legacy/ethumb/src/bin/Makefile.am index ff15c57a55..5eccd9780b 100644 --- a/legacy/ethumb/src/bin/Makefile.am +++ b/legacy/ethumb/src/bin/Makefile.am @@ -6,6 +6,7 @@ AM_CPPFLAGS = \ @EDJE_CFLAGS@ @ECORE_FILE_CFLAGS@ bin_PROGRAMS = ethumb +noinst_HEADERS = ethumb_SOURCES = ethumb.c ethumb_LDADD = \ @@ -13,3 +14,18 @@ ethumb_LDADD = \ @ECORE_FILE_LIBS@ \ $(top_builddir)/src/lib/libethumb.la ethumb_DEPENDENCIES = $(top_builddir)/config.h + + + +if USE_MODULE_ETHUMBD + +AM_CPPFLAGS += @EDBUS_CFLAGS@ +bin_PROGRAMS += ethumbd +noinst_HEADERS += ethumbd_private.h +ethumbd_SOURCES = ethumbd.c ethumbd_child.c +ethumbd_LDADD = \ + @EINA_LIBS@ @EVAS_LIBS@ @ECORE_LIBS@ @EDJE_LIBS@ @EDBUS_LIBS@ \ + $(top_builddir)/src/lib/libethumb.la +ethumbd_DEPENDENCIES = $(top_builddir)/config.h + +endif diff --git a/legacy/ethumb/src/bin/ethumbd.c b/legacy/ethumb/src/bin/ethumbd.c new file mode 100644 index 0000000000..3b9aaef7e0 --- /dev/null +++ b/legacy/ethumb/src/bin/ethumbd.c @@ -0,0 +1,1672 @@ +/** + * @file + * + * 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 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. + * + * 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. + * + * @author Rafael Antognolli + */ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "ethumbd_private.h" + +#ifndef PATH_MAX +#define PATH_MAX 4096 +#endif + +#define MAX_ID 2000000 + +#define DBG(...) EINA_ERROR_PDBG(__VA_ARGS__) +#define INF(...) EINA_ERROR_PINFO(__VA_ARGS__) +#define WRN(...) EINA_ERROR_PWARN(__VA_ARGS__) +#define ERR(...) EINA_ERROR_PERR(__VA_ARGS__) + +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"; +static const char _ethumb_dbus_path[] = "/org/enlightenment/Ethumb"; +static const char fdo_interface[] = "org.freedesktop.DBus"; +static const char fdo_bus_name[] = "org.freedesktop.DBus"; +static const char fdo_path[] = "/org/freedesktop/DBus"; + +struct _Ethumb_Setup +{ + struct + { + int fdo : 1; + int size : 1; + int format : 1; + int aspect : 1; + int crop : 1; + int directory : 1; + int category : 1; + int frame : 1; + int video_time : 1; + int document_page : 1; + } flags; + int fdo; + int tw, th; + int format; + int aspect; + float cx, cy; + const char *directory; + const char *category; + const char *theme_file; + const char *group; + const char *swallow; + float video_time; + int document_page; +}; + +struct _Ethumb_Request +{ + long id; + const char *file, *key; + const char *thumb, *thumb_key; + struct _Ethumb_Setup setup; +}; + +struct _Ethumb_Object +{ + int used; + const char *path; + const char *client; + Eina_List *queue; + int nqueue; + long id_count; + long max_id; + long min_id; + E_DBus_Object *dbus_obj; +}; + +struct _Ethumb_Queue +{ + int count; + int max_count; + int nqueue; + int last; + int current; + struct _Ethumb_Object *table; + int *list; +}; + +struct _Ethumbd +{ + E_DBus_Connection *conn; + E_DBus_Signal_Handler *name_owner_changed_handler; + E_DBus_Interface *eiface, *objects_iface; + E_DBus_Object *dbus_obj; + Ecore_Idler *idler; + struct _Ethumb_Request *processing; + struct _Ethumb_Queue queue; + int pipeout; + int pipein; + Ecore_Fd_Handler *fd_handler; + double timeout; + Ecore_Timer *timeout_timer; +}; + +struct _Ethumb_Object_Data +{ + int index; + struct _Ethumbd *ed; +}; + +struct _Ethumb_DBus_Method_Table +{ + const char *name; + const char *signature; + const char *reply; + E_DBus_Method_Cb function; +}; + +struct _Ethumb_DBus_Signal_Table +{ + const char *name; + const char *signature; +}; + +const Ecore_Getopt optdesc = { + "ethumbd", + NULL, + PACKAGE_VERSION, + "(C) 2009 - ProFUSION embedded systems", + "LGPL v3 - GNU Lesser General Public License", + "Ethumb daemon.\n" + "\n" + "ethumbd uses the Ethumb library to create thumbnails for any " + "program that requests it (now just by dbus).\n", + 0, + { + ECORE_GETOPT_STORE_DOUBLE + ('t', "timeout", "finish ethumbd after seconds of no activity."), + ECORE_GETOPT_LICENSE('L', "license"), + ECORE_GETOPT_COPYRIGHT('C', "copyright"), + ECORE_GETOPT_VERSION('V', "version"), + ECORE_GETOPT_HELP('h', "help"), + ECORE_GETOPT_SENTINEL + } +}; + +static void _ethumb_dbus_generated_signal(struct _Ethumbd *ed, long *id, const char *thumb_path, const char *thumb_key, Eina_Bool success); + +static int +_ethumbd_timeout_cb(void *data) +{ + struct _Ethumbd *ed = data; + + ecore_main_loop_quit(); + ed->timeout_timer = NULL; + + return 0; +} + +static void +_ethumbd_timeout_start(struct _Ethumbd *ed) +{ + if (ed->timeout < 0) + return; + + if (!ed->timeout_timer) + ed->timeout_timer = ecore_timer_add(ed->timeout, _ethumbd_timeout_cb, ed); +} + +static void +_ethumbd_timeout_stop(struct _Ethumbd *ed) +{ + if (!ed->timeout_timer) + return; + + ecore_timer_del(ed->timeout_timer); + ed->timeout_timer = NULL; +} + +static int +_ethumb_dbus_check_id(struct _Ethumb_Object *eobject, long id) +{ + if (id < 0 || id > MAX_ID) + return 0; + + if (eobject->min_id < eobject->max_id) + return id < eobject->min_id || id > eobject->max_id; + else if (eobject->min_id > eobject->max_id) + return id < eobject->min_id && id > eobject->max_id; + else + return id != eobject->max_id; +} + +static void +_ethumb_dbus_inc_max_id(struct _Ethumb_Object *eobject, long id) +{ + if (eobject->min_id < 0 && eobject->max_id < 0) + eobject->min_id = id; + + eobject->max_id = id; +} + +static void +_ethumb_dbus_inc_min_id(struct _Ethumb_Object *eobject) +{ + Eina_List *l; + + l = eobject->queue; + while (l) + { + struct _Ethumb_Request *request = l->data; + if (request->id >= 0) + { + eobject->min_id = request->id; + break; + } + + l = l->next; + } + + if (!l) + { + eobject->min_id = -1; + eobject->max_id = -1; + } +} + +int +_ethumbd_read_safe(int fd, void *buf, ssize_t size) +{ + ssize_t todo; + char *p; + + todo = size; + p = buf; + + while (todo > 0) + { + ssize_t r; + + r = read(fd, p, todo); + if (r > 0) + { + todo -= r; + p += r; + } + else if (r == 0) + return 0; + else + { + if (errno == EINTR || errno == EAGAIN) + continue; + else + { + ERR("could not read from fd %d: %s", + fd, strerror(errno)); + return 0; + } + } + } + + return 1; +} + +int +_ethumbd_write_safe(int fd, const void *buf, ssize_t size) +{ + ssize_t todo; + const char *p; + + todo = size; + p = buf; + + while (todo > 0) + { + ssize_t r; + + r = write(fd, p, todo); + if (r > 0) + { + todo -= r; + p += r; + } + else if (r == 0) + return 0; + else + { + if (errno == EINTR || errno == EAGAIN) + continue; + else + { + ERR("could not write to fd %d: %s", fd, strerror(errno)); + return 0; + } + } + } + + return 1; +} + +static void +_ethumbd_child_write_op_new(struct _Ethumbd *ed, int index) +{ + int id = ETHUMBD_OP_NEW; + _ethumbd_write_safe(ed->pipeout, &id, sizeof(id)); + _ethumbd_write_safe(ed->pipeout, &index, sizeof(index)); +} + +static void +_ethumbd_child_write_op_del(struct _Ethumbd *ed, int index) +{ + int id = ETHUMBD_OP_DEL; + _ethumbd_write_safe(ed->pipeout, &id, sizeof(id)); + _ethumbd_write_safe(ed->pipeout, &index, sizeof(index)); +} + +static void +_ethumbd_pipe_str_write(int fd, const char *str) +{ + int len; + + if (str) + len = strlen(str) + 1; + else + len = 0; + + _ethumbd_write_safe(fd, &len, sizeof(len)); + _ethumbd_write_safe(fd, str, len); +} + +static int +_ethumbd_pipe_str_read(int fd, char **str) +{ + int size; + int r; + char buf[PATH_MAX]; + + r = _ethumbd_read_safe(fd, &size, sizeof(size)); + if (!r) + { + *str = NULL; + return 0; + } + + if (!size) + { + *str = NULL; + return 1; + } + + r = _ethumbd_read_safe(fd, buf, size); + if (!r) + { + *str = NULL; + return 0; + } + + *str = strdup(buf); + return 1; +} + +static void +_ethumbd_child_write_op_generate(struct _Ethumbd *ed, int index, const char *path, const char *key, const char *thumb_path, const char *thumb_key) +{ + int id = ETHUMBD_OP_GENERATE; + + _ethumbd_write_safe(ed->pipeout, &id, sizeof(id)); + _ethumbd_write_safe(ed->pipeout, &index, sizeof(index)); + + _ethumbd_pipe_str_write(ed->pipeout, path); + _ethumbd_pipe_str_write(ed->pipeout, key); + _ethumbd_pipe_str_write(ed->pipeout, thumb_path); + _ethumbd_pipe_str_write(ed->pipeout, thumb_key); +} + +static void +_generated_cb(struct _Ethumbd *ed, Eina_Bool success, const char *thumb_path, const char *thumb_key) +{ + int i = ed->queue.current; + + DBG("thumbnail ready at: \"%s:%s\"\n", thumb_path, thumb_key); + + if (ed->queue.table[i].used) + _ethumb_dbus_generated_signal(ed, &ed->processing->id, thumb_path, + thumb_key, success); + eina_stringshare_del(ed->processing->file); + eina_stringshare_del(ed->processing->key); + eina_stringshare_del(ed->processing->thumb); + eina_stringshare_del(ed->processing->thumb_key); + free(ed->processing); + ed->processing = NULL; +} + +static int +_ethumbd_fd_handler(void *data, Ecore_Fd_Handler *fd_handler) +{ + struct _Ethumbd *ed = data; + Eina_Bool success; + int r; + char *thumb_path, *thumb_key; + + if (ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_ERROR)) + { + ERR("error on pipein! child exiting...\n"); + ed->fd_handler = NULL; + ecore_main_loop_quit(); + return 0; + } + + r = _ethumbd_read_safe(ed->pipein, &success, sizeof(success)); + if (!r) + { + ERR("ethumbd child exited!\n"); + ed->fd_handler = NULL; + return 0; + } + + r = _ethumbd_pipe_str_read(ed->pipein, &thumb_path); + r = _ethumbd_pipe_str_read(ed->pipein, &thumb_key); + _generated_cb(ed, success, thumb_path, thumb_key); + + free(thumb_path); + free(thumb_key); + + return 1; +} + +static void +_ethumbd_pipe_write_setup(int fd, int type, const void *data) +{ + const int *i_value; + const float *f_value; + + _ethumbd_write_safe(fd, &type, sizeof(type)); + + switch (type) + { + case ETHUMBD_FDO: + case ETHUMBD_FORMAT: + case ETHUMBD_ASPECT: + case ETHUMBD_SIZE_W: + case ETHUMBD_SIZE_H: + case ETHUMBD_DOCUMENT_PAGE: + i_value = data; + _ethumbd_write_safe(fd, i_value, sizeof(*i_value)); + break; + case ETHUMBD_CROP_X: + case ETHUMBD_CROP_Y: + case ETHUMBD_VIDEO_TIME: + f_value = data; + _ethumbd_write_safe(fd, f_value, sizeof(*f_value)); + break; + case ETHUMBD_DIRECTORY: + case ETHUMBD_CATEGORY: + case ETHUMBD_FRAME_FILE: + case ETHUMBD_FRAME_GROUP: + case ETHUMBD_FRAME_SWALLOW: + _ethumbd_pipe_str_write(fd, data); + break; + case ETHUMBD_SETUP_FINISHED: + break; + default: + ERR("wrong ethumb setup parameter.\n"); + } +} + +static void +_process_setup(struct _Ethumbd *ed) +{ + int op_id = ETHUMBD_OP_SETUP; + int index = ed->queue.current; + int fd = ed->pipeout; + + struct _Ethumb_Setup *setup = &ed->processing->setup; + + _ethumbd_write_safe(ed->pipeout, &op_id, sizeof(op_id)); + _ethumbd_write_safe(ed->pipeout, &index, sizeof(index)); + + if (setup->flags.fdo) + _ethumbd_pipe_write_setup(fd, ETHUMBD_FDO, &setup->fdo); + if (setup->flags.size) + { + _ethumbd_pipe_write_setup(fd, ETHUMBD_SIZE_W, &setup->tw); + _ethumbd_pipe_write_setup(fd, ETHUMBD_SIZE_H, &setup->th); + } + if (setup->flags.format) + _ethumbd_pipe_write_setup(fd, ETHUMBD_FORMAT, &setup->format); + if (setup->flags.aspect) + _ethumbd_pipe_write_setup(fd, ETHUMBD_ASPECT, &setup->aspect); + if (setup->flags.crop) + { + _ethumbd_pipe_write_setup(fd, ETHUMBD_CROP_X, &setup->cx); + _ethumbd_pipe_write_setup(fd, ETHUMBD_CROP_Y, &setup->cy); + } + if (setup->flags.directory) + _ethumbd_pipe_write_setup(fd, ETHUMBD_DIRECTORY, setup->directory); + if (setup->flags.category) + _ethumbd_pipe_write_setup(fd, ETHUMBD_CATEGORY, setup->category); + if (setup->flags.frame) + { + _ethumbd_pipe_write_setup(fd, ETHUMBD_FRAME_FILE, setup->theme_file); + _ethumbd_pipe_write_setup(fd, ETHUMBD_FRAME_GROUP, setup->group); + _ethumbd_pipe_write_setup(fd, ETHUMBD_FRAME_SWALLOW, setup->swallow); + } + if (setup->flags.video_time) + _ethumbd_pipe_write_setup(fd, ETHUMBD_VIDEO_TIME, &setup->video_time); + if (setup->flags.document_page) + _ethumbd_pipe_write_setup(fd, ETHUMBD_DOCUMENT_PAGE, + &setup->document_page); + _ethumbd_pipe_write_setup(fd, ETHUMBD_SETUP_FINISHED, NULL); + + + if (setup->directory) eina_stringshare_del(setup->directory); + if (setup->category) eina_stringshare_del(setup->category); + if (setup->theme_file) eina_stringshare_del(setup->theme_file); + if (setup->group) eina_stringshare_del(setup->group); + if (setup->swallow) eina_stringshare_del(setup->swallow); + + free(ed->processing); + ed->processing = NULL; +} + +static void +_process_file(struct _Ethumbd *ed) +{ + _ethumbd_child_write_op_generate(ed, ed->queue.current, ed->processing->file, + ed->processing->key, ed->processing->thumb, + ed->processing->thumb_key); +} + +static int +_get_next_on_queue(struct _Ethumb_Queue *queue) +{ + int i, index; + struct _Ethumb_Object *eobject; + + i = queue->last; + i++; + if (i >= queue->count) + i = 0; + + index = queue->list[i]; + eobject = &(queue->table[index]); + while (!eobject->nqueue) + { + i = (i + 1) % queue->count; + + index = queue->list[i]; + eobject = &(queue->table[index]); + } + + return queue->list[i]; +} + +static int +_process_queue_cb(void *data) +{ + struct _Ethumb_Object *eobject; + int i; + struct _Ethumbd *ed = data; + struct _Ethumb_Queue *queue = &ed->queue; + struct _Ethumb_Request *request; + + if (ed->processing) + return 1; + + if (!queue->nqueue) + { + ed->idler = NULL; + if (!queue->count) + _ethumbd_timeout_start(ed); + ed->idler = NULL; + return 0; + } + + i = _get_next_on_queue(queue); + eobject = &(queue->table[i]); + + request = eina_list_data_get(eobject->queue); + eobject->queue = eina_list_remove_list(eobject->queue, eobject->queue); + ed->queue.current = i; + DBG("processing file: \"%s:%s\"...\n", request->file, + request->key); + ed->processing = request; + + if (request->id < 0) + _process_setup(ed); + else + { + _process_file(ed); + _ethumb_dbus_inc_min_id(eobject); + } + eobject->nqueue--; + queue->nqueue--; + + queue->last = i; + + return 1; +} + +static void +_process_queue_start(struct _Ethumbd *ed) +{ + if (!ed->idler) + ed->idler = ecore_idler_add(_process_queue_cb, ed); +} + +static void +_process_queue_stop(struct _Ethumbd *ed) +{ + if (ed->idler) + { + ecore_idler_del(ed->idler); + ed->idler = NULL; + } +} + +static int +_ethumb_table_append(struct _Ethumbd *ed) +{ + int i; + char buf[1024]; + struct _Ethumb_Queue *q = &ed->queue; + + if (q->count == q->max_count) + { + int new_max = q->max_count + 5; + int start, size; + + start = q->max_count; + size = new_max - q->max_count; + + q->table = realloc(q->table, new_max * sizeof(struct _Ethumb_Object)); + q->list = realloc(q->list, new_max * sizeof(int)); + memset(&q->table[start], 0, size * sizeof(struct _Ethumb_Object)); + + q->max_count = new_max; + } + + for (i = 0; i < q->max_count; i++) + { + if (!q->table[i].used) + break; + } + + snprintf(buf, sizeof(buf), "%s/%d", _ethumb_dbus_path, i); + q->table[i].used = 1; + q->table[i].path = eina_stringshare_add(buf); + q->table[i].max_id = -1; + q->table[i].min_id = -1; + q->list[q->count] = i; + q->count++; + DBG("new object: %s, index = %d, count = %d\n", buf, i, q->count); + + return i; +} + +static inline int +_get_index_for_path(const char *path) +{ + int i; + int n; + n = sscanf(path, "/org/enlightenment/Ethumb/%d", &i); + if (!n) + return -1; + return i; +} + +static void +_ethumb_table_del(struct _Ethumbd *ed, int i) +{ + int j; + Eina_List *l; + const Eina_List *il; + struct _Ethumb_Queue *q = &ed->queue; + struct _Ethumb_Object_Data *odata; + + eina_stringshare_del(q->table[i].path); + + l = q->table[i].queue; + while (l) + { + struct _Ethumb_Request *request = l->data; + eina_stringshare_del(request->file); + eina_stringshare_del(request->key); + eina_stringshare_del(request->thumb); + eina_stringshare_del(request->thumb_key); + free(request); + l = eina_list_remove_list(l, l); + } + q->nqueue -= q->table[i].nqueue; + + il = e_dbus_object_interfaces_get(q->table[i].dbus_obj); + while (il) + { + e_dbus_object_interface_detach(q->table[i].dbus_obj, il->data); + il = e_dbus_object_interfaces_get(q->table[i].dbus_obj); + } + odata = e_dbus_object_data_get(q->table[i].dbus_obj); + free(odata); + e_dbus_object_free(q->table[i].dbus_obj); + + memset(&(q->table[i]), 0, sizeof(struct _Ethumb_Object)); + for (j = 0; j < q->count; j++) + { + if (q->list[j] == i) + q->list[j] = q->list[q->count - 1]; + } + + q->count--; + _ethumbd_child_write_op_del(ed, i); + if (!q->count && !ed->processing) + _ethumbd_timeout_start(ed); +} + +static void +_ethumb_table_clear(struct _Ethumbd *ed) +{ + int i; + + for (i = 0; i < ed->queue.max_count; i++) + if (ed->queue.table[i].used) + _ethumb_table_del(ed, i); +} + +static void +_name_owner_changed_cb(void *data, DBusMessage *msg) +{ + DBusError err; + struct _Ethumbd *ed = data; + struct _Ethumb_Queue *q = &ed->queue; + const char *name, *from, *to; + int i; + + dbus_error_init(&err); + if (!dbus_message_get_args(msg, &err, + DBUS_TYPE_STRING, &name, + DBUS_TYPE_STRING, &from, + DBUS_TYPE_STRING, &to, + DBUS_TYPE_INVALID)) + { + ERR("could not get NameOwnerChanged arguments: %s: %s\n", + err.name, err.message); + dbus_error_free(&err); + return; + } + + DBG("NameOwnerChanged: name = %s, from = %s, to = %s\n", name, from, to); + + if (from[0] == '\0' || to[0] != '\0') + return; + + from = eina_stringshare_add(from); + for (i = 0; i < q->max_count; i++) + { + if (q->table[i].used && q->table[i].client == from) + { + _ethumb_table_del(ed, i); + DBG("deleting [%d] from queue table.\n", i); + } + } +} + +static void +_ethumb_dbus_add_name_owner_changed_cb(struct _Ethumbd *ed) +{ + ed->name_owner_changed_handler = e_dbus_signal_handler_add( + ed->conn, fdo_bus_name, fdo_path, fdo_interface, "NameOwnerChanged", + _name_owner_changed_cb, ed); +} + +DBusMessage * +_ethumb_dbus_ethumb_new_cb(E_DBus_Object *object, DBusMessage *msg) +{ + DBusMessage *reply; + DBusMessageIter iter; + E_DBus_Object *dbus_object; + struct _Ethumb_Object_Data *odata; + int i; + const char *return_path = ""; + const char *client; + struct _Ethumbd *ed; + + ed = e_dbus_object_data_get(object); + client = dbus_message_get_sender(msg); + if (!client) + goto end_new; + + i = _ethumb_table_append(ed); + + odata = calloc(1, sizeof(*odata)); + odata->index = i; + odata->ed = ed; + + ed->queue.table[i].client = eina_stringshare_add(client); + return_path = ed->queue.table[i].path; + + dbus_object = e_dbus_object_add(ed->conn, return_path, odata); + if (!dbus_object) + { + ERR("could not create dbus_object.\n"); + free(odata); + return_path = ""; + goto end_new; + } + + e_dbus_object_interface_attach(dbus_object, ed->objects_iface); + ed->queue.table[i].dbus_obj = dbus_object; + + _ethumbd_child_write_op_new(ed, i); + _ethumbd_timeout_stop(ed); + +end_new: + reply = dbus_message_new_method_return(msg); + dbus_message_iter_init_append(reply, &iter); + dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH, + &return_path); + return reply; +} + +static struct _Ethumb_DBus_Method_Table _ethumb_dbus_methods[] = +{ + { "new", "", "o", _ethumb_dbus_ethumb_new_cb }, + { } +}; + +static const char * +_ethumb_dbus_get_bytearray(DBusMessageIter *iter) +{ + int el_type; + int length; + DBusMessageIter riter; + const char *result; + + el_type = dbus_message_iter_get_element_type(iter); + if (el_type != DBUS_TYPE_BYTE) + { + ERR("not an byte array element.\n"); + return NULL; + } + + dbus_message_iter_recurse(iter, &riter); + dbus_message_iter_get_fixed_array(&riter, &result, &length); + + if (result[0] == '\0') + return NULL; + else + return eina_stringshare_add(result); +} + +static void +_ethumb_dbus_append_bytearray(DBusMessageIter *iter, const char *string) +{ + DBusMessageIter viter; + + if (!string) + string = ""; + + dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "y", &viter); + dbus_message_iter_append_fixed_array(&viter, DBUS_TYPE_BYTE, &string, + strlen(string) + 1); + dbus_message_iter_close_container(iter, &viter); +} + +DBusMessage * +_ethumb_dbus_queue_add_cb(E_DBus_Object *object, DBusMessage *msg) +{ + DBusMessage *reply; + DBusMessageIter iter; + const char *file, *key; + const char *thumb, *thumb_key; + struct _Ethumb_Object_Data *odata; + struct _Ethumb_Object *eobject; + struct _Ethumbd *ed; + struct _Ethumb_Request *request; + long id = -1; + + dbus_message_iter_init(msg, &iter); + dbus_message_iter_get_basic(&iter, &id); + dbus_message_iter_next(&iter); + file = _ethumb_dbus_get_bytearray(&iter); + dbus_message_iter_next(&iter); + key = _ethumb_dbus_get_bytearray(&iter); + dbus_message_iter_next(&iter); + thumb = _ethumb_dbus_get_bytearray(&iter); + dbus_message_iter_next(&iter); + thumb_key = _ethumb_dbus_get_bytearray(&iter); + + if (!file) + { + ERR("no filename given.\n"); + goto end; + } + + odata = e_dbus_object_data_get(object); + if (!odata) + { + ERR("could not get dbus_object data.\n"); + goto end; + } + + ed = odata->ed; + eobject = &(ed->queue.table[odata->index]); + if (!_ethumb_dbus_check_id(eobject, id)) + goto end; + request = calloc(1, sizeof(*request)); + request->id = id; + request->file = file; + request->key = key; + request->thumb = thumb; + request->thumb_key = thumb_key; + eobject->queue = eina_list_append(eobject->queue, request); + eobject->nqueue++; + ed->queue.nqueue++; + _ethumb_dbus_inc_max_id(eobject, id); + + _process_queue_start(ed); + +end: + reply = dbus_message_new_method_return(msg); + dbus_message_iter_init_append(reply, &iter); + dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT64, &id); + return reply; +} + +DBusMessage * +_ethumb_dbus_queue_remove_cb(E_DBus_Object *object, DBusMessage *msg) +{ + DBusMessage *reply; + DBusMessageIter iter; + long id; + struct _Ethumb_Object_Data *odata; + struct _Ethumb_Object *eobject; + struct _Ethumb_Request *request; + struct _Ethumbd *ed; + int r = 0; + Eina_List *l; + + dbus_message_iter_init(msg, &iter); + dbus_message_iter_get_basic(&iter, &id); + + odata = e_dbus_object_data_get(object); + if (!odata) + { + ERR("could not get dbus_object data.\n"); + goto end; + } + + ed = odata->ed; + eobject = &ed->queue.table[odata->index]; + l = eobject->queue; + while (l) + { + request = l->data; + if (id == request->id) + break; + l = l->next; + } + + if (l) + { + r = 1; + eina_stringshare_del(request->file); + eina_stringshare_del(request->key); + eina_stringshare_del(request->thumb); + eina_stringshare_del(request->thumb_key); + free(request); + eobject->queue = eina_list_remove_list(eobject->queue, l); + eobject->nqueue--; + ed->queue.nqueue--; + _ethumb_dbus_inc_min_id(eobject); + } + +end: + reply = dbus_message_new_method_return(msg); + dbus_message_iter_init_append(reply, &iter); + dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &r); + return reply; +} + +DBusMessage * +_ethumb_dbus_queue_clear_cb(E_DBus_Object *object, DBusMessage *msg) +{ + DBusMessage *reply; + struct _Ethumb_Object_Data *odata; + struct _Ethumb_Object *eobject; + struct _Ethumbd *ed; + Eina_List *l; + + odata = e_dbus_object_data_get(object); + if (!odata) + { + ERR("could not get dbus_object data.\n"); + goto end; + } + + ed = odata->ed; + eobject = &ed->queue.table[odata->index]; + l = eobject->queue; + while (l) + { + struct _Ethumb_Request *request = l->data; + eina_stringshare_del(request->file); + eina_stringshare_del(request->key); + eina_stringshare_del(request->thumb); + eina_stringshare_del(request->thumb_key); + free(request); + l = eina_list_remove_list(l, l); + } + ed->queue.nqueue -= eobject->nqueue; + eobject->nqueue = 0; + +end: + reply = dbus_message_new_method_return(msg); + return reply; +} + +DBusMessage * +_ethumb_dbus_delete_cb(E_DBus_Object *object, DBusMessage *msg) +{ + DBusMessage *reply; + DBusMessageIter iter; + struct _Ethumb_Object_Data *odata; + struct _Ethumbd *ed; + + dbus_message_iter_init(msg, &iter); + reply = dbus_message_new_method_return(msg); + + odata = e_dbus_object_data_get(object); + if (!odata) + { + ERR("could not get dbus_object data for del_cb.\n"); + return reply; + } + ed = odata->ed; + _ethumb_table_del(ed, odata->index); + free(odata); + + return reply; +} + +static int +_ethumb_dbus_fdo_set(struct _Ethumb_Object *eobject, DBusMessageIter *iter, struct _Ethumb_Request *request) +{ + int type; + int fdo; + + type = dbus_message_iter_get_arg_type(iter); + if (type != DBUS_TYPE_INT32 && type != DBUS_TYPE_INT64) + { + ERR("invalid param for fdo_set.\n"); + return 0; + } + + dbus_message_iter_get_basic(iter, &fdo); + DBG("setting fdo to: %d\n", fdo); + + return 1; +} + +static int +_ethumb_dbus_size_set(struct _Ethumb_Object *eobject, DBusMessageIter *iter, struct _Ethumb_Request *request) +{ + DBusMessageIter oiter; + int type; + int w, h; + + type = dbus_message_iter_get_arg_type(iter); + if (type != DBUS_TYPE_STRUCT) + { + ERR("invalid param for size_set.\n"); + return 0; + } + + dbus_message_iter_recurse(iter, &oiter); + dbus_message_iter_get_basic(&oiter, &w); + dbus_message_iter_next(&oiter); + dbus_message_iter_get_basic(&oiter, &h); + DBG("setting size to: %dx%d\n", w, h); + request->setup.flags.size = 1; + request->setup.tw = w; + request->setup.th = h; + + return 1; +} + +static int +_ethumb_dbus_format_set(struct _Ethumb_Object *eobject, DBusMessageIter *iter, struct _Ethumb_Request *request) +{ + int type; + int format; + + type = dbus_message_iter_get_arg_type(iter); + if (type != DBUS_TYPE_INT32 && type != DBUS_TYPE_INT64) + { + ERR("invalid param for format_set.\n"); + return 0; + } + + dbus_message_iter_get_basic(iter, &format); + DBG("setting format to: %d\n", format); + request->setup.flags.format = 1; + request->setup.format = format; + + return 1; +} + +static int +_ethumb_dbus_aspect_set(struct _Ethumb_Object *eobject, DBusMessageIter *iter, struct _Ethumb_Request *request) +{ + int type; + int aspect; + + type = dbus_message_iter_get_arg_type(iter); + if (type != DBUS_TYPE_INT32 && type != DBUS_TYPE_INT64) + { + ERR("invalid param for aspect_set.\n"); + return 0; + } + + dbus_message_iter_get_basic(iter, &aspect); + DBG("setting aspect to: %d\n", aspect); + request->setup.flags.aspect = 1; + request->setup.aspect = aspect; + + return 1; +} + +static int +_ethumb_dbus_crop_set(struct _Ethumb_Object *eobject, DBusMessageIter *iter, struct _Ethumb_Request *request) +{ + DBusMessageIter oiter; + int type; + float x, y; + + type = dbus_message_iter_get_arg_type(iter); + if (type != DBUS_TYPE_STRUCT) + { + ERR("invalid param for crop_set.\n"); + return 0; + } + + dbus_message_iter_recurse(iter, &oiter); + dbus_message_iter_get_basic(&oiter, &x); + dbus_message_iter_next(&oiter); + dbus_message_iter_get_basic(&oiter, &y); + DBG("setting crop to: %3.2f,%3.2f\n", x, y); + request->setup.flags.crop = 1; + request->setup.cx = x; + request->setup.cy = y; + + return 1; +} + +static int +_ethumb_dbus_frame_set(struct _Ethumb_Object *eobject, DBusMessageIter *iter, struct _Ethumb_Request *request) +{ + DBusMessageIter oiter; + int type; + const char *file, *group, *swallow; + + type = dbus_message_iter_get_arg_type(iter); + if (type != DBUS_TYPE_STRUCT) + { + ERR("invalid param for frame_set.\n"); + return 0; + } + + dbus_message_iter_recurse(iter, &oiter); + file = _ethumb_dbus_get_bytearray(&oiter); + dbus_message_iter_next(&oiter); + group = _ethumb_dbus_get_bytearray(&oiter); + dbus_message_iter_next(&oiter); + swallow = _ethumb_dbus_get_bytearray(&oiter); + DBG("setting frame to \"%s:%s:%s\"\n", file, group, swallow); + request->setup.flags.frame = 1; + request->setup.theme_file = eina_stringshare_add(file); + request->setup.group = eina_stringshare_add(group); + request->setup.swallow = eina_stringshare_add(swallow); + + return 1; +} + +static int +_ethumb_dbus_directory_set(struct _Ethumb_Object *eobject, DBusMessageIter *iter, struct _Ethumb_Request *request) +{ + int type; + const char *directory; + + type = dbus_message_iter_get_arg_type(iter); + if (type != DBUS_TYPE_ARRAY) + { + ERR("invalid param for dir_path_set.\n"); + return 0; + } + + directory = _ethumb_dbus_get_bytearray(iter); + DBG("setting directory to: %s\n", directory); + request->setup.flags.directory = 1; + request->setup.directory = eina_stringshare_add(directory); + + return 1; +} + +static int +_ethumb_dbus_category_set(struct _Ethumb_Object *eobject, DBusMessageIter *iter, struct _Ethumb_Request *request) +{ + int type; + const char *category; + + type = dbus_message_iter_get_arg_type(iter); + if (type != DBUS_TYPE_ARRAY) + { + ERR("invalid param for category.\n"); + return 0; + } + + category = _ethumb_dbus_get_bytearray(iter); + DBG("setting category to: %s\n", category); + request->setup.flags.category = 1; + request->setup.category = eina_stringshare_add(category); + + return 1; +} + +static int +_ethumb_dbus_video_time_set(struct _Ethumb_Object *eobject, DBusMessageIter *iter, struct _Ethumb_Request *request) +{ + int type; + double video_time; + + type = dbus_message_iter_get_arg_type(iter); + if (type != DBUS_TYPE_DOUBLE) + { + ERR("invalid param for video_time_set.\n"); + return 0; + } + + dbus_message_iter_get_basic(iter, &video_time); + DBG("setting video_time to: %3.2f\n", video_time); + request->setup.flags.video_time = 1; + request->setup.video_time = video_time; + + return 1; +} + +static int +_ethumb_dbus_document_page_set(struct _Ethumb_Object *eobject, DBusMessageIter *iter, struct _Ethumb_Request *request) +{ + int type; + int document_page; + + type = dbus_message_iter_get_arg_type(iter); + if (type != DBUS_TYPE_INT32 && type != DBUS_TYPE_INT64) + { + ERR("invalid param for document_page_set.\n"); + return 0; + } + + dbus_message_iter_get_basic(iter, &document_page); + DBG("setting document_page to: %d\n", document_page); + request->setup.flags.document_page = 1; + request->setup.document_page = document_page; + + return 1; +} + +static struct +{ + const char *option; + int (*setup_func)(struct _Ethumb_Object *eobject, DBusMessageIter *iter, struct _Ethumb_Request *request); +} _option_cbs[] = { + { "fdo", _ethumb_dbus_fdo_set }, + { "size", _ethumb_dbus_size_set }, + { "format", _ethumb_dbus_format_set }, + { "aspect", _ethumb_dbus_aspect_set }, + { "crop", _ethumb_dbus_crop_set }, + { "frame", _ethumb_dbus_frame_set }, + { "directory", _ethumb_dbus_directory_set }, + { "category", _ethumb_dbus_category_set }, + { "video_time", _ethumb_dbus_video_time_set }, + { "document_page", _ethumb_dbus_document_page_set }, + { NULL, NULL} +}; + +static int +_ethumb_dbus_ethumb_setup_parse_element(struct _Ethumb_Object *eobject, DBusMessageIter *iter, struct _Ethumb_Request *request) +{ + DBusMessageIter viter, diter; + const char *option; + int i, r; + + dbus_message_iter_recurse(iter, &diter); + dbus_message_iter_get_basic(&diter, &option); + dbus_message_iter_next(&diter); + + r = 0; + for (i = 0; _option_cbs[i].option; i++) + if (!strcmp(_option_cbs[i].option, option)) + { + r = 1; + break; + } + + if (!r) + { + ERR("ethumb_setup invalid option: %s\n", option); + return 0; + } + + dbus_message_iter_recurse(&diter, &viter); + return _option_cbs[i].setup_func(eobject, &viter, request); +} + +DBusMessage * +_ethumb_dbus_ethumb_setup_cb(E_DBus_Object *object, DBusMessage *msg) +{ + DBusMessage *reply; + DBusMessageIter iter, aiter; + struct _Ethumb_Object_Data *odata; + struct _Ethumbd *ed; + struct _Ethumb_Object *eobject; + struct _Ethumb_Request *request; + int r = 0; + int atype; + + dbus_message_iter_init(msg, &iter); + if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) + { + ERR("wrong parameters.\n"); + goto end; + } + + odata = e_dbus_object_data_get(object); + if (!odata) + { + ERR("could not get dbus_object data for setup_cb.\n"); + goto end; + } + + ed = odata->ed; + eobject = &ed->queue.table[odata->index]; + + request = calloc(1, sizeof(*request)); + request->id = -1; + dbus_message_iter_recurse(&iter, &aiter); + atype = dbus_message_iter_get_arg_type(&aiter); + + r = 1; + while (atype != DBUS_TYPE_INVALID) + { + if (!_ethumb_dbus_ethumb_setup_parse_element(eobject, &aiter, request)) + r = 0; + dbus_message_iter_next(&aiter); + atype = dbus_message_iter_get_arg_type(&aiter); + } + + eobject->queue = eina_list_append(eobject->queue, request); + eobject->nqueue++; + ed->queue.nqueue++; + +end: + reply = dbus_message_new_method_return(msg); + dbus_message_iter_init_append(reply, &iter); + dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &r); + + return reply; +} + +static void +_ethumb_dbus_generated_signal(struct _Ethumbd *ed, long *id, const char *thumb_path, const char *thumb_key, Eina_Bool success) +{ + DBusMessage *signal; + int current; + const char *opath; + DBusMessageIter iter; + Eina_Bool value; + + value = success; + + current = ed->queue.current; + opath = ed->queue.table[current].path; + signal = dbus_message_new_signal(opath, _ethumb_dbus_objects_interface, + "generated"); + + dbus_message_iter_init_append(signal, &iter); + dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT64, id); + _ethumb_dbus_append_bytearray(&iter, thumb_path); + _ethumb_dbus_append_bytearray(&iter, thumb_key); + dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &value); + + e_dbus_message_send(ed->conn, signal, NULL, -1, NULL); + dbus_message_unref(signal); +} + +static struct _Ethumb_DBus_Method_Table _ethumb_dbus_objects_methods[] = +{ + { "queue_add", "xayayayay", "x", _ethumb_dbus_queue_add_cb }, + { "queue_remove", "x", "b", _ethumb_dbus_queue_remove_cb }, + { "clear_queue", "", "", _ethumb_dbus_queue_clear_cb }, + { "ethumb_setup", "a{sv}", "b", _ethumb_dbus_ethumb_setup_cb }, + { "delete", "", "", _ethumb_dbus_delete_cb }, + { } +}; + +static struct _Ethumb_DBus_Signal_Table _ethumb_dbus_objects_signals[] = +{ + { "generated", "xayayb" }, + { } +}; + +static int +_ethumb_dbus_interface_elements_add(E_DBus_Interface *iface, struct _Ethumb_DBus_Method_Table *mtable, struct _Ethumb_DBus_Signal_Table *stable) +{ + int i = -1; + while (mtable && mtable[++i].name != NULL) + if (!e_dbus_interface_method_add(iface, + mtable[i].name, + mtable[i].signature, + mtable[i].reply, + mtable[i].function)) + return 0; + + i = -1; + while (stable && stable[++i].name != NULL) + if (!e_dbus_interface_signal_add(iface, + stable[i].name, + stable[i].signature)) + return 0; + return 1; +} + +static void +_ethumb_dbus_request_name_cb(void *data, DBusMessage *msg, DBusError *err) +{ + E_DBus_Object *dbus_object; + struct _Ethumbd *ed = data; + int r; + + if (dbus_error_is_set(err)) + { + ERR("request name error: %s\n", err->message); + dbus_error_free(err); + e_dbus_connection_close(ed->conn); + return; + } + + dbus_object = e_dbus_object_add(ed->conn, _ethumb_dbus_path, ed); + if (!dbus_object) + return; + ed->dbus_obj = dbus_object; + ed->eiface = e_dbus_interface_new(_ethumb_dbus_interface); + if (!ed->eiface) + { + ERR("could not create interface.\n"); + return; + } + r = _ethumb_dbus_interface_elements_add(ed->eiface, + _ethumb_dbus_methods, NULL); + if (!r) + { + ERR("could not add methods to the interface.\n"); + e_dbus_interface_unref(ed->eiface); + return; + } + e_dbus_object_interface_attach(dbus_object, ed->eiface); + + ed->objects_iface = e_dbus_interface_new(_ethumb_dbus_objects_interface); + if (!ed->objects_iface) + { + ERR("could not create interface.\n"); + return; + } + + r = _ethumb_dbus_interface_elements_add(ed->objects_iface, + _ethumb_dbus_objects_methods, + _ethumb_dbus_objects_signals); + if (!r) + { + ERR("ERROR: could not setup objects interface methods.\n"); + e_dbus_interface_unref(ed->objects_iface); + return; + } + + _ethumb_dbus_add_name_owner_changed_cb(ed); + + _ethumbd_timeout_start(ed); +} + +static int +_ethumb_dbus_setup(struct _Ethumbd *ed) +{ + + e_dbus_request_name(ed->conn, _ethumb_dbus_bus_name, 0, + _ethumb_dbus_request_name_cb, ed); + + return 1; +} + +static void +_ethumb_dbus_finish(struct _Ethumbd *ed) +{ + _process_queue_stop(ed); + _ethumb_table_clear(ed); + e_dbus_signal_handler_del(ed->conn, ed->name_owner_changed_handler); + e_dbus_interface_unref(ed->objects_iface); + e_dbus_interface_unref(ed->eiface); + e_dbus_object_free(ed->dbus_obj); + free(ed->queue.table); + free(ed->queue.list); +} + +static int +_ethumbd_spawn(struct _Ethumbd *ed) +{ + int pparent[2]; // parent writes here + int pchild[2]; // child writes here + int pid; + + if (pipe(pparent) == -1) + { + ERR("could not create parent pipe.\n"); + return 0; + } + + if (pipe(pchild) == -1) + { + ERR("could not create child pipe.\n"); + return 0; + } + + pid = fork(); + if (pid == -1) + { + ERR("fork error.\n"); + return 0; + } + + if (pid == 0) + { + close(pparent[1]); + close(pchild[0]); + ethumbd_child_start(pparent[0], pchild[1]); + return 2; + } + else + { + close(pparent[0]); + close(pchild[1]); + ed->pipeout = pparent[1]; + ed->pipein = pchild[0]; + ed->fd_handler = ecore_main_fd_handler_add( + ed->pipein, ECORE_FD_READ | ECORE_FD_ERROR, + _ethumbd_fd_handler, ed, NULL, NULL); + return 1; + } +} + +int +main(int argc, char *argv[]) +{ + Eina_Bool quit_option = 0; + int exit_value = 0; + int arg_index; + struct _Ethumbd ed = {0}; + int child; + double timeout = -1; + + ecore_init(); + eina_stringshare_init(); + + ethumb_init(); + + child = _ethumbd_spawn(&ed); + if (!child) + { + exit_value = -6; + goto finish; + } + + if (child == 2) + { + exit_value = 0; + goto finish; + } + + if (!e_dbus_init()) + { + ERR("could not init e_dbus.\n"); + exit_value = -1; + goto finish; + } + + Ecore_Getopt_Value values[] = { + ECORE_GETOPT_VALUE_DOUBLE(timeout), + ECORE_GETOPT_VALUE_BOOL(quit_option), + ECORE_GETOPT_VALUE_BOOL(quit_option), + ECORE_GETOPT_VALUE_BOOL(quit_option), + ECORE_GETOPT_VALUE_BOOL(quit_option), + ECORE_GETOPT_VALUE_NONE + }; + + arg_index = ecore_getopt_parse(&optdesc, values, argc, argv); + if (arg_index < 0) + { + ERR("Could not parse arguments.\n"); + exit_value = -2; + goto finish; + } + + if (quit_option) + goto finish; + + ed.conn = e_dbus_bus_get(DBUS_BUS_SESSION); + if (!ed.conn) + { + ERR("could not connect to session bus.\n"); + exit_value = -3; + goto finish_edbus; + } + + ed.timeout = timeout; + + if (!_ethumb_dbus_setup(&ed)) + { + e_dbus_connection_close(ed.conn); + ERR("could not setup dbus connection.\n"); + exit_value = -5; + goto finish_edbus; + } + + ecore_main_loop_begin(); + _ethumb_dbus_finish(&ed); + +finish_edbus: + e_dbus_shutdown(); +finish: + ethumb_shutdown(); + eina_stringshare_init(); + ecore_shutdown(); + return exit_value; +} diff --git a/legacy/ethumb/src/bin/ethumbd_child.c b/legacy/ethumb/src/bin/ethumbd_child.c new file mode 100644 index 0000000000..06eced531c --- /dev/null +++ b/legacy/ethumb/src/bin/ethumbd_child.c @@ -0,0 +1,614 @@ +/** + * @file + * + * 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 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. + * + * 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. + * + * @author Rafael Antognolli + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "ethumbd_private.h" + +#define DBG(...) EINA_ERROR_PDBG(__VA_ARGS__) +#define INF(...) EINA_ERROR_PINFO(__VA_ARGS__) +#define WRN(...) EINA_ERROR_PWARN(__VA_ARGS__) +#define ERR(...) EINA_ERROR_PERR(__VA_ARGS__) + +#define NETHUMBS 100 + +struct _Ethumbd_Child +{ + Ecore_Fd_Handler *fd_handler; + Ethumb *ethumbt[NETHUMBS]; + int pipein, pipeout; +}; + + +int +_ec_read_safe(int fd, void *buf, ssize_t size) +{ + ssize_t todo; + char *p; + + todo = size; + p = buf; + + while (todo > 0) + { + ssize_t r; + + r = read(fd, p, todo); + if (r > 0) + { + todo -= r; + p += r; + } + else if (r == 0) + return 0; + else + { + if (errno == EINTR || errno == EAGAIN) + continue; + else + { + ERR("could not read from fd %d: %s", + fd, strerror(errno)); + return 0; + } + } + } + + return 1; +} + +int +_ec_write_safe(int fd, const void *buf, ssize_t size) +{ + ssize_t todo; + const char *p; + + todo = size; + p = buf; + + while (todo > 0) + { + ssize_t r; + + r = write(fd, p, todo); + if (r > 0) + { + todo -= r; + p += r; + } + else if (r == 0) + return 0; + else + { + if (errno == EINTR || errno == EAGAIN) + continue; + else + { + ERR("could not write to fd %d: %s", fd, strerror(errno)); + return 0; + } + } + } + + return 1; +} + +static int +_ec_pipe_str_read(struct _Ethumbd_Child *ec, char **str) +{ + int size; + int r; + char buf[PATH_MAX]; + + r = _ec_read_safe(ec->pipein, &size, sizeof(size)); + if (!r) + { + *str = NULL; + return 0; + } + + if (!size) + { + *str = NULL; + return 1; + } + + r = _ec_read_safe(ec->pipein, buf, size); + if (!r) + { + *str = NULL; + return 0; + } + + *str = strdup(buf); + return 1; +} + +static void +_ec_pipe_str_write(struct _Ethumbd_Child *ec, const char *str) +{ + int size; + + if (!str) + size = 0; + else + size = strlen(str) + 1; + + _ec_write_safe(ec->pipeout, &size, sizeof(size)); + _ec_write_safe(ec->pipeout, str, size); +} + +static struct _Ethumbd_Child * +_ec_new(int pipein, int pipeout) +{ + struct _Ethumbd_Child *ec = calloc(1, sizeof(*ec)); + + ec->pipein = pipein; + ec->pipeout = pipeout; + + return ec; +} + +static void +_ec_free(struct _Ethumbd_Child *ec) +{ + int i; + + if (ec->fd_handler) + ecore_main_fd_handler_del(ec->fd_handler); + + for (i = 0; i < NETHUMBS; i++) + { + if (ec->ethumbt[i]) + ethumb_free(ec->ethumbt[i]); + } + + free(ec); +} + +static int +_ec_op_new(struct _Ethumbd_Child *ec) +{ + int r; + int index; + + r = _ec_read_safe(ec->pipein, &index, sizeof(index)); + if (!r) + return 0; + + DBG("ethumbd new(). index = %d\n", index); + + ec->ethumbt[index] = ethumb_new(); + return 1; +} + +static int +_ec_op_del(struct _Ethumbd_Child *ec) +{ + int r; + int index; + + r = _ec_read_safe(ec->pipein, &index, sizeof(index)); + if (!r) + return 0; + + DBG("ethumbd del(). index = %d\n", index); + + ethumb_free(ec->ethumbt[index]); + ec->ethumbt[index] = NULL; + return 1; +} + +static void +_ec_op_generated_cb(Ethumb *e, Eina_Bool success, void *data) +{ + struct _Ethumbd_Child *ec = data; + const char *thumb_path, *thumb_key; + + DBG("thumb generated!\n"); + ethumb_thumb_path_get(e, &thumb_path, &thumb_key); + _ec_write_safe(ec->pipeout, &success, sizeof(success)); + + _ec_pipe_str_write(ec, thumb_path); + _ec_pipe_str_write(ec, thumb_key); +} + +static int +_ec_op_generate(struct _Ethumbd_Child *ec) +{ + int index; + char *path, *key, *thumb_path, *thumb_key; + int r; + + r = _ec_read_safe(ec->pipein, &index, sizeof(index)); + if (!r) + return 0; + + r = _ec_pipe_str_read(ec, &path); + if (!r) + return 0; + r = _ec_pipe_str_read(ec, &key); + if (!r) + return 0; + r = _ec_pipe_str_read(ec, &thumb_path); + if (!r) + return 0; + r = _ec_pipe_str_read(ec, &thumb_key); + if (!r) + return 0; + + ethumb_file_set(ec->ethumbt[index], path, key); + ethumb_thumb_path_set(ec->ethumbt[index], thumb_path, thumb_key); + ethumb_generate(ec->ethumbt[index], _ec_op_generated_cb, + ec); + + free(path); + free(key); + free(thumb_path); + free(thumb_key); + + return 1; +} + +static int +_ec_fdo_set(struct _Ethumbd_Child *ec, Ethumb *e) +{ + int r; + int value; + + r = _ec_read_safe(ec->pipein, &value, sizeof(value)); + if (!r) + return 0; + ethumb_thumb_fdo_set(e, value); + DBG("fdo = %d\n", value); + + return 1; +} + +static int +_ec_size_set(struct _Ethumbd_Child *ec, Ethumb *e) +{ + int r; + int w, h; + int type; + + r = _ec_read_safe(ec->pipein, &w, sizeof(w)); + if (!r) + return 0; + r = _ec_read_safe(ec->pipein, &type, sizeof(type)); + if (!r) + return 0; + r = _ec_read_safe(ec->pipein, &h, sizeof(h)); + if (!r) + return 0; + ethumb_thumb_size_set(e, w, h); + DBG("size = %dx%d\n", w, h); + + return 1; +} + +static int +_ec_format_set(struct _Ethumbd_Child *ec, Ethumb *e) +{ + int r; + int value; + + r = _ec_read_safe(ec->pipein, &value, sizeof(value)); + if (!r) + return 0; + ethumb_thumb_format_set(e, value); + DBG("format = %d\n", value); + + return 1; +} + +static int +_ec_aspect_set(struct _Ethumbd_Child *ec, Ethumb *e) +{ + int r; + int value; + + r = _ec_read_safe(ec->pipein, &value, sizeof(value)); + if (!r) + return 0; + ethumb_thumb_aspect_set(e, value); + DBG("aspect = %d\n", value); + + return 1; +} + +static int +_ec_crop_set(struct _Ethumbd_Child *ec, Ethumb *e) +{ + int r; + float x, y; + int type; + + r = _ec_read_safe(ec->pipein, &x, sizeof(x)); + if (!r) + return 0; + r = _ec_read_safe(ec->pipein, &type, sizeof(type)); + if (!r) + return 0; + r = _ec_read_safe(ec->pipein, &y, sizeof(y)); + if (!r) + return 0; + ethumb_thumb_crop_align_set(e, x, y); + DBG("crop = %fx%f\n", x, y); + + return 1; +} + +static int +_ec_frame_set(struct _Ethumbd_Child *ec, Ethumb *e) +{ + int r; + int type; + char *theme_file, *group, *swallow; + + r = _ec_pipe_str_read(ec, &theme_file); + if (!r) + return 0; + r = _ec_read_safe(ec->pipein, &type, sizeof(type)); + if (!r) + return 0; + r = _ec_pipe_str_read(ec, &group); + if (!r) + return 0; + r = _ec_read_safe(ec->pipein, &type, sizeof(type)); + if (!r) + return 0; + r = _ec_pipe_str_read(ec, &swallow); + if (!r) + return 0; + DBG("frame = %s:%s:%s\n", theme_file, group, swallow); + ethumb_frame_set(e, theme_file, group, swallow); + free(theme_file); + free(group); + free(swallow); + + return 1; +} + +static int +_ec_directory_set(struct _Ethumbd_Child *ec, Ethumb *e) +{ + int r; + char *directory; + + r = _ec_pipe_str_read(ec, &directory); + if (!r) + return 0; + ethumb_thumb_dir_path_set(e, directory); + DBG("directory = %s\n", directory); + free(directory); + + return 1; +} + +static int +_ec_category_set(struct _Ethumbd_Child *ec, Ethumb *e) +{ + int r; + char *category; + + r = _ec_pipe_str_read(ec, &category); + if (!r) + return 0; + ethumb_thumb_category_set(e, category); + DBG("category = %s\n", category); + free(category); + + return 1; +} + +static int +_ec_video_time_set(struct _Ethumbd_Child *ec, Ethumb *e) +{ + int r; + float value; + + r = _ec_read_safe(ec->pipein, &value, sizeof(value)); + if (!r) + return 0; + ethumb_video_time_set(e, value); + DBG("video_time = %f\n", value); + + return 1; +} + +static int +_ec_document_page_set(struct _Ethumbd_Child *ec, Ethumb *e) +{ + int r; + int value; + + r = _ec_read_safe(ec->pipein, &value, sizeof(value)); + if (!r) + return 0; + ethumb_document_page_set(e, value); + DBG("document_page = %d\n", value); + + return 1; +} + +static void +_ec_setup_process(struct _Ethumbd_Child *ec, int index, int type) +{ + Ethumb *e; + + e = ec->ethumbt[index]; + + switch (type) + { + case ETHUMBD_FDO: + _ec_fdo_set(ec, e); + break; + case ETHUMBD_SIZE_W: + _ec_size_set(ec, e); + break; + case ETHUMBD_FORMAT: + _ec_format_set(ec, e); + break; + case ETHUMBD_ASPECT: + _ec_aspect_set(ec, e); + break; + case ETHUMBD_CROP_X: + _ec_crop_set(ec, e); + break; + case ETHUMBD_FRAME_FILE: + _ec_frame_set(ec, e); + break; + case ETHUMBD_DIRECTORY: + _ec_directory_set(ec, e); + break; + case ETHUMBD_CATEGORY: + _ec_category_set(ec, e); + break; + case ETHUMBD_VIDEO_TIME: + _ec_video_time_set(ec, e); + break; + case ETHUMBD_DOCUMENT_PAGE: + _ec_document_page_set(ec, e); + break; + default: + ERR("wrong type!\n"); + } +} + +static int +_ec_op_setup(struct _Ethumbd_Child *ec) +{ + int r; + int index; + int type; + + r = _ec_read_safe(ec->pipein, &index, sizeof(index)); + if (!r) + return 0; + + r = _ec_read_safe(ec->pipein, &type, sizeof(type)); + if (!r) + return 0; + while (type != ETHUMBD_SETUP_FINISHED) + { + _ec_setup_process(ec, index, type); + r = _ec_read_safe(ec->pipein, &type, sizeof(type)); + if (!r) + return 0; + } + + return 1; +} + +static int +_ec_fd_handler(void *data, Ecore_Fd_Handler *fd_handler) +{ + struct _Ethumbd_Child *ec = data; + int op_id; + int r; + + if (ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_ERROR)) + { + ERR("error on pipein! child exiting...\n"); + ec->fd_handler = NULL; + ecore_main_loop_quit(); + return 0; + } + + r = _ec_read_safe(ec->pipein, &op_id, sizeof(op_id)); + if (!r) + { + DBG("ethumbd exited! child exiting...\n"); + ec->fd_handler = NULL; + ecore_main_loop_quit(); + return 0; + } + + DBG("received op: %d\n", op_id); + + r = 1; + switch (op_id) + { + case ETHUMBD_OP_NEW: + r = _ec_op_new(ec); + break; + case ETHUMBD_OP_GENERATE: + r = _ec_op_generate(ec); + break; + case ETHUMBD_OP_SETUP: + r = _ec_op_setup(ec); + break; + case ETHUMBD_OP_DEL: + r = _ec_op_del(ec); + break; + default: + ERR("invalid operation: %d\n", op_id); + r = 0; + } + + if (!r) + { + ERR("ethumbd exited! child exiting...\n"); + ec->fd_handler = NULL; + ecore_main_loop_quit(); + } + + return r; +} + +static void +_ec_setup(struct _Ethumbd_Child *ec) +{ + ec->fd_handler = ecore_main_fd_handler_add( + ec->pipein, ECORE_FD_READ | ECORE_FD_ERROR, + _ec_fd_handler, ec, NULL, NULL); +} + +void +ethumbd_child_start(int pipein, int pipeout) +{ + struct _Ethumbd_Child *ec; + + ethumb_init(); + + ec = _ec_new(pipein, pipeout); + + _ec_setup(ec); + + DBG("child started!\n"); + ecore_main_loop_begin(); + DBG("child finishing.\n"); + + _ec_free(ec); + + ethumb_shutdown(); +} diff --git a/legacy/ethumb/src/bin/ethumbd_private.h b/legacy/ethumb/src/bin/ethumbd_private.h new file mode 100644 index 0000000000..c67229effd --- /dev/null +++ b/legacy/ethumb/src/bin/ethumbd_private.h @@ -0,0 +1,34 @@ +#ifndef __ETHUMBD_PRIVATE_H__ +#define __ETHUMBD_PRIVATE_H__ 1 + + +enum Ethumbd_Operations +{ + ETHUMBD_OP_NEW, + ETHUMBD_OP_GENERATE, + ETHUMBD_OP_SETUP, + ETHUMBD_OP_DEL +}; + +enum Ethubmd_Setup_Option +{ + ETHUMBD_FDO, + ETHUMBD_SIZE_W, + ETHUMBD_SIZE_H, + ETHUMBD_FORMAT, + ETHUMBD_ASPECT, + ETHUMBD_CROP_X, + ETHUMBD_CROP_Y, + ETHUMBD_DIRECTORY, + ETHUMBD_CATEGORY, + ETHUMBD_FRAME_FILE, + ETHUMBD_FRAME_GROUP, + ETHUMBD_FRAME_SWALLOW, + ETHUMBD_VIDEO_TIME, + ETHUMBD_DOCUMENT_PAGE, + ETHUMBD_SETUP_FINISHED +}; + +void ethumbd_child_start(int pipein, int pipeout); + +#endif diff --git a/legacy/ethumb/src/lib/Makefile.am b/legacy/ethumb/src/lib/Makefile.am index 6fb0b1f59c..3508f7e471 100644 --- a/legacy/ethumb/src/lib/Makefile.am +++ b/legacy/ethumb/src/lib/Makefile.am @@ -1,5 +1,7 @@ MAINTAINERCLEANFILES = Makefile.in +SUBDIRS = . + AM_CPPFLAGS = \ -I$(top_srcdir) \ -I$(top_builddir) \ @@ -18,3 +20,8 @@ libethumb_la_DEPENDENCIES = $(top_builddir)/config.h libethumb_la_LIBADD = \ @EVAS_LIBS@ @ECORE_EVAS_LIBS@ @ECORE_FILE_LIBS@ @EDJE_LIBS@ libethumb_la_LDFLAGS = -version-info @version_info@ + + +if USE_MODULE_ETHUMBD +SUBDIRS += client +endif diff --git a/legacy/ethumb/src/lib/client/Ethumb_Client.c b/legacy/ethumb/src/lib/client/Ethumb_Client.c new file mode 100644 index 0000000000..622f49bcdb --- /dev/null +++ b/legacy/ethumb/src/lib/client/Ethumb_Client.c @@ -0,0 +1,1080 @@ +/** + * @file + * + * 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 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. + * + * 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. + * + * @author Rafael Antognolli + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include +#include +#include +#include "Ethumb_Client.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef PATH_MAX +#define PATH_MAX 4096 +#endif + +#include + +#define MAX_ID 2000000 + +#define DBG(...) EINA_ERROR_PDBG(__VA_ARGS__) +#define INF(...) EINA_ERROR_PINFO(__VA_ARGS__) +#define WRN(...) EINA_ERROR_PWARN(__VA_ARGS__) +#define ERR(...) EINA_ERROR_PERR(__VA_ARGS__) + +struct _Ethumb_Client +{ + Ethumb *ethumb; + int ethumb_dirty; + int connected; + long id_count; + + E_DBus_Connection *conn; + E_DBus_Signal_Handler *name_owner_changed_handler; + E_DBus_Signal_Handler *generated_signal; + DBusPendingCall *pending_get_name_owner; + const char *unique_name; + DBusPendingCall *pending_new; + ec_connect_callback_t connect_cb; + void *connect_cb_data; + Eina_List *pending_add; + Eina_List *pending_remove; + Eina_List *pending_gen; + DBusPendingCall *pending_clear; + DBusPendingCall *pending_setup; + void (*on_server_die_cb)(Ethumb_Client *client, void *data); + void *on_server_die_cb_data; + const char *object_path; +}; + +struct _ethumb_pending_add +{ + long id; + const char *file; + const char *key; + const char *thumb; + const char *thumb_key; + generated_callback_t generated_cb; + void *data; + DBusPendingCall *pending_call; + Ethumb_Client *client; +}; + +struct _ethumb_pending_remove +{ + long id; + void (*remove_cb)(Eina_Bool result, void *data); + void *data; + DBusPendingCall *pending_call; + Ethumb_Client *client; +}; + +struct _ethumb_pending_gen +{ + long id; + const char *file; + const char *key; + const char *thumb; + const char *thumb_key; + generated_callback_t generated_cb; + void *data; +}; + +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"; +static const char _ethumb_dbus_path[] = "/org/enlightenment/Ethumb"; +static const char fdo_interface[] = "org.freedesktop.DBus"; +static const char fdo_bus_name[] = "org.freedesktop.DBus"; +static const char fdo_path[] = "/org/freedesktop/DBus"; + +static int _initcount = 0; + +static void _ethumb_client_generated_cb(void *data, DBusMessage *msg); + +static inline bool +__dbus_callback_check_and_init(const char *file, int line, const char *function, DBusMessage *msg, DBusMessageIter *itr, DBusError *err) +{ + if (!msg) + { + ERR("%s:%d:%s() callback without message arguments!\n", + file, line, function); + + if (err) + ERR("%s:%d:%s() an error was reported by server: " + "name=\"%s\", message=\"%s\"\n", + 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", + file, line, function); + return 0; + } + + return 1; +} + +#define _dbus_callback_check_and_init(msg, itr, err) \ + __dbus_callback_check_and_init(__FILE__, __LINE__, __FUNCTION__, \ + msg, itr, err) + +static inline bool +__dbus_iter_type_check(int type, int expected, const char *expected_name) +{ + if (type == expected) + return 1; + + ERR("expected type %s (%c) but got %c instead!\n", + expected_name, expected, type); + + return 0; +} +#define _dbus_iter_type_check(t, e) __dbus_iter_type_check(t, e, #e) + +#define CHECK_NULL_RETURN(ptr, ...) \ + do \ + { \ + if ((ptr) == NULL) \ + { \ + ERR("%s == NULL!\n", #ptr); \ + return __VA_ARGS__; \ + } \ + } \ + while (0) + +static void +_ethumb_client_name_owner_changed(void *data, DBusMessage *msg) +{ + DBusError err; + const char *name, *from, *to; + Ethumb_Client *client = data; + + dbus_error_init(&err); + if (!dbus_message_get_args(msg, &err, + DBUS_TYPE_STRING, &name, + DBUS_TYPE_STRING, &from, + DBUS_TYPE_STRING, &to, + DBUS_TYPE_INVALID)) + { + ERR("could not get NameOwnerChanged arguments: %s: %s\n", + err.name, err.message); + dbus_error_free(&err); + return; + } + + if (strcmp(name, _ethumb_dbus_bus_name) != 0) + return; + + DBG("NameOwnerChanged from=[%s] to=[%s]\n", 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", + from, client->unique_name); + else + { + ERR("server exit!!!\n"); + if (client->on_server_die_cb) + client->on_server_die_cb(client, + client->on_server_die_cb_data); + } + } + else + DBG("unknown change from %s to %s\n", from, to); +} + +static void +_ethumb_client_new_cb(void *data, DBusMessage *msg, DBusError *error) +{ + DBusMessageIter iter; + const char *opath; + int t; + Ethumb_Client *client = data; + + client->pending_new = NULL; + + if (!_dbus_callback_check_and_init(msg, &iter, error)) + goto end_error; + t = dbus_message_iter_get_arg_type(&iter); + if (!_dbus_iter_type_check(t, DBUS_TYPE_OBJECT_PATH)) + goto end_error; + + dbus_message_iter_get_basic(&iter, &opath); + if (opath[0] == '\0') + goto end_error; + + client->object_path = eina_stringshare_add(opath); + + client->generated_signal = e_dbus_signal_handler_add( + client->conn, _ethumb_dbus_bus_name, opath, + _ethumb_dbus_objects_interface, "generated", + _ethumb_client_generated_cb, client); + + client->connect_cb(client, 1, client->connect_cb_data); + return; + +end_error: + client->connect_cb(client, 0, client->connect_cb_data); + return; +} + +static void +_ethumb_client_call_new(Ethumb_Client *client) +{ + DBusMessage *msg; + + msg = dbus_message_new_method_call(_ethumb_dbus_bus_name, _ethumb_dbus_path, + _ethumb_dbus_interface, "new"); + client->pending_new = e_dbus_message_send(client->conn, msg, + _ethumb_client_new_cb, -1, + client); + dbus_message_unref(msg); +} + +static void +_ethumb_client_get_name_owner(void *data, DBusMessage *msg, DBusError *err) +{ + DBusMessageIter iter; + const char *uid; + Ethumb_Client *client = data; + int t; + + client->pending_get_name_owner = NULL; + + if (!_dbus_callback_check_and_init(msg, &iter, err)) + goto error; + + t = dbus_message_iter_get_arg_type(&iter); + if (!_dbus_iter_type_check(t, DBUS_TYPE_STRING)) + goto error; + + dbus_message_iter_get_basic(&iter, &uid); + if (!uid) + { + ERR("no name owner!\n"); + goto error; + } + + DBG("unique name = %s\n", uid); + client->unique_name = eina_stringshare_add(uid); + + _ethumb_client_call_new(client); + client->connected = 1; + return; + +error: + client->connect_cb(client, 0, client->connect_cb_data); +} + +EAPI int +ethumb_client_init(void) +{ + if (_initcount) + return ++_initcount; + + ethumb_init(); + e_dbus_init(); + + return ++_initcount; +} + +EAPI int +ethumb_client_shutdown(void) +{ + _initcount--; + if (_initcount > 0) + return _initcount; + + e_dbus_shutdown(); + ethumb_shutdown(); + return _initcount; +} + +EAPI Ethumb_Client * +ethumb_client_connect(ec_connect_callback_t connect_cb, void *data) +{ + Ethumb_Client *eclient; + + EINA_SAFETY_ON_NULL_RETURN_VAL(connect_cb, NULL); + + eclient = calloc(1, sizeof(*eclient)); + if (!eclient) + { + ERR("could not allocate Ethumb_Client structure.\n"); + goto err; + } + + eclient->connect_cb = connect_cb; + eclient->connect_cb_data = data; + + eclient->ethumb = ethumb_new(); + if (!eclient->ethumb) + { + ERR("could not create ethumb handler.\n"); + goto ethumb_new_err; + } + + eclient->conn = e_dbus_bus_get(DBUS_BUS_SESSION); + if (!eclient->conn) + { + ERR("could not connect to session bus.\n"); + goto connection_err; + } + + eclient->name_owner_changed_handler = e_dbus_signal_handler_add( + eclient->conn, fdo_bus_name, fdo_path, fdo_interface, + "NameOwnerChanged", _ethumb_client_name_owner_changed, eclient); + + eclient->pending_get_name_owner = e_dbus_get_name_owner( + eclient->conn, _ethumb_dbus_bus_name, _ethumb_client_get_name_owner, + eclient); + if (!eclient->pending_get_name_owner) + { + ERR("could not create a get_name_owner request.\n"); + goto connection_err; + } + + return eclient; + +connection_err: + ethumb_free(eclient->ethumb); +ethumb_new_err: + free(eclient); +err: + return NULL; +} + +EAPI void +ethumb_client_disconnect(Ethumb_Client *client) +{ + Eina_List *l; + + EINA_SAFETY_ON_NULL_RETURN(client); + + if (!client->connected) + goto end_connection; + + ethumb_client_queue_clear(client); + l = client->pending_remove; + while (l) + { + struct _ethumb_pending_remove *pending = l->data; + l = eina_list_remove_list(l, l); + dbus_pending_call_cancel(pending->pending_call); + dbus_pending_call_unref(pending->pending_call); + free(pending); + } + + l = client->pending_gen; + while (l) + { + struct _ethumb_pending_gen *pending = l->data; + l = eina_list_remove_list(l, l); + free(pending); + } + +end_connection: + if (client->object_path) + eina_stringshare_del(client->object_path); + + if (client->pending_new) + dbus_pending_call_cancel(client->pending_new); + + if (client->unique_name) + eina_stringshare_del(client->unique_name); + + if (client->pending_get_name_owner) + dbus_pending_call_cancel(client->pending_get_name_owner); + + ethumb_free(client->ethumb); + + e_dbus_signal_handler_del(client->conn, client->name_owner_changed_handler); + if (client->connected) + e_dbus_signal_handler_del(client->conn, client->generated_signal); + e_dbus_connection_close(client->conn); + + free(client); +} + +EAPI void +ethumb_client_on_server_die_callback_set(Ethumb_Client *client, void (*on_server_die_cb)(Ethumb_Client *client, void *data), void *data) +{ + client->on_server_die_cb = on_server_die_cb; + client->on_server_die_cb_data = data; +} + +static void +_ethumb_client_ethumb_setup_cb(void *data, DBusMessage *msg, DBusError *error) +{ + DBusMessageIter iter; + int t, result = 0; + Ethumb_Client *client = data; + + client->pending_setup = NULL; + + if (!_dbus_callback_check_and_init(msg, &iter, error)) + return; + + t = dbus_message_iter_get_arg_type(&iter); + if (!_dbus_iter_type_check(t, DBUS_TYPE_BOOLEAN)) + return; + + dbus_message_iter_get_basic(&iter, &result); +} + +static const char * +_ethumb_client_dbus_get_bytearray(DBusMessageIter *iter) +{ + int el_type; + int length; + DBusMessageIter riter; + const char *result; + + el_type = dbus_message_iter_get_element_type(iter); + if (el_type != DBUS_TYPE_BYTE) + { + ERR("not an byte array element.\n"); + return NULL; + } + + dbus_message_iter_recurse(iter, &riter); + dbus_message_iter_get_fixed_array(&riter, &result, &length); + + if (result[0] == '\0') + return NULL; + else + return eina_stringshare_add(result); +} + +static void +_ethumb_client_dbus_append_bytearray(DBusMessageIter *iter, const char *string) +{ + DBusMessageIter viter; + + if (!string) + string = ""; + + dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "y", &viter); + dbus_message_iter_append_fixed_array(&viter, DBUS_TYPE_BYTE, &string, + strlen(string) + 1); + dbus_message_iter_close_container(iter, &viter); +} + +EAPI void +ethumb_client_ethumb_setup(Ethumb_Client *client) +{ + DBusMessage *msg; + DBusMessageIter iter, aiter, diter, viter, vaiter; + Ethumb *e = client->ethumb; + const char *entry; + int tw, th, format, aspect; + float cx, cy; + const char *theme_file, *group, *swallow; + const char *directory, *category; + float video_time; + int document_page; + + EINA_SAFETY_ON_NULL_RETURN(client); + client->ethumb_dirty = 0; + + msg = dbus_message_new_method_call(_ethumb_dbus_bus_name, + client->object_path, + _ethumb_dbus_objects_interface, + "ethumb_setup"); + dbus_message_iter_init_append(msg, &iter); + dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &aiter); + +#define _open_variant_iter(str_entry, str_type, end_iter) \ + entry = str_entry; \ + dbus_message_iter_open_container(&aiter, DBUS_TYPE_DICT_ENTRY, NULL, &diter); \ + dbus_message_iter_append_basic(&diter, DBUS_TYPE_STRING, &entry); \ + dbus_message_iter_open_container(&diter, DBUS_TYPE_VARIANT, str_type, \ + &end_iter); + +#define _close_variant_iter(end_iter) \ + dbus_message_iter_close_container(&diter, &end_iter); \ + dbus_message_iter_close_container(&aiter, &diter); + + /* starting array elements */ + + _open_variant_iter("size", "(ii)", viter); + dbus_message_iter_open_container(&viter, DBUS_TYPE_STRUCT, NULL, &vaiter); + ethumb_thumb_size_get(e, &tw, &th); + dbus_message_iter_append_basic(&vaiter, DBUS_TYPE_INT32, &tw); + dbus_message_iter_append_basic(&vaiter, DBUS_TYPE_INT32, &th); + dbus_message_iter_close_container(&viter, &vaiter); + _close_variant_iter(viter); + + _open_variant_iter("format", "i", viter); + format = ethumb_thumb_format_get(e); + dbus_message_iter_append_basic(&viter, DBUS_TYPE_INT32, &format); + _close_variant_iter(viter); + + _open_variant_iter("aspect", "i", viter); + aspect = ethumb_thumb_aspect_get(e); + dbus_message_iter_append_basic(&viter, DBUS_TYPE_INT32, &aspect); + _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); + dbus_message_iter_append_basic(&vaiter, DBUS_TYPE_DOUBLE, &cx); + dbus_message_iter_append_basic(&vaiter, DBUS_TYPE_DOUBLE, &cy); + dbus_message_iter_close_container(&viter, &vaiter); + _close_variant_iter(viter); + + _open_variant_iter("frame", "(ayayay)", viter); + dbus_message_iter_open_container(&viter, DBUS_TYPE_STRUCT, NULL, &vaiter); + ethumb_frame_get(e, &theme_file, &group, &swallow); + _ethumb_client_dbus_append_bytearray(&vaiter, theme_file); + _ethumb_client_dbus_append_bytearray(&vaiter, group); + _ethumb_client_dbus_append_bytearray(&vaiter, swallow); + dbus_message_iter_close_container(&viter, &vaiter); + _close_variant_iter(viter); + + _open_variant_iter("directory", "ay", viter); + directory = ethumb_thumb_dir_path_get(e); + _ethumb_client_dbus_append_bytearray(&viter, directory); + _close_variant_iter(viter); + + _open_variant_iter("category", "ay", viter); + category = ethumb_thumb_category_get(e); + _ethumb_client_dbus_append_bytearray(&viter, category); + _close_variant_iter(viter); + + _open_variant_iter("video_time", "d", viter); + video_time = ethumb_video_time_get(e); + dbus_message_iter_append_basic(&viter, DBUS_TYPE_DOUBLE, &video_time); + _close_variant_iter(viter); + + _open_variant_iter("document_page", "i", viter); + document_page = ethumb_document_page_get(e); + dbus_message_iter_append_basic(&viter, DBUS_TYPE_INT32, &document_page); + _close_variant_iter(viter); + +#undef _open_variant_iter +#undef _close_variant_iter + + dbus_message_iter_close_container(&iter, &aiter); + + client->pending_setup = e_dbus_message_send(client->conn, msg, + _ethumb_client_ethumb_setup_cb, + -1, client); + dbus_message_unref(msg); +} + +static void +_ethumb_client_generated_cb(void *data, DBusMessage *msg) +{ + DBusMessageIter iter; + long id = -1; + const char *thumb; + const char *thumb_key; + Ethumb_Client *client = data; + int t; + int success; + Eina_List *l; + int found; + struct _ethumb_pending_gen *pending; + + dbus_message_iter_init(msg, &iter); + + t = dbus_message_iter_get_arg_type(&iter); + if (!_dbus_iter_type_check(t, DBUS_TYPE_INT64)) + goto end; + dbus_message_iter_get_basic(&iter, &id); + dbus_message_iter_next(&iter); + + t = dbus_message_iter_get_arg_type(&iter); + if (!_dbus_iter_type_check(t, DBUS_TYPE_ARRAY)) + goto end; + thumb = _ethumb_client_dbus_get_bytearray(&iter); + dbus_message_iter_next(&iter); + + t = dbus_message_iter_get_arg_type(&iter); + if (!_dbus_iter_type_check(t, DBUS_TYPE_ARRAY)) + goto end; + thumb_key = _ethumb_client_dbus_get_bytearray(&iter); + dbus_message_iter_next(&iter); + + t = dbus_message_iter_get_arg_type(&iter); + if (!_dbus_iter_type_check(t, DBUS_TYPE_BOOLEAN)) + goto end; + dbus_message_iter_get_basic(&iter, &success); + + found = 0; + l = client->pending_gen; + while (l) + { + pending = l->data; + if (pending->id == id) + { + found = 1; + break; + } + l = l->next; + } + + if (found) + { + client->pending_gen = eina_list_remove_list(client->pending_gen, l); + pending->generated_cb(id, pending->file, pending->key, success, + pending->data); + eina_stringshare_del(pending->file); + eina_stringshare_del(pending->key); + eina_stringshare_del(pending->thumb); + eina_stringshare_del(pending->thumb_key); + free(pending); + } + +end: + eina_stringshare_del(thumb); + eina_stringshare_del(thumb_key); +} + +static void +_ethumb_client_queue_add_cb(void *data, DBusMessage *msg, DBusError *error) +{ + DBusMessageIter iter; + int t; + long id = -1; + struct _ethumb_pending_add *pending = data; + struct _ethumb_pending_gen *generating; + Ethumb_Client *client = pending->client; + + client->pending_add = eina_list_remove(client->pending_add, pending); + + if (!_dbus_callback_check_and_init(msg, &iter, error)) + goto end; + + t = dbus_message_iter_get_arg_type(&iter); + if (!_dbus_iter_type_check(t, DBUS_TYPE_INT64)) + goto end; + + dbus_message_iter_get_basic(&iter, &id); + + generating = calloc(1, sizeof(*generating)); + generating->id = id; + generating->file = pending->file; + generating->key = pending->key; + generating->thumb = pending->thumb; + generating->thumb_key = pending->thumb_key; + generating->generated_cb = pending->generated_cb; + generating->data = pending->data; + client->pending_gen = eina_list_append(client->pending_gen, generating); + +end: + free(pending); +} + +static long +_ethumb_client_queue_add(Ethumb_Client *client, const char *file, const char *key, const char *thumb, const char *thumb_key, generated_callback_t generated_cb, void *data) +{ + DBusMessage *msg; + DBusMessageIter iter; + struct _ethumb_pending_add *pending; + + + pending = calloc(1, sizeof(*pending)); + pending->id = client->id_count; + pending->file = eina_stringshare_add(file); + pending->key = eina_stringshare_add(key); + pending->thumb = eina_stringshare_add(thumb); + pending->thumb_key = eina_stringshare_add(thumb_key); + pending->generated_cb = generated_cb; + pending->data = data; + pending->client = client; + + client->id_count = (client->id_count + 1) % MAX_ID; + + msg = dbus_message_new_method_call(_ethumb_dbus_bus_name, + client->object_path, + _ethumb_dbus_objects_interface, + "queue_add"); + + dbus_message_iter_init_append(msg, &iter); + dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT64, &pending->id); + _ethumb_client_dbus_append_bytearray(&iter, file); + _ethumb_client_dbus_append_bytearray(&iter, key); + _ethumb_client_dbus_append_bytearray(&iter, thumb); + _ethumb_client_dbus_append_bytearray(&iter, thumb_key); + + pending->pending_call = e_dbus_message_send(client->conn, msg, + _ethumb_client_queue_add_cb, + -1, pending); + client->pending_add = eina_list_append(client->pending_add, pending); + dbus_message_unref(msg); + + return pending->id; +} + +static void +_ethumb_client_queue_remove_cb(void *data, DBusMessage *msg, DBusError *error) +{ + DBusMessageIter iter; + int t; + int success = 0; + struct _ethumb_pending_remove *pending = data; + Ethumb_Client *client = pending->client; + + client->pending_remove = eina_list_remove(client->pending_remove, pending); + + if (!_dbus_callback_check_and_init(msg, &iter, error)) + goto end; + + t = dbus_message_iter_get_arg_type(&iter); + if (!_dbus_iter_type_check(t, DBUS_TYPE_BOOLEAN)) + goto end; + + dbus_message_iter_get_basic(&iter, &success); + +end: + if (pending->remove_cb) + pending->remove_cb(success, pending->data); + free(pending); +} + +EAPI void +ethumb_client_queue_remove(Ethumb_Client *client, long id, void (*queue_remove_cb)(Eina_Bool success, void *data), void *data) +{ + DBusMessage *msg; + struct _ethumb_pending_remove *pending; + Eina_List *l; + int found; + EINA_SAFETY_ON_NULL_RETURN(client); + + pending = calloc(1, sizeof(*pending)); + pending->id = id; + pending->remove_cb = queue_remove_cb; + pending->data = data; + pending->client = client; + + msg = dbus_message_new_method_call(_ethumb_dbus_bus_name, + client->object_path, + _ethumb_dbus_objects_interface, + "queue_remove"); + + dbus_message_append_args(msg, DBUS_TYPE_INT64, &id, DBUS_TYPE_INVALID); + pending->pending_call = e_dbus_message_send(client->conn, msg, + _ethumb_client_queue_remove_cb, + -1, pending); + client->pending_remove = eina_list_append(client->pending_remove, pending); + + found = 0; + l = client->pending_add; + while (l) + { + struct _ethumb_pending_add *pending = l->data; + if (pending->id != id) + { + l = l->next; + continue; + } + l = eina_list_remove_list(l, 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); + free(pending); + found = 1; + break; + } + + if (found) + goto end; + + l = client->pending_gen; + while (l) + { + struct _ethumb_pending_gen *pending = l->data; + if (pending->id != id) + { + l = l->next; + continue; + } + l = eina_list_remove_list(l, l); + eina_stringshare_del(pending->file); + eina_stringshare_del(pending->key); + eina_stringshare_del(pending->thumb); + eina_stringshare_del(pending->thumb_key); + free(pending); + found = 1; + break; + } + +end: + dbus_message_unref(msg); +} + +static void +_ethumb_client_queue_clear_cb(void *data, DBusMessage *msg, DBusError *error) +{ + Ethumb_Client *client = data; + + client->pending_clear = NULL; +} + +EAPI void +ethumb_client_queue_clear(Ethumb_Client *client) +{ + DBusMessage *msg; + EINA_SAFETY_ON_NULL_RETURN(client); + + if (client->pending_clear) + return; + + msg = dbus_message_new_method_call(_ethumb_dbus_bus_name, + client->object_path, + _ethumb_dbus_objects_interface, + "queue_clear"); + + client->pending_clear = e_dbus_message_send(client->conn, msg, + _ethumb_client_queue_clear_cb, + -1, client); + dbus_message_unref(msg); +} + +EAPI void +ethumb_client_fdo_set(Ethumb_Client *client, Ethumb_Thumb_FDO_Size s) +{ + EINA_SAFETY_ON_NULL_RETURN(client); + + client->ethumb_dirty = 1; + ethumb_thumb_fdo_set(client->ethumb, s); +} + +EAPI void +ethumb_client_size_set(Ethumb_Client *client, int tw, int th) +{ + EINA_SAFETY_ON_NULL_RETURN(client); + + client->ethumb_dirty = 1; + ethumb_thumb_size_set(client->ethumb, tw, th); +} + +EAPI void +ethumb_client_size_get(const Ethumb_Client *client, int *tw, int *th) +{ + EINA_SAFETY_ON_NULL_RETURN(client); + + ethumb_thumb_size_get(client->ethumb, tw, th); +} + +EAPI void +ethumb_client_format_set(Ethumb_Client *client, Ethumb_Thumb_Format f) +{ + EINA_SAFETY_ON_NULL_RETURN(client); + + client->ethumb_dirty = 1; + ethumb_thumb_format_set(client->ethumb, f); +} + +EAPI Ethumb_Thumb_Format +ethumb_client_format_get(const Ethumb_Client *client) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(client, 0); + + return ethumb_thumb_format_get(client->ethumb); +} + +EAPI void +ethumb_client_aspect_set(Ethumb_Client *client, Ethumb_Thumb_Aspect a) +{ + EINA_SAFETY_ON_NULL_RETURN(client); + + client->ethumb_dirty = 1; + ethumb_thumb_aspect_set(client->ethumb, a); +} + +EAPI Ethumb_Thumb_Aspect +ethumb_client_aspect_get(const Ethumb_Client *client) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(client, 0); + + return ethumb_thumb_aspect_get(client->ethumb); +} + +EAPI void +ethumb_client_crop_align_set(Ethumb_Client *client, float x, float y) +{ + EINA_SAFETY_ON_NULL_RETURN(client); + + client->ethumb_dirty = 1; + ethumb_thumb_crop_align_set(client->ethumb, x, y); +} + +EAPI void +ethumb_client_crop_align_get(const Ethumb_Client *client, float *x, float *y) +{ + EINA_SAFETY_ON_NULL_RETURN(client); + + ethumb_thumb_crop_align_get(client->ethumb, x, y); +} + +EAPI Eina_Bool +ethumb_client_frame_set(Ethumb_Client *client, const char *file, const char *group, const char *swallow) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(client, 0); + + client->ethumb_dirty = 1; + return ethumb_frame_set(client->ethumb, file, group, swallow); +} + +EAPI void +ethumb_client_dir_path_set(Ethumb_Client *client, const char *path) +{ + EINA_SAFETY_ON_NULL_RETURN(client); + + client->ethumb_dirty = 1; + ethumb_thumb_dir_path_set(client->ethumb, path); +} + +EAPI const char * +ethumb_client_dir_path_get(const Ethumb_Client *client) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(client, NULL); + + return ethumb_thumb_dir_path_get(client->ethumb); +} + +EAPI void +ethumb_client_category_set(Ethumb_Client *client, const char *category) +{ + EINA_SAFETY_ON_NULL_RETURN(client); + + client->ethumb_dirty = 1; + ethumb_thumb_category_set(client->ethumb, category); +} + +EAPI const char * +ethumb_client_category_get(const Ethumb_Client *client) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(client, NULL); + + return ethumb_thumb_category_get(client->ethumb); +} + +EAPI void +ethumb_client_video_time_set(Ethumb_Client *client, float time) +{ + EINA_SAFETY_ON_NULL_RETURN(client); + + client->ethumb_dirty = 1; + ethumb_video_time_set(client->ethumb, time); +} + +EAPI void +ethumb_client_document_page_set(Ethumb_Client *client, int page) +{ + EINA_SAFETY_ON_NULL_RETURN(client); + + client->ethumb_dirty = 1; + ethumb_document_page_set(client->ethumb, page); +} + +EAPI Eina_Bool +ethumb_client_file_set(Ethumb_Client *client, const char *path, const char *key) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(client, 0); + + return ethumb_file_set(client->ethumb, path, key); +} + +EAPI void +ethumb_client_file_get(Ethumb_Client *client, const char **path, const char **key) +{ + EINA_SAFETY_ON_NULL_RETURN(client); + + ethumb_file_get(client->ethumb, path, key); +} + +EAPI void +ethumb_client_file_free(Ethumb_Client *client) +{ + EINA_SAFETY_ON_NULL_RETURN(client); + + ethumb_file_free(client->ethumb); +} + +EAPI void +ethumb_client_thumb_path_set(Ethumb_Client *client, const char *path, const char *key) +{ + EINA_SAFETY_ON_NULL_RETURN(client); + + ethumb_thumb_path_set(client->ethumb, path, key); +} + +EAPI void +ethumb_client_thumb_path_get(Ethumb_Client *client, const char **path, const char **key) +{ + EINA_SAFETY_ON_NULL_RETURN(client); + + ethumb_thumb_path_get(client->ethumb, path, key); +} + +EAPI Eina_Bool +ethumb_client_thumb_exists(Ethumb_Client *client) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(client, 0); + + return ethumb_exists(client->ethumb); +} + +EAPI long +ethumb_client_generate(Ethumb_Client *client, generated_callback_t generated_cb, void *data) +{ + const char *file, *key, *thumb, *thumb_key; + long id; + EINA_SAFETY_ON_NULL_RETURN_VAL(client, -1); + + ethumb_file_get(client->ethumb, &file, &key); + if (!file) + { + ERR("no file set.\n"); + return 0; + } + + ethumb_thumb_path_get(client->ethumb, &thumb, &thumb_key); + + if (client->ethumb_dirty) + ethumb_client_ethumb_setup(client); + id = _ethumb_client_queue_add(client, file, key, thumb, thumb_key, + generated_cb, data); + + return id; +} diff --git a/legacy/ethumb/src/lib/client/Ethumb_Client.h b/legacy/ethumb/src/lib/client/Ethumb_Client.h new file mode 100644 index 0000000000..54bca88816 --- /dev/null +++ b/legacy/ethumb/src/lib/client/Ethumb_Client.h @@ -0,0 +1,85 @@ +#ifndef __ETHUMB_CLIENT_H__ +#define __ETHUMB_CLIENT_H__ 1 + +#ifndef EAPI +#ifdef _WIN32 +# ifdef EFL_EVAS_BUILD +# ifdef DLL_EXPORT +# define EAPI __declspec(dllexport) +# define GNUC_NULL_TERMINATED +# else +# define EAPI +# define GNUC_NULL_TERMINATED +# endif /* ! DLL_EXPORT */ +# else +# define EAPI __declspec(dllimport) +# define GNUC_NULL_TERMINATED +# endif /* ! EFL_EVAS_BUILD */ +#else +# ifdef __GNUC__ +# if __GNUC__ >= 4 +# define EAPI __attribute__ ((visibility("default"))) +# define GNUC_NULL_TERMINATED __attribute__((__sentinel__)) +# else +# define EAPI +# define GNUC_NULL_TERMINATED +# endif +# else +# define EAPI +# define GNUC_NULL_TERMINATED +# endif +#endif /* ! _WIN32 */ +#endif /* EAPI */ + +#include "Ethumb.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct _Ethumb_Client Ethumb_Client; +typedef void (*ec_connect_callback_t)(Ethumb_Client *client, Eina_Bool success, void *data); +typedef void (*generated_callback_t)(long id, const char *file, const char *key, Eina_Bool success, void *data); + +EAPI int ethumb_client_init(void); +EAPI int ethumb_client_shutdown(void); + +EAPI Ethumb_Client * ethumb_client_connect(ec_connect_callback_t connect_cb, void *data); +EAPI void ethumb_client_disconnect(Ethumb_Client *client); +EAPI void ethumb_client_on_server_die_callback_set(Ethumb_Client *client, void (*on_server_die_cb)(Ethumb_Client *client, void *data), void *data); + +EAPI void ethumb_client_queue_remove(Ethumb_Client *client, long id, void (*queue_remove_cb)(Eina_Bool success, void *data), void *data); +EAPI void ethumb_client_queue_clear(Ethumb_Client *client); + +EAPI void ethumb_client_fdo_set(Ethumb_Client *client, Ethumb_Thumb_FDO_Size s); +EAPI void ethumb_client_size_set(Ethumb_Client *client, int tw, int th); +EAPI void ethumb_client_size_get(const Ethumb_Client *client, int *tw, int *th); +EAPI void ethumb_client_format_set(Ethumb_Client *client, Ethumb_Thumb_Format f); +EAPI Ethumb_Thumb_Format ethumb_client_format_get(const Ethumb_Client *client); +EAPI void ethumb_client_aspect_set(Ethumb_Client *client, Ethumb_Thumb_Aspect a); +EAPI Ethumb_Thumb_Aspect ethumb_client_aspect_get(const Ethumb_Client *client); +EAPI void ethumb_client_crop_align_set(Ethumb_Client *client, float x, float y); +EAPI void ethumb_client_crop_align_get(const Ethumb_Client *client, float *x, float *y); +EAPI Eina_Bool ethumb_client_frame_set(Ethumb_Client *client, const char *file, const char *group, const char *swallow); +EAPI void ethumb_client_dir_path_set(Ethumb_Client *client, const char *path); +EAPI const char * ethumb_client_dir_path_get(const Ethumb_Client *client); +EAPI void ethumb_client_category_set(Ethumb_Client *client, const char *category); +EAPI const char * ethumb_client_category_get(const Ethumb_Client *client); +EAPI void ethumb_client_video_time_set(Ethumb_Client *client, float time); +EAPI void ethumb_client_document_page_set(Ethumb_Client *client, int page); + +EAPI void ethumb_client_ethumb_setup(Ethumb_Client *client); + +EAPI Eina_Bool ethumb_client_file_set(Ethumb_Client *client, const char *path, const char *key); +EAPI void ethumb_client_file_get(Ethumb_Client *client, const char **path, const char **key); +EAPI void ethumb_client_file_free(Ethumb_Client *client); + +EAPI void ethumb_client_thumb_path_set(Ethumb_Client *client, const char *path, const char *key); +EAPI void ethumb_client_thumb_path_get(Ethumb_Client *client, const char **path, const char **key); +EAPI Eina_Bool ethumb_client_thumb_exists(Ethumb_Client *client); +EAPI long ethumb_client_generate(Ethumb_Client *client, generated_callback_t generated_cb, void *data); + +#ifdef __cplusplus +} +#endif +#endif /* __ETHUMB_CLIENT_H__ */ diff --git a/legacy/ethumb/src/lib/client/Makefile.am b/legacy/ethumb/src/lib/client/Makefile.am new file mode 100644 index 0000000000..542d347958 --- /dev/null +++ b/legacy/ethumb/src/lib/client/Makefile.am @@ -0,0 +1,21 @@ +MAINTAINERCLEANFILES = Makefile.in + +AM_CPPFLAGS = \ + -I$(top_srcdir) \ + -I$(top_builddir) \ + -I$(top_srcdir)/src/lib \ + @EDBUS_CFLAGS@ + +include_HEADERS = Ethumb_Client.h + +lib_LTLIBRARIES = libethumb_client.la + +libethumb_client_la_SOURCES = \ + Ethumb_Client.c +libethumb_client_la_DEPENDENCIES = $(top_builddir)/config.h +libethumb_client_la_LIBADD = \ + $(top_builddir)/src/lib/libethumb.la \ + @EDBUS_LIBS@ +libethumb_client_la_LDFLAGS = -version-info @version_info@ + +# @EVAS_LIBS@ @ECORE_EVAS_LIBS@ @ECORE_FILE_LIBS@ @EDJE_LIBS@ diff --git a/legacy/ethumb/src/tests/Makefile.am b/legacy/ethumb/src/tests/Makefile.am new file mode 100644 index 0000000000..fa6cfb6b51 --- /dev/null +++ b/legacy/ethumb/src/tests/Makefile.am @@ -0,0 +1,22 @@ +MAINTAINERCLEANFILES = Makefile.in + +AM_CPPFLAGS = \ + -I$(top_srcdir)/src/lib \ + -I$(top_srcdir)/src/lib/client \ + @EINA_CFLAGS@ @EVAS_CFLAGS@ @ECORE_CFLAGS@ @ECORE_EVAS_CFLAGS@ \ + @EDJE_CFLAGS@ @ECORE_FILE_CFLAGS@ + +check_PROGRAMS = + +if USE_MODULE_ETHUMBD + +AM_CPPFLAGS += @EDBUS_CFLAGS@ +check_PROGRAMS += ethumb_dbus +ethumb_dbus_SOURCES = ethumb_dbus.c +ethumb_dbus_LDADD = \ + @EINA_LIBS@ @EVAS_LIBS@ @ECORE_LIBS@ @ECORE_EVAS_LIBS@ @EDJE_LIBS@ \ + @ECORE_FILE_LIBS@ @EDBUS_LIBS@ \ + $(top_builddir)/src/lib/libethumb.la \ + $(top_builddir)/src/lib/client/libethumb_client.la + +endif diff --git a/legacy/ethumb/src/tests/ethumb_dbus.c b/legacy/ethumb/src/tests/ethumb_dbus.c new file mode 100644 index 0000000000..f92d6f106f --- /dev/null +++ b/legacy/ethumb/src/tests/ethumb_dbus.c @@ -0,0 +1,135 @@ +/** + * @file + * + * 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 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. + * + * 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. + * + * @author Rafael Antognolli + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void +_on_server_die_cb(Ethumb_Client *client, void *data) +{ + ecore_main_loop_quit(); +} + +static void +_queue_add_cb(long id, const char *file, const char *key, Eina_Bool success, void *data) +{ + fprintf(stderr, ">>> file ready: %s; id = %ld\n", file, id); +} + +static void +_disconnect(Ethumb_Client *client) +{ + ethumb_client_disconnect(client); +} + +static void +_request_thumbnails(Ethumb_Client *client, void *data) +{ + const char *path = data; + DIR *dir; + struct dirent *de; + char buf[PATH_MAX]; + int i; + + dir = opendir(path); + if (!dir) + { + fprintf(stderr, "ERROR: could not open directory: %s\n", path); + return; + } + + ethumb_client_format_set(client, ETHUMB_THUMB_JPEG); + ethumb_client_aspect_set(client, ETHUMB_THUMB_CROP); + ethumb_client_crop_align_set(client, 0.2, 0.2); + ethumb_client_size_set(client, 192, 192); + ethumb_client_category_set(client, "custom"); + + while ((de = readdir(dir))) + { + if (de->d_type != DT_REG) + continue; + snprintf(buf, sizeof(buf), "%s/%s", path, de->d_name); + ethumb_client_file_set(client, buf, NULL); + ethumb_client_generate(client, _queue_add_cb, NULL); + } + + for (i = 100; i < 200; i++) + { + ethumb_client_queue_remove(client, i, NULL, NULL); + } + + closedir(dir); +} + +static void +_connect_cb(Ethumb_Client *client, Eina_Bool success, void *data) +{ + fprintf(stderr, "connected: %d\n", success); + if (!success) + { + ecore_main_loop_quit(); + return; + } + + _request_thumbnails(client, data); +} + +int +main(int argc, char *argv[]) +{ + Ethumb_Client *client; + + if (argc < 2) + { + fprintf(stderr, "ERROR: directory not specified.\n"); + fprintf(stderr, "usage:\n\tethumb_dbus \n"); + return -2; + } + + ethumb_client_init(); + client = ethumb_client_connect(_connect_cb, argv[1]); + if (!client) + { + fprintf(stderr, "ERROR: couldn't connect to server.\n"); + ethumb_client_shutdown(); + return -1; + } + ethumb_client_on_server_die_callback_set(client, _on_server_die_cb, NULL); + + fprintf(stderr, "*** debug\n"); + ecore_main_loop_begin(); + + _disconnect(client); + + ethumb_client_shutdown(); + + return 0; +}