Welcome Ethumb, it's ready to get out of PROTO.
authorbarbieri <barbieri@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Sat, 12 Sep 2009 18:39:04 +0000 (18:39 +0000)
committerbarbieri <barbieri@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Sat, 12 Sep 2009 18:39:04 +0000 (18:39 +0000)
Ethumb is a library that generate thumbnails (little images) of
files. By default it supports any file Evas loads, like JPG, PNG,
TIFF, XPM and so on. It is extensible with plugins, shipping with
video thumbnails using emotion (even animated using Edje!), edje, and
epdf.  Please help by writing eps, edvi, fonts, eyelight
presentations, ...

It is recommended that users use Ethumb_Client API and not direct the
thumbnail client.

git-svn-id: svn+ssh://svn.enlightenment.org/var/svn/e/trunk/ethumb@42451 7cbeb6ba-43b4-40fd-8cce-4c39aea84d33

58 files changed:
ABOUT-NLS [new file with mode: 0644]
AUTHORS [new file with mode: 0644]
BUGS [new file with mode: 0644]
COPYING [new file with mode: 0644]
ChangeLog [new file with mode: 0644]
INSTALL [new file with mode: 0644]
Makefile.am [new file with mode: 0644]
NEWS [new file with mode: 0644]
README [new file with mode: 0644]
TODO [new file with mode: 0644]
autogen.sh [new file with mode: 0755]
configure.ac [new file with mode: 0644]
data/Makefile.am [new file with mode: 0644]
data/frames/Makefile.am [new file with mode: 0644]
data/frames/default.edc [new file with mode: 0644]
data/frames/images/border-0.jpg [new file with mode: 0644]
debian/changelog [new file with mode: 0644]
debian/compat [new file with mode: 0644]
debian/control [new file with mode: 0644]
debian/copyright [new file with mode: 0644]
debian/rules [new file with mode: 0755]
ethumb.pc.in [new file with mode: 0644]
ethumb_client.pc.in [new file with mode: 0644]
m4/Makefile.am [new file with mode: 0644]
m4/ac-modules.m4 [new file with mode: 0644]
m4/ac_attribute.m4 [new file with mode: 0644]
m4/as-expand.m4 [new file with mode: 0644]
m4/iconv.m4 [new file with mode: 0644]
m4/lib-ld.m4 [new file with mode: 0644]
m4/lib-link.m4 [new file with mode: 0644]
m4/lib-prefix.m4 [new file with mode: 0644]
m4/progtest.m4 [new file with mode: 0644]
org.enlightenment.Ethumb.service.in [new file with mode: 0644]
src/Makefile.am [new file with mode: 0644]
src/bin/Makefile.am [new file with mode: 0644]
src/bin/ethumb.c [new file with mode: 0644]
src/bin/ethumbd.c [new file with mode: 0644]
src/bin/ethumbd_child.c [new file with mode: 0644]
src/bin/ethumbd_client.c [new file with mode: 0644]
src/bin/ethumbd_private.h [new file with mode: 0644]
src/lib/Ethumb.c [new file with mode: 0644]
src/lib/Ethumb.h [new file with mode: 0644]
src/lib/Ethumb_Plugin.h [new file with mode: 0644]
src/lib/Makefile.am [new file with mode: 0644]
src/lib/client/Ethumb_Client.c [new file with mode: 0644]
src/lib/client/Ethumb_Client.h [new file with mode: 0644]
src/lib/client/Makefile.am [new file with mode: 0644]
src/lib/ethumb_private.h [new file with mode: 0644]
src/lib/md5.c [new file with mode: 0644]
src/lib/md5.h [new file with mode: 0644]
src/plugins/Makefile.am [new file with mode: 0644]
src/plugins/emotion/Makefile.am [new file with mode: 0644]
src/plugins/emotion/emotion.c [new file with mode: 0644]
src/plugins/emotion/template.edc [new file with mode: 0644]
src/plugins/epdf/Makefile.am [new file with mode: 0644]
src/plugins/epdf/epdf.c [new file with mode: 0644]
src/tests/Makefile.am [new file with mode: 0644]
src/tests/ethumb_dbus.c [new file with mode: 0644]

diff --git a/ABOUT-NLS b/ABOUT-NLS
new file mode 100644 (file)
index 0000000..83bc72e
--- /dev/null
+++ b/ABOUT-NLS
@@ -0,0 +1,1068 @@
+1 Notes on the Free Translation Project
+***************************************
+
+Free software is going international!  The Free Translation Project is
+a way to get maintainers of free software, translators, and users all
+together, so that free software will gradually become able to speak many
+languages.  A few packages already provide translations for their
+messages.
+
+   If you found this `ABOUT-NLS' file inside a distribution, you may
+assume that the distributed package does use GNU `gettext' internally,
+itself available at your nearest GNU archive site.  But you do _not_
+need to install GNU `gettext' prior to configuring, installing or using
+this package with messages translated.
+
+   Installers will find here some useful hints.  These notes also
+explain how users should proceed for getting the programs to use the
+available translations.  They tell how people wanting to contribute and
+work on translations can contact the appropriate team.
+
+   When reporting bugs in the `intl/' directory or bugs which may be
+related to internationalization, you should tell about the version of
+`gettext' which is used.  The information can be found in the
+`intl/VERSION' file, in internationalized packages.
+
+1.1 Quick configuration advice
+==============================
+
+If you want to exploit the full power of internationalization, you
+should configure it using
+
+     ./configure --with-included-gettext
+
+to force usage of internationalizing routines provided within this
+package, despite the existence of internationalizing capabilities in the
+operating system where this package is being installed.  So far, only
+the `gettext' implementation in the GNU C library version 2 provides as
+many features (such as locale alias, message inheritance, automatic
+charset conversion or plural form handling) as the implementation here.
+It is also not possible to offer this additional functionality on top
+of a `catgets' implementation.  Future versions of GNU `gettext' will
+very likely convey even more functionality.  So it might be a good idea
+to change to GNU `gettext' as soon as possible.
+
+   So you need _not_ provide this option if you are using GNU libc 2 or
+you have installed a recent copy of the GNU gettext package with the
+included `libintl'.
+
+1.2 INSTALL Matters
+===================
+
+Some packages are "localizable" when properly installed; the programs
+they contain can be made to speak your own native language.  Most such
+packages use GNU `gettext'.  Other packages have their own ways to
+internationalization, predating GNU `gettext'.
+
+   By default, this package will be installed to allow translation of
+messages.  It will automatically detect whether the system already
+provides the GNU `gettext' functions.  If not, the included GNU
+`gettext' library will be used.  This library is wholly contained
+within this package, usually in the `intl/' subdirectory, so prior
+installation of the GNU `gettext' package is _not_ required.
+Installers may use special options at configuration time for changing
+the default behaviour.  The commands:
+
+     ./configure --with-included-gettext
+     ./configure --disable-nls
+
+will, respectively, bypass any pre-existing `gettext' to use the
+internationalizing routines provided within this package, or else,
+_totally_ disable translation of messages.
+
+   When you already have GNU `gettext' installed on your system and run
+configure without an option for your new package, `configure' will
+probably detect the previously built and installed `libintl.a' file and
+will decide to use this.  This might not be desirable.  You should use
+the more recent version of the GNU `gettext' library.  I.e. if the file
+`intl/VERSION' shows that the library which comes with this package is
+more recent, you should use
+
+     ./configure --with-included-gettext
+
+to prevent auto-detection.
+
+   The configuration process will not test for the `catgets' function
+and therefore it will not be used.  The reason is that even an
+emulation of `gettext' on top of `catgets' could not provide all the
+extensions of the GNU `gettext' library.
+
+   Internationalized packages usually have many `po/LL.po' files, where
+LL gives an ISO 639 two-letter code identifying the language.  Unless
+translations have been forbidden at `configure' time by using the
+`--disable-nls' switch, all available translations are installed
+together with the package.  However, the environment variable `LINGUAS'
+may be set, prior to configuration, to limit the installed set.
+`LINGUAS' should then contain a space separated list of two-letter
+codes, stating which languages are allowed.
+
+1.3 Using This Package
+======================
+
+As a user, if your language has been installed for this package, you
+only have to set the `LANG' environment variable to the appropriate
+`LL_CC' combination.  If you happen to have the `LC_ALL' or some other
+`LC_xxx' environment variables set, you should unset them before
+setting `LANG', otherwise the setting of `LANG' will not have the
+desired effect.  Here `LL' is an ISO 639 two-letter language code, and
+`CC' is an ISO 3166 two-letter country code.  For example, let's
+suppose that you speak German and live in Germany.  At the shell
+prompt, merely execute `setenv LANG de_DE' (in `csh'),
+`export LANG; LANG=de_DE' (in `sh') or `export LANG=de_DE' (in `bash').
+This can be done from your `.login' or `.profile' file, once and for
+all.
+
+   You might think that the country code specification is redundant.
+But in fact, some languages have dialects in different countries.  For
+example, `de_AT' is used for Austria, and `pt_BR' for Brazil.  The
+country code serves to distinguish the dialects.
+
+   The locale naming convention of `LL_CC', with `LL' denoting the
+language and `CC' denoting the country, is the one use on systems based
+on GNU libc.  On other systems, some variations of this scheme are
+used, such as `LL' or `LL_CC.ENCODING'.  You can get the list of
+locales supported by your system for your language by running the
+command `locale -a | grep '^LL''.
+
+   Not all programs have translations for all languages.  By default, an
+English message is shown in place of a nonexistent translation.  If you
+understand other languages, you can set up a priority list of languages.
+This is done through a different environment variable, called
+`LANGUAGE'.  GNU `gettext' gives preference to `LANGUAGE' over `LANG'
+for the purpose of message handling, but you still need to have `LANG'
+set to the primary language; this is required by other parts of the
+system libraries.  For example, some Swedish users who would rather
+read translations in German than English for when Swedish is not
+available, set `LANGUAGE' to `sv:de' while leaving `LANG' to `sv_SE'.
+
+   Special advice for Norwegian users: The language code for Norwegian
+bokma*l changed from `no' to `nb' recently (in 2003).  During the
+transition period, while some message catalogs for this language are
+installed under `nb' and some older ones under `no', it's recommended
+for Norwegian users to set `LANGUAGE' to `nb:no' so that both newer and
+older translations are used.
+
+   In the `LANGUAGE' environment variable, but not in the `LANG'
+environment variable, `LL_CC' combinations can be abbreviated as `LL'
+to denote the language's main dialect.  For example, `de' is equivalent
+to `de_DE' (German as spoken in Germany), and `pt' to `pt_PT'
+(Portuguese as spoken in Portugal) in this context.
+
+1.4 Translating Teams
+=====================
+
+For the Free Translation Project to be a success, we need interested
+people who like their own language and write it well, and who are also
+able to synergize with other translators speaking the same language.
+Each translation team has its own mailing list.  The up-to-date list of
+teams can be found at the Free Translation Project's homepage,
+`http://translationproject.org/', in the "Teams" area.
+
+   If you'd like to volunteer to _work_ at translating messages, you
+should become a member of the translating team for your own language.
+The subscribing address is _not_ the same as the list itself, it has
+`-request' appended.  For example, speakers of Swedish can send a
+message to `sv-request@li.org', having this message body:
+
+     subscribe
+
+   Keep in mind that team members are expected to participate
+_actively_ in translations, or at solving translational difficulties,
+rather than merely lurking around.  If your team does not exist yet and
+you want to start one, or if you are unsure about what to do or how to
+get started, please write to `coordinator@translationproject.org' to
+reach the coordinator for all translator teams.
+
+   The English team is special.  It works at improving and uniformizing
+the terminology in use.  Proven linguistic skills are praised more than
+programming skills, here.
+
+1.5 Available Packages
+======================
+
+Languages are not equally supported in all packages.  The following
+matrix shows the current state of internationalization, as of November
+2007.  The matrix shows, in regard of each package, for which languages
+PO files have been submitted to translation coordination, with a
+translation percentage of at least 50%.
+
+     Ready PO files       af am ar az be bg bs ca cs cy da de el en en_GB eo
+                        +----------------------------------------------------+
+     Compendium         |                      []       [] []        []      |
+     a2ps               |             []                [] [] []     []      |
+     aegis              |                                  ()                |
+     ant-phone          |                                  ()                |
+     anubis             |                                  []                |
+     ap-utils           |                                                    |
+     aspell             |                      [] []    [] []        []      |
+     bash               |                                                 [] |
+     bfd                |                                                    |
+     bibshelf           |                                  []                |
+     binutils           |                                                    |
+     bison              |                               [] []                |
+     bison-runtime      |                                  []                |
+     bluez-pin          | []                      []       [] []          [] |
+     cflow              |                               []                   |
+     clisp              |                               [] []    []          |
+     console-tools      |                         []       []                |
+     coreutils          |                []    [] []       []                |
+     cpio               |                                                    |
+     cpplib             |                      []       [] []                |
+     cryptonit          |                                  []                |
+     dialog             |                                                    |
+     diffutils          |                      [] []    [] [] []          [] |
+     doodle             |                                  []                |
+     e2fsprogs          |                         []       []                |
+     enscript           |                      []       [] []        []      |
+     fetchmail          |                      []       [] () []     []      |
+     findutils          |                []                                  |
+     findutils_stable   |                []    []       []                   |
+     flex               |                      []       [] []                |
+     fslint             |                                                    |
+     gas                |                                                    |
+     gawk               |                      []       [] []                |
+     gcal               |                      []                            |
+     gcc                |                                  []                |
+     gettext-examples   | []                   []          [] []          [] |
+     gettext-runtime    |             []       []       [] []             [] |
+     gettext-tools      |                      []          []                |
+     gip                |                []                                  |
+     gliv               |                []                []                |
+     glunarclock        |                []                                  |
+     gmult              | []                               []                |
+     gnubiff            |                                  ()                |
+     gnucash            |                      [] []       () ()     []      |
+     gnuedu             |                                                    |
+     gnulib             |                []                                  |
+     gnunet             |                                                    |
+     gnunet-gtk         |                                                    |
+     gnutls             |                                  []                |
+     gpe-aerial         |                         []       []                |
+     gpe-beam           |                         []       []                |
+     gpe-calendar       |                                                    |
+     gpe-clock          |                         []       []                |
+     gpe-conf           |                         []       []                |
+     gpe-contacts       |                                                    |
+     gpe-edit           |                         []                         |
+     gpe-filemanager    |                                                    |
+     gpe-go             |                         []                         |
+     gpe-login          |                         []       []                |
+     gpe-ownerinfo      |                         []       []                |
+     gpe-package        |                                                    |
+     gpe-sketchbook     |                         []       []                |
+     gpe-su             |                         []       []                |
+     gpe-taskmanager    |                         []       []                |
+     gpe-timesheet      |                         []                         |
+     gpe-today          |                         []       []                |
+     gpe-todo           |                                                    |
+     gphoto2            |                         []    [] []        []      |
+     gprof              |                               [] []                |
+     gpsdrive           |                                                    |
+     gramadoir          | []                               []                |
+     grep               |                         []                      [] |
+     gretl              |                                  ()                |
+     gsasl              |                                                    |
+     gss                |                                                    |
+     gst-plugins-bad    |                []             []                   |
+     gst-plugins-base   |                []             []                   |
+     gst-plugins-good   |                []    []       []                   |
+     gst-plugins-ugly   |                []             []                   |
+     gstreamer          | []             []    [] []    [] []        []      |
+     gtick              |                                  ()                |
+     gtkam              |             []          []    [] []                |
+     gtkorphan          |                []                []                |
+     gtkspell           |             []                   [] []          [] |
+     gutenprint         |                               []                   |
+     hello              |                []    []       [] []             [] |
+     herrie             |                                  []                |
+     hylafax            |                                                    |
+     idutils            |                               [] []                |
+     indent             |                      [] []       []             [] |
+     iso_15924          |                                                    |
+     iso_3166           |       []    [] [] [] [] [] [] [] [] []          [] |
+     iso_3166_2         |                                                    |
+     iso_4217           |                         []    [] []                |
+     iso_639            |                         []    [] []             [] |
+     jpilot             |                         []                         |
+     jtag               |                                                    |
+     jwhois             |                                                    |
+     kbd                |                         []    [] [] []             |
+     keytouch           |                      []          []                |
+     keytouch-editor    |                                  []                |
+     keytouch-keyboa... |                      []                            |
+     latrine            |                                  ()                |
+     ld                 |                               []                   |
+     leafpad            |                []    [] []       [] []             |
+     libc               |                      [] []    [] []                |
+     libexif            |                                  []                |
+     libextractor       |                                  []                |
+     libgpewidget       |                         []    [] []                |
+     libgpg-error       |                                  []                |
+     libgphoto2         |                               [] []                |
+     libgphoto2_port    |                               [] []                |
+     libgsasl           |                                                    |
+     libiconv           |                                  []             [] |
+     libidn             |                         []    []                [] |
+     lifelines          |                               [] ()                |
+     lilypond           |                                  []                |
+     lingoteach         |                                                    |
+     lprng              |                                                    |
+     lynx               |                      [] []    [] []                |
+     m4                 |                         []    [] [] []             |
+     mailfromd          |                                                    |
+     mailutils          |                      []                            |
+     make               |                               [] []                |
+     man-db             |                      []       [] []                |
+     minicom            |                         []    [] []                |
+     nano               |                []    []          []                |
+     opcodes            |                                  []                |
+     parted             |                         []       []                |
+     pilot-qof          |                                                    |
+     popt               |                         []    [] []                |
+     psmisc             |                []                                  |
+     pwdutils           |                                                    |
+     qof                |                                                    |
+     radius             |                      []                            |
+     recode             |             []       []       [] [] []          [] |
+     rpm                |                               []                   |
+     screem             |                                                    |
+     scrollkeeper       |          [] []       [] [] [] [] []        []      |
+     sed                |                      []          []             [] |
+     shared-mime-info   |                []    [] []    [] () []     []   [] |
+     sharutils          |                []    [] []    [] [] []             |
+     shishi             |                                                    |
+     skencil            |                               [] ()                |
+     solfege            |                                                    |
+     soundtracker       |                               [] []                |
+     sp                 |                                  []                |
+     system-tools-ba... |       []       [] [] [] []    [] [] []     []      |
+     tar                |                []                []                |
+     texinfo            |                               [] []             [] |
+     tin                |                                  ()        ()      |
+     tuxpaint           | []             []             [] []        []   [] |
+     unicode-han-tra... |                                                    |
+     unicode-transla... |                                                    |
+     util-linux         |                      [] []    [] []                |
+     util-linux-ng      |                      [] []    [] []                |
+     vorbis-tools       |                         []                         |
+     wastesedge         |                                  ()                |
+     wdiff              |                      []       [] []        []      |
+     wget               |                      [] []       []                |
+     xchat              |             [] []    [] []       [] []     []      |
+     xkeyboard-config   |                []                                  |
+     xpad               |                []             []           []      |
+                        +----------------------------------------------------+
+                          af am ar az be bg bs ca cs cy da de el en en_GB eo
+                           6  0  2  1  8 26  2 40 48  2 56 88 15  1  15   18
+
+                          es et eu fa fi fr  ga gl gu he hi hr hu id is it
+                        +--------------------------------------------------+
+     Compendium         | []          [] []  []                []          |
+     a2ps               |    []       [] []                             () |
+     aegis              |                                                  |
+     ant-phone          |                []                                |
+     anubis             |                []                                |
+     ap-utils           |             [] []                                |
+     aspell             |                []  []                         [] |
+     bash               | []                                               |
+     bfd                | []          []                                   |
+     bibshelf           | []                 []                         [] |
+     binutils           | []          [] []                                |
+     bison              | [] []          []  []                   []    [] |
+     bison-runtime      |    []          []  []                   []    [] |
+     bluez-pin          |             [] []  []                [] []       |
+     cflow              |                    []                            |
+     clisp              | []             []                                |
+     console-tools      |                                                  |
+     coreutils          | [] []       [] []  []                []          |
+     cpio               | []             []  []                            |
+     cpplib             | []             []                                |
+     cryptonit          |                []                                |
+     dialog             |       []           []                         [] |
+     diffutils          | []          [] []  [] []    []       [] []    [] |
+     doodle             |                    []                         [] |
+     e2fsprogs          | []             []                             [] |
+     enscript           |                []  []             []             |
+     fetchmail          | []                                               |
+     findutils          |    []              []                []          |
+     findutils_stable   |    []          []  []                []          |
+     flex               | []             []  []                            |
+     fslint             |                                                  |
+     gas                | []             []                                |
+     gawk               | []             []  []       []                () |
+     gcal               | []             []                                |
+     gcc                | []                                               |
+     gettext-examples   | []          [] []  []                [] []    [] |
+     gettext-runtime    | []          [] []  []                   []    [] |
+     gettext-tools      | []    []       []                             [] |
+     gip                | []    []       []  []                            |
+     gliv               |                ()                                |
+     glunarclock        |             []     []                []          |
+     gmult              |       []       []                             [] |
+     gnubiff            |                ()                             () |
+     gnucash            | ()             ()                    ()          |
+     gnuedu             | []                                               |
+     gnulib             | [] []              []                            |
+     gnunet             |                                                  |
+     gnunet-gtk         |                                                  |
+     gnutls             |                                                  |
+     gpe-aerial         | []             []                                |
+     gpe-beam           | []             []                                |
+     gpe-calendar       |                                                  |
+     gpe-clock          | []          [] []                    []          |
+     gpe-conf           |                []                                |
+     gpe-contacts       | []             []                                |
+     gpe-edit           | []             []                    [] []       |
+     gpe-filemanager    | []                                               |
+     gpe-go             | []             []                    []          |
+     gpe-login          | []             []                    []          |
+     gpe-ownerinfo      | []          [] []                    [] []       |
+     gpe-package        | []                                               |
+     gpe-sketchbook     | []             []                                |
+     gpe-su             | []          [] []                    []          |
+     gpe-taskmanager    | []          [] []                                |
+     gpe-timesheet      | []             []  []                   []       |
+     gpe-today          | []          [] []  []                            |
+     gpe-todo           | []                                               |
+     gphoto2            | []          [] []                    []       [] |
+     gprof              | []          [] []  []                   []       |
+     gpsdrive           |    []                                            |
+     gramadoir          |                []  []                            |
+     grep               | []          []     []                            |
+     gretl              | []    []       []                             () |
+     gsasl              |                    []                   []       |
+     gss                |                []  []                            |
+     gst-plugins-bad    | []          []                       []       [] |
+     gst-plugins-base   | []          []                       []       [] |
+     gst-plugins-good   | []    []    []                       []       [] |
+     gst-plugins-ugly   | []          []                       []       [] |
+     gstreamer          |             []                       []       [] |
+     gtick              |             []     []                         [] |
+     gtkam              | []             []                    []       [] |
+     gtkorphan          |                []                             [] |
+     gtkspell           | []    []    [] []  []                []       [] |
+     gutenprint         |                                      []          |
+     hello              | [] [] [] [] [] []  [] []    []    [] [] []    [] |
+     herrie             |                    []                            |
+     hylafax            |                                                  |
+     idutils            |                []  []                [] []    [] |
+     indent             | [] [] []    [] []  [] []             [] []    [] |
+     iso_15924          |                []                                |
+     iso_3166           | [] [] []    [] []     [] [] [] [] [] [] []    [] |
+     iso_3166_2         |                []                                |
+     iso_4217           | [] []       [] []                    []       [] |
+     iso_639            | []       [] [] []  []                []          |
+     jpilot             | []             []                                |
+     jtag               |                []                                |
+     jwhois             | []             []                    [] []    [] |
+     kbd                | []             []                                |
+     keytouch           |                []  []                         [] |
+     keytouch-editor    |                    []                            |
+     keytouch-keyboa... |                    []                         [] |
+     latrine            |                    []                         [] |
+     ld                 | []          [] []  []                            |
+     leafpad            | []             []  []       []       []       [] |
+     libc               | []          [] []     []             []          |
+     libexif            | []                                               |
+     libextractor       |                    []                            |
+     libgpewidget       | []             []  []                [] []       |
+     libgpg-error       |                []                                |
+     libgphoto2         | []             []                             [] |
+     libgphoto2_port    |                []                             [] |
+     libgsasl           |                []  []                            |
+     libiconv           |    []       []     []                            |
+     libidn             |                []                             [] |
+     lifelines          |                ()                                |
+     lilypond           | []          [] []                                |
+     lingoteach         |                []                       []    [] |
+     lprng              |                                                  |
+     lynx               |    []                                []       [] |
+     m4                 |                []  [] []                []       |
+     mailfromd          |                                                  |
+     mailutils          | []             []                                |
+     make               | []          [] []  [] []    []    []    []       |
+     man-db             |                                               [] |
+     minicom            | []          [] []                    []          |
+     nano               | []    []       []  [] []             []       [] |
+     opcodes            | []          [] []  []                            |
+     parted             |                []                       []    [] |
+     pilot-qof          |                                                  |
+     popt               |                []  [] []                   []    |
+     psmisc             |                                      []       [] |
+     pwdutils           |                                                  |
+     qof                |                                         []       |
+     radius             | []             []                                |
+     recode             | []             []  [] []    []       [] []    [] |
+     rpm                |                []                       []       |
+     screem             |                                                  |
+     scrollkeeper       | []          []                       []          |
+     sed                | [] []          []  []                []          |
+     shared-mime-info   | []    []    [] []                    []       [] |
+     sharutils          | [] []       [] []  [] []             []       [] |
+     shishi             |                []                                |
+     skencil            | []             []                                |
+     solfege            |                                               [] |
+     soundtracker       | []             []                             [] |
+     sp                 |                []                                |
+     system-tools-ba... | []    []    [] []  []             [] [] []    [] |
+     tar                |    [] []    []     []                []          |
+     texinfo            |                []           []       []          |
+     tin                |    []          ()                                |
+     tuxpaint           |                    []                []          |
+     unicode-han-tra... |                                                  |
+     unicode-transla... |                []  []                            |
+     util-linux         | [] []       [] []                    [] []    [] |
+     util-linux-ng      | [] []       [] []                    [] []    [] |
+     vorbis-tools       |                                                  |
+     wastesedge         |                ()                                |
+     wdiff              | [] []          []  [] []             [] []    [] |
+     wget               |    []       [] []  []             [] [] []    [] |
+     xchat              | []          [] []        []    []    []       [] |
+     xkeyboard-config   | []          [] []                    []          |
+     xpad               | []                 []                []          |
+                        +--------------------------------------------------+
+                          es et eu fa fi fr  ga gl gu he hi hr hu id is it
+                          85 22 14  2 48 101 61 12  2  8  2  6 53 29  1 52
+
+                          ja ka ko ku ky lg lt lv mk mn ms mt nb ne nl  nn
+                        +--------------------------------------------------+
+     Compendium         |                                           []     |
+     a2ps               |       ()                      []          []     |
+     aegis              |                                           ()     |
+     ant-phone          |                                           []     |
+     anubis             |                               []    []    []     |
+     ap-utils           |                               []                 |
+     aspell             |                            []             []     |
+     bash               |                                           []     |
+     bfd                |                                                  |
+     bibshelf           |                               []                 |
+     binutils           |                                                  |
+     bison              |                               []    []    []     |
+     bison-runtime      |                               []    []    []     |
+     bluez-pin          |          []                   []          []     |
+     cflow              |                                                  |
+     clisp              |                                           []     |
+     console-tools      |                                                  |
+     coreutils          |                                           []     |
+     cpio               |                                           []     |
+     cpplib             |                                           []     |
+     cryptonit          |                                           []     |
+     dialog             |                               []          []     |
+     diffutils          | []                            []          []     |
+     doodle             |                                                  |
+     e2fsprogs          |                                           []     |
+     enscript           |                                           []     |
+     fetchmail          | []                                        []     |
+     findutils          |                                           []     |
+     findutils_stable   |                                           []     |
+     flex               |       []                                  []     |
+     fslint             |                                                  |
+     gas                |                                                  |
+     gawk               | []                                        []     |
+     gcal               |                                                  |
+     gcc                |                                                  |
+     gettext-examples   | []                            []          []     |
+     gettext-runtime    | []    []                                  []     |
+     gettext-tools      | []    []                                         |
+     gip                |                               []          []     |
+     gliv               |                                           []     |
+     glunarclock        |                               []          []     |
+     gmult              | []                            []          []     |
+     gnubiff            |                                                  |
+     gnucash            | ()                                  () ()        |
+     gnuedu             |                                                  |
+     gnulib             | []                                        []     |
+     gnunet             |                                                  |
+     gnunet-gtk         |                                                  |
+     gnutls             |                               []                 |
+     gpe-aerial         |                                           []     |
+     gpe-beam           |                                           []     |
+     gpe-calendar       | []                                               |
+     gpe-clock          | []    []                                  []     |
+     gpe-conf           | []    []                                  []     |
+     gpe-contacts       |       []                                         |
+     gpe-edit           | []    []                                  []     |
+     gpe-filemanager    | []    []                                         |
+     gpe-go             | []    []                                  []     |
+     gpe-login          | []    []                                  []     |
+     gpe-ownerinfo      | []                                        []     |
+     gpe-package        | []    []                                         |
+     gpe-sketchbook     |       []                                  []     |
+     gpe-su             | []    []                                  []     |
+     gpe-taskmanager    | []    [] []                               []     |
+     gpe-timesheet      |                                           []     |
+     gpe-today          | []                                        []     |
+     gpe-todo           | []                                               |
+     gphoto2            | []                                        []     |
+     gprof              |                               []                 |
+     gpsdrive           |                                           []     |
+     gramadoir          |                                           ()     |
+     grep               |             []                            []     |
+     gretl              |                                                  |
+     gsasl              |                                           []     |
+     gss                |                                                  |
+     gst-plugins-bad    |                                           []     |
+     gst-plugins-base   |                                           []     |
+     gst-plugins-good   |                                           []     |
+     gst-plugins-ugly   |                                           []     |
+     gstreamer          |                                           []     |
+     gtick              |                                           []     |
+     gtkam              | []                                        []     |
+     gtkorphan          |                                           []     |
+     gtkspell           |                            []             []     |
+     gutenprint         |                                           []     |
+     hello              | [] [] []                      []    []    []  [] |
+     herrie             |                                           []     |
+     hylafax            |                                                  |
+     idutils            |                                           []     |
+     indent             | []                                        []     |
+     iso_15924          |                                           []     |
+     iso_3166           | []    [] []       []    []          []    []  [] |
+     iso_3166_2         |                                           []     |
+     iso_4217           | []                []                      []     |
+     iso_639            | []                []                      []  [] |
+     jpilot             | ()                                        ()     |
+     jtag               |                                                  |
+     jwhois             |                                           []     |
+     kbd                |                                           []     |
+     keytouch           |                                           []     |
+     keytouch-editor    |                                           []     |
+     keytouch-keyboa... |                                                  |
+     latrine            |                                           []     |
+     ld                 |                                                  |
+     leafpad            | []                []                             |
+     libc               | []    []                                  []     |
+     libexif            |                                                  |
+     libextractor       |                                                  |
+     libgpewidget       |                                           []     |
+     libgpg-error       |                                                  |
+     libgphoto2         | []                                               |
+     libgphoto2_port    | []                                               |
+     libgsasl           |                                           []     |
+     libiconv           |                                           []     |
+     libidn             | []                                        []     |
+     lifelines          |                                           []     |
+     lilypond           |                                           []     |
+     lingoteach         |                                           []     |
+     lprng              |                                                  |
+     lynx               | []                                        []     |
+     m4                 | []                                        []     |
+     mailfromd          |                                                  |
+     mailutils          |                                                  |
+     make               | []    []                                  []     |
+     man-db             |                                                  |
+     minicom            | []                                               |
+     nano               |                               []    []    []     |
+     opcodes            |                                           []     |
+     parted             | []                                        []     |
+     pilot-qof          |                                                  |
+     popt               | []    []                                  []     |
+     psmisc             | []                                  []    []     |
+     pwdutils           |                                                  |
+     qof                |                                                  |
+     radius             |                                                  |
+     recode             |                                           []     |
+     rpm                | []    []                                         |
+     screem             | []                                               |
+     scrollkeeper       |                                     [] [] []  [] |
+     sed                | []                                        []     |
+     shared-mime-info   | []    []          []          []    []    []  [] |
+     sharutils          | []                                        []     |
+     shishi             |                                                  |
+     skencil            |                                                  |
+     solfege            |                                     ()        () |
+     soundtracker       |                                                  |
+     sp                 | ()                                               |
+     system-tools-ba... | []    []          []                      []     |
+     tar                | []          []                            []     |
+     texinfo            |                                     []    []     |
+     tin                |                                                  |
+     tuxpaint           |                                     ()    []  [] |
+     unicode-han-tra... |                                                  |
+     unicode-transla... |                                                  |
+     util-linux         | []                                        []     |
+     util-linux-ng      | []                                        []     |
+     vorbis-tools       |                                                  |
+     wastesedge         |                                           []     |
+     wdiff              |                               []    []           |
+     wget               | []                                        []     |
+     xchat              | []    []                []                []     |
+     xkeyboard-config   |    [] []                                  []     |
+     xpad               |       []                      []          []     |
+                        +--------------------------------------------------+
+                          ja ka ko ku ky lg lt lv mk mn ms mt nb ne nl  nn
+                          51  2 25  3  2  0  6  0  2  2 20  0 11  1 103  6
+
+                          or pa pl pt pt_BR rm ro ru rw sk sl sq sr sv  ta
+                        +--------------------------------------------------+
+     Compendium         |          []  []      []       []          []     |
+     a2ps               |       ()     []      [] []       []    [] []     |
+     aegis              |                      () ()                       |
+     ant-phone          |                      []                   []     |
+     anubis             |       []             [] []                       |
+     ap-utils           |       ()                                         |
+     aspell             |                      [] []    []                 |
+     bash               |       []                      []                 |
+     bfd                |                                                  |
+     bibshelf           |                                           []     |
+     binutils           |                         []    []                 |
+     bison              |       []     []      [] []                []     |
+     bison-runtime      |       []     []      []          []       []     |
+     bluez-pin          |       []     []   [] [] []    [] []    [] []     |
+     cflow              |       []                                         |
+     clisp              |                         []                       |
+     console-tools      |                         []                       |
+     coreutils          |       []                []       []       []     |
+     cpio               |       []                []                []     |
+     cpplib             |                                           []     |
+     cryptonit          |              []                           []     |
+     dialog             |                                           []     |
+     diffutils          |       []     []      [] []             [] []     |
+     doodle             |                                     []    []     |
+     e2fsprogs          |       []                                  []     |
+     enscript           |              []      [] []       []       []     |
+     fetchmail          |       []                []          []           |
+     findutils          |       [] []                               []     |
+     findutils_stable   |       [] []          []       [] []       []     |
+     flex               |       []     []      [] []                []     |
+     fslint             |                                           []     |
+     gas                |                                                  |
+     gawk               |       []     []      []                   []     |
+     gcal               |                                           []     |
+     gcc                |                                        [] []     |
+     gettext-examples   |       [] []          [] []    [] []    [] []     |
+     gettext-runtime    |       [] []          [] []    [] []    [] []     |
+     gettext-tools      |       []             [] []    [] []    [] []     |
+     gip                |                   []          []       [] []     |
+     gliv               |       []     []      [] []    []          []     |
+     glunarclock        |              []      [] []    []       [] []     |
+     gmult              |                   [] []                [] []     |
+     gnubiff            |                      ()                   []     |
+     gnucash            |       ()                                  []     |
+     gnuedu             |                                                  |
+     gnulib             |       []                         []       []     |
+     gnunet             |                                                  |
+     gnunet-gtk         |                                           []     |
+     gnutls             |       []                                  []     |
+     gpe-aerial         |          []  []      [] []       []    [] []     |
+     gpe-beam           |          []  []      [] []       []    [] []     |
+     gpe-calendar       |                         []       []    [] []     |
+     gpe-clock          |          []  []      [] []    [] []    [] []     |
+     gpe-conf           |          []  []      [] []    [] []       []     |
+     gpe-contacts       |                      [] []       []    [] []     |
+     gpe-edit           |       [] []  []      [] []    [] []    [] []     |
+     gpe-filemanager    |                                  []       []     |
+     gpe-go             |       []     []      [] []    [] []    [] []     |
+     gpe-login          |          []  []      [] []    [] []    [] []     |
+     gpe-ownerinfo      |          []  []      [] []    [] []    [] []     |
+     gpe-package        |                                  []       []     |
+     gpe-sketchbook     |          []  []      [] []    [] []    [] []     |
+     gpe-su             |          []  []      [] []    [] []    [] []     |
+     gpe-taskmanager    |          []  []      [] []    [] []    [] []     |
+     gpe-timesheet      |          []  []      [] []    [] []    [] []     |
+     gpe-today          |          []  []      [] []    [] []    [] []     |
+     gpe-todo           |                         []       []    [] []     |
+     gphoto2            |    [] []             []       []       [] []     |
+     gprof              |              []      []                   []     |
+     gpsdrive           |                         []                []     |
+     gramadoir          |                               []          []     |
+     grep               |       []                      [] []       []     |
+     gretl              |       [] []  []                                  |
+     gsasl              |       []                               [] []     |
+     gss                |       []             []       []          []     |
+     gst-plugins-bad    |       []     []                           []     |
+     gst-plugins-base   |       []                                  []     |
+     gst-plugins-good   |       []                                  []     |
+     gst-plugins-ugly   |       []     []                           []     |
+     gstreamer          |       []                            [] [] []     |
+     gtick              |                         []                       |
+     gtkam              |    [] []     []         []                []     |
+     gtkorphan          |                                           []     |
+     gtkspell           |              []   [] [] []    [] []    [] []     |
+     gutenprint         |                                           []     |
+     hello              |       []     []      [] []    [] []    [] []     |
+     herrie             |       []                []                []     |
+     hylafax            |                                                  |
+     idutils            |       []     []      [] []                []     |
+     indent             |       []     []      [] []    []       [] []     |
+     iso_15924          |                                                  |
+     iso_3166           |    [] [] []  []      [] [] [] [] [] [] [] []  [] |
+     iso_3166_2         |                                                  |
+     iso_4217           |       [] []             [] []    []    [] []     |
+     iso_639            |       []                [] [] [] []    [] []     |
+     jpilot             |                                                  |
+     jtag               |                               []                 |
+     jwhois             |       []     []      []                   []     |
+     kbd                |       []             []                   []     |
+     keytouch           |                                           []     |
+     keytouch-editor    |                                           []     |
+     keytouch-keyboa... |                                           []     |
+     latrine            |                                                  |
+     ld                 |                                           []     |
+     leafpad            |       [] []             []    []          []  [] |
+     libc               |       []                []    []          []     |
+     libexif            |       []                      []                 |
+     libextractor       |                      []                   []     |
+     libgpewidget       |       [] []  []      []       [] []    [] []     |
+     libgpg-error       |       []             []                   []     |
+     libgphoto2         |       []                                         |
+     libgphoto2_port    |       []                []                []     |
+     libgsasl           |       []             []                [] []     |
+     libiconv           |                                  []    [] []     |
+     libidn             |       []                               [] ()     |
+     lifelines          |       []                                  []     |
+     lilypond           |                                                  |
+     lingoteach         |              []                                  |
+     lprng              |       []                                         |
+     lynx               |              []         []                []     |
+     m4                 |       []     []      [] []                []     |
+     mailfromd          |       []                                         |
+     mailutils          |       []                []                []     |
+     make               |       []     []         []                []     |
+     man-db             |       []             [] []                []     |
+     minicom            |       []     []      [] []                []     |
+     nano               |              []      [] []                []     |
+     opcodes            |                      []                   []     |
+     parted             |       []                                         |
+     pilot-qof          |                                                  |
+     popt               |       [] []             []                []     |
+     psmisc             |       []                                  []     |
+     pwdutils           |       []                                  []     |
+     qof                |              []                           []     |
+     radius             |       []                []                       |
+     recode             |       [] []  []      [] []       []       []     |
+     rpm                |       [] []             []                []     |
+     screem             |                                                  |
+     scrollkeeper       |       []             [] []    []    [] [] []     |
+     sed                |       [] []  []      [] []    [] []    [] []     |
+     shared-mime-info   |       [] []  []                     [] [] []     |
+     sharutils          |       []                []             [] []     |
+     shishi             |       []                                         |
+     skencil            |          []  []                           []     |
+     solfege            |              []                                  |
+     soundtracker       |                               []          []     |
+     sp                 |                                                  |
+     system-tools-ba... |    [] [] []  []      []             [] [] []  [] |
+     tar                |       []                []       []       []     |
+     texinfo            |       []             [] []                []     |
+     tin                |                         ()                       |
+     tuxpaint           |       [] []                      [] [] [] []     |
+     unicode-han-tra... |                                                  |
+     unicode-transla... |                                                  |
+     util-linux         |              []         []       []       []     |
+     util-linux-ng      |              []         []       []       []     |
+     vorbis-tools       |                         []                       |
+     wastesedge         |                                                  |
+     wdiff              |       []     []      [] []    [] []       []     |
+     wget               |          []             []    []          []     |
+     xchat              |    []                   []    [] [] [] [] []     |
+     xkeyboard-config   |                               [] []       []     |
+     xpad               |                               [] []       []     |
+                        +--------------------------------------------------+
+                          or pa pl pt pt_BR rm ro ru rw sk sl sq sr sv  ta
+                           0  5 77 31  53    4 58 72  3 45 46  9 45 122  3
+
+                          tg th tk tr uk ven vi  wa xh zh_CN zh_HK zh_TW zu
+                        +---------------------------------------------------+
+     Compendium         |          []        []         []          []      | 19
+     a2ps               |          [] []     []                             | 19
+     aegis              |                    []                             |  1
+     ant-phone          |          []        []                             |  6
+     anubis             |          [] []     []                             | 11
+     ap-utils           |             ()     []                             |  4
+     aspell             |             []     []  []                         | 16
+     bash               |          []                                       |  6
+     bfd                |                                                   |  2
+     bibshelf           |                    []                             |  7
+     binutils           |          [] []     []                     []      |  9
+     bison              |          [] []     []                     []      | 20
+     bison-runtime      |             []     []         []          []      | 18
+     bluez-pin          |          [] []     []  []     []          []      | 28
+     cflow              |             []     []                             |  5
+     clisp              |                                                   |  9
+     console-tools      |          []        []                             |  5
+     coreutils          |          [] []     []                             | 18
+     cpio               |          [] []     []         []                  | 11
+     cpplib             |          [] []     []         []          []      | 12
+     cryptonit          |                    []                             |  6
+     dialog             |                    []  []     []                  |  9
+     diffutils          |          [] []     []         []          []      | 29
+     doodle             |                    []                             |  6
+     e2fsprogs          |          []        []                             | 10
+     enscript           |          [] []     []                             | 16
+     fetchmail          |          []        []                             | 12
+     findutils          |          [] []     []                             | 11
+     findutils_stable   |          [] []     []                     []      | 18
+     flex               |          []        []                             | 15
+     fslint             |                    []                             |  2
+     gas                |          []                                       |  3
+     gawk               |          []        []         []                  | 16
+     gcal               |          []                                       |  5
+     gcc                |          []                   []          []      |  7
+     gettext-examples   |          [] []     []         []    []    []      | 29
+     gettext-runtime    |          [] []     []         []    []    []      | 28
+     gettext-tools      |          [] []     []         []          []      | 20
+     gip                |                    []                     []      | 13
+     gliv               |          []        []                             | 11
+     glunarclock        |                    []  []                 []      | 15
+     gmult              |          []        []         []          []      | 16
+     gnubiff            |                    []                             |  2
+     gnucash            |          () []                                    |  5
+     gnuedu             |                    []                             |  2
+     gnulib             |                    []                             | 10
+     gnunet             |                                                   |  0
+     gnunet-gtk         |          []        []                             |  3
+     gnutls             |                                                   |  4
+     gpe-aerial         |                    []         []                  | 14
+     gpe-beam           |                    []         []                  | 14
+     gpe-calendar       |                    []  []                         |  7
+     gpe-clock          |          []        []  []     []                  | 21
+     gpe-conf           |                    []  []     []                  | 16
+     gpe-contacts       |                    []         []                  | 10
+     gpe-edit           |          []        []  []     []          []      | 22
+     gpe-filemanager    |                    []  []                         |  7
+     gpe-go             |          []        []  []     []                  | 19
+     gpe-login          |          []        []  []     []          []      | 21
+     gpe-ownerinfo      |          []        []         []          []      | 21
+     gpe-package        |                    []                             |  6
+     gpe-sketchbook     |          []        []                             | 16
+     gpe-su             |          []        []  []     []                  | 21
+     gpe-taskmanager    |          []        []  []     []                  | 21
+     gpe-timesheet      |          []        []         []          []      | 18
+     gpe-today          |          []        []  []     []          []      | 21
+     gpe-todo           |                    []  []                         |  8
+     gphoto2            |             []     []         []          []      | 21
+     gprof              |          []        []                             | 13
+     gpsdrive           |                    []                             |  5
+     gramadoir          |                    []                             |  7
+     grep               |                    []                             | 12
+     gretl              |                                                   |  6
+     gsasl              |                    []         []          []      |  9
+     gss                |                    []                             |  7
+     gst-plugins-bad    |             []     []         []                  | 13
+     gst-plugins-base   |             []     []                             | 11
+     gst-plugins-good   |             []     []         []    []    []      | 16
+     gst-plugins-ugly   |             []     []         []                  | 13
+     gstreamer          |          [] []     []                             | 18
+     gtick              |             []     []                             |  7
+     gtkam              |                    []                             | 16
+     gtkorphan          |                    []                             |  7
+     gtkspell           |             []     []  []     []    []    []      | 27
+     gutenprint         |                                                   |  4
+     hello              |          [] []     []         []          []      | 38
+     herrie             |          []        []                             |  8
+     hylafax            |                                                   |  0
+     idutils            |          []        []                             | 15
+     indent             |          [] []     []         []          []      | 28
+     iso_15924          |                    []         []                  |  4
+     iso_3166           |    [] [] [] []     []  []     []    []    []      | 54
+     iso_3166_2         |                    []         []                  |  4
+     iso_4217           |    []    []        []         []    []            | 24
+     iso_639            |             []     []  []     []    []            | 26
+     jpilot             |          [] []     []         []                  |  7
+     jtag               |                    []                             |  3
+     jwhois             |          []        []                     []      | 13
+     kbd                |          [] []     []                             | 13
+     keytouch           |                    []                             |  8
+     keytouch-editor    |                    []                             |  5
+     keytouch-keyboa... |                    []                             |  5
+     latrine            |          []        []                             |  5
+     ld                 |          []        []         []          []      | 10
+     leafpad            |          [] []     []         []          []      | 24
+     libc               |          []                   []          []      | 19
+     libexif            |                    []                             |  5
+     libextractor       |                    []                             |  5
+     libgpewidget       |                    []  []     []                  | 20
+     libgpg-error       |                    []                             |  6
+     libgphoto2         |             []     []                             |  9
+     libgphoto2_port    |             []     []                     []      | 11
+     libgsasl           |                    []                             |  8
+     libiconv           |                    []  []                         | 11
+     libidn             |                    []         []                  | 11
+     lifelines          |                                                   |  4
+     lilypond           |                    []                             |  6
+     lingoteach         |                    []                             |  6
+     lprng              |                    []                             |  2
+     lynx               |          [] []     []                             | 15
+     m4                 |                    []         []          []      | 18
+     mailfromd          |             []     []                             |  3
+     mailutils          |             []     []                             |  8
+     make               |          []        []         []                  | 20
+     man-db             |                    []                             |  9
+     minicom            |                    []                             | 14
+     nano               |                    []         []          []      | 20
+     opcodes            |          []        []                             | 10
+     parted             |          [] []                            []      | 11
+     pilot-qof          |                    []                             |  1
+     popt               |          []        []         []          []      | 18
+     psmisc             |                    []         []                  | 10
+     pwdutils           |                    []                             |  3
+     qof                |                    []                             |  4
+     radius             |             []     []                             |  7
+     recode             |          []        []         []                  | 25
+     rpm                |          [] []     []                     []      | 13
+     screem             |                    []                             |  2
+     scrollkeeper       |          [] []     []                     []      | 26
+     sed                |          []        []         []          []      | 23
+     shared-mime-info   |             []     []         []                  | 29
+     sharutils          |          []        []                     []      | 23
+     shishi             |                    []                             |  3
+     skencil            |                    []                             |  7
+     solfege            |                    []                             |  3
+     soundtracker       |          []        []                             |  9
+     sp                 |          []                                       |  3
+     system-tools-ba... |    []    [] []     []     []  []          []      | 38
+     tar                |          [] []     []                             | 17
+     texinfo            |          []        []         []                  | 15
+     tin                |                                                   |  1
+     tuxpaint           |                    []  []                 []      | 19
+     unicode-han-tra... |                                                   |  0
+     unicode-transla... |                                                   |  2
+     util-linux         |          [] []     []                             | 20
+     util-linux-ng      |          [] []     []                             | 20
+     vorbis-tools       |             []     []                             |  4
+     wastesedge         |                                                   |  1
+     wdiff              |          []        []                             | 23
+     wget               |          []        []                     []      | 20
+     xchat              |             []     []         []          []      | 29
+     xkeyboard-config   |          [] []     []                             | 14
+     xpad               |                    []         []          []      | 15
+                        +---------------------------------------------------+
+       76 teams           tg th tk tr uk ven vi  wa xh zh_CN zh_HK zh_TW zu
+      163 domains          0  3  1 74 51  0  143 21  1  57     7    45    0  2036
+
+   Some counters in the preceding matrix are higher than the number of
+visible blocks let us expect.  This is because a few extra PO files are
+used for implementing regional variants of languages, or language
+dialects.
+
+   For a PO file in the matrix above to be effective, the package to
+which it applies should also have been internationalized and
+distributed as such by its maintainer.  There might be an observable
+lag between the mere existence a PO file and its wide availability in a
+distribution.
+
+   If November 2007 seems to be old, you may fetch a more recent copy
+of this `ABOUT-NLS' file on most GNU archive sites.  The most
+up-to-date matrix with full percentage details can be found at
+`http://translationproject.org/extra/matrix.html'.
+
+1.6 Using `gettext' in new packages
+===================================
+
+If you are writing a freely available program and want to
+internationalize it you are welcome to use GNU `gettext' in your
+package.  Of course you have to respect the GNU Library General Public
+License which covers the use of the GNU `gettext' library.  This means
+in particular that even non-free programs can use `libintl' as a shared
+library, whereas only free software can use `libintl' as a static
+library or use modified versions of `libintl'.
+
+   Once the sources are changed appropriately and the setup can handle
+the use of `gettext' the only thing missing are the translations.  The
+Free Translation Project is also available for packages which are not
+developed inside the GNU project.  Therefore the information given above
+applies also for every other Free Software Project.  Contact
+`coordinator@translationproject.org' to make the `.pot' files available
+to the translation teams.
+
diff --git a/AUTHORS b/AUTHORS
new file mode 100644 (file)
index 0000000..cfc62b6
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1 @@
+Rafael Antognolli <antognolli@profusion.mobi>
diff --git a/BUGS b/BUGS
new file mode 100644 (file)
index 0000000..a48563d
--- /dev/null
+++ b/BUGS
@@ -0,0 +1,7 @@
+Possible error when calculating edje frame size for thumbnails.
+
+Since edje_object_size_min_calc() still doesn't retuns the actual edje object
+size, it's possible that a part from the edje frame stay outside the picture.
+This should be fixed soon, with a new call to get the current edje object size
+or changing something on the API to tell ethumb that the frame has some border.
+                        - antognolli, 30-03-2009
diff --git a/COPYING b/COPYING
new file mode 100644 (file)
index 0000000..cca7fc2
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,165 @@
+                  GNU LESSER GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+
+  This version of the GNU Lesser General Public License incorporates
+the terms and conditions of version 3 of the GNU General Public
+License, supplemented by the additional permissions listed below.
+
+  0. Additional Definitions.
+
+  As used herein, "this License" refers to version 3 of the GNU Lesser
+General Public License, and the "GNU GPL" refers to version 3 of the GNU
+General Public License.
+
+  "The Library" refers to a covered work governed by this License,
+other than an Application or a Combined Work as defined below.
+
+  An "Application" is any work that makes use of an interface provided
+by the Library, but which is not otherwise based on the Library.
+Defining a subclass of a class defined by the Library is deemed a mode
+of using an interface provided by the Library.
+
+  A "Combined Work" is a work produced by combining or linking an
+Application with the Library.  The particular version of the Library
+with which the Combined Work was made is also called the "Linked
+Version".
+
+  The "Minimal Corresponding Source" for a Combined Work means the
+Corresponding Source for the Combined Work, excluding any source code
+for portions of the Combined Work that, considered in isolation, are
+based on the Application, and not on the Linked Version.
+
+  The "Corresponding Application Code" for a Combined Work means the
+object code and/or source code for the Application, including any data
+and utility programs needed for reproducing the Combined Work from the
+Application, but excluding the System Libraries of the Combined Work.
+
+  1. Exception to Section 3 of the GNU GPL.
+
+  You may convey a covered work under sections 3 and 4 of this License
+without being bound by section 3 of the GNU GPL.
+
+  2. Conveying Modified Versions.
+
+  If you modify a copy of the Library, and, in your modifications, a
+facility refers to a function or data to be supplied by an Application
+that uses the facility (other than as an argument passed when the
+facility is invoked), then you may convey a copy of the modified
+version:
+
+   a) under this License, provided that you make a good faith effort to
+   ensure that, in the event an Application does not supply the
+   function or data, the facility still operates, and performs
+   whatever part of its purpose remains meaningful, or
+
+   b) under the GNU GPL, with none of the additional permissions of
+   this License applicable to that copy.
+
+  3. Object Code Incorporating Material from Library Header Files.
+
+  The object code form of an Application may incorporate material from
+a header file that is part of the Library.  You may convey such object
+code under terms of your choice, provided that, if the incorporated
+material is not limited to numerical parameters, data structure
+layouts and accessors, or small macros, inline functions and templates
+(ten or fewer lines in length), you do both of the following:
+
+   a) Give prominent notice with each copy of the object code that the
+   Library is used in it and that the Library and its use are
+   covered by this License.
+
+   b) Accompany the object code with a copy of the GNU GPL and this license
+   document.
+
+  4. Combined Works.
+
+  You may convey a Combined Work under terms of your choice that,
+taken together, effectively do not restrict modification of the
+portions of the Library contained in the Combined Work and reverse
+engineering for debugging such modifications, if you also do each of
+the following:
+
+   a) Give prominent notice with each copy of the Combined Work that
+   the Library is used in it and that the Library and its use are
+   covered by this License.
+
+   b) Accompany the Combined Work with a copy of the GNU GPL and this license
+   document.
+
+   c) For a Combined Work that displays copyright notices during
+   execution, include the copyright notice for the Library among
+   these notices, as well as a reference directing the user to the
+   copies of the GNU GPL and this license document.
+
+   d) Do one of the following:
+
+       0) Convey the Minimal Corresponding Source under the terms of this
+       License, and the Corresponding Application Code in a form
+       suitable for, and under terms that permit, the user to
+       recombine or relink the Application with a modified version of
+       the Linked Version to produce a modified Combined Work, in the
+       manner specified by section 6 of the GNU GPL for conveying
+       Corresponding Source.
+
+       1) Use a suitable shared library mechanism for linking with the
+       Library.  A suitable mechanism is one that (a) uses at run time
+       a copy of the Library already present on the user's computer
+       system, and (b) will operate properly with a modified version
+       of the Library that is interface-compatible with the Linked
+       Version.
+
+   e) Provide Installation Information, but only if you would otherwise
+   be required to provide such information under section 6 of the
+   GNU GPL, and only to the extent that such information is
+   necessary to install and execute a modified version of the
+   Combined Work produced by recombining or relinking the
+   Application with a modified version of the Linked Version. (If
+   you use option 4d0, the Installation Information must accompany
+   the Minimal Corresponding Source and Corresponding Application
+   Code. If you use option 4d1, you must provide the Installation
+   Information in the manner specified by section 6 of the GNU GPL
+   for conveying Corresponding Source.)
+
+  5. Combined Libraries.
+
+  You may place library facilities that are a work based on the
+Library side by side in a single library together with other library
+facilities that are not Applications and are not covered by this
+License, and convey such a combined library under terms of your
+choice, if you do both of the following:
+
+   a) Accompany the combined library with a copy of the same work based
+   on the Library, uncombined with any other library facilities,
+   conveyed under the terms of this License.
+
+   b) Give prominent notice with the combined library that part of it
+   is a work based on the Library, and explaining where to find the
+   accompanying uncombined form of the same work.
+
+  6. Revised Versions of the GNU Lesser General Public License.
+
+  The Free Software Foundation may publish revised and/or new versions
+of the GNU Lesser General Public License from time to time. Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.
+
+  Each version is given a distinguishing version number. If the
+Library as you received it specifies that a certain numbered version
+of the GNU Lesser General Public License "or any later version"
+applies to it, you have the option of following the terms and
+conditions either of that published version or of any later version
+published by the Free Software Foundation. If the Library as you
+received it does not specify a version number of the GNU Lesser
+General Public License, you may choose any version of the GNU Lesser
+General Public License ever published by the Free Software Foundation.
+
+  If the Library as you received it specifies that a proxy can decide
+whether future versions of the GNU Lesser General Public License shall
+apply, that proxy's public statement of acceptance of any version is
+permanent authorization for you to choose that version for the
+Library.
diff --git a/ChangeLog b/ChangeLog
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/INSTALL b/INSTALL
new file mode 100644 (file)
index 0000000..23e5f25
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,236 @@
+Installation Instructions
+*************************
+
+Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005 Free
+Software Foundation, Inc.
+
+This file is free documentation; the Free Software Foundation gives
+unlimited permission to copy, distribute and modify it.
+
+Basic Installation
+==================
+
+These are generic installation instructions.
+
+   The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation.  It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions.  Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, and a
+file `config.log' containing compiler output (useful mainly for
+debugging `configure').
+
+   It can also use an optional file (typically called `config.cache'
+and enabled with `--cache-file=config.cache' or simply `-C') that saves
+the results of its tests to speed up reconfiguring.  (Caching is
+disabled by default to prevent problems with accidental use of stale
+cache files.)
+
+   If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release.  If you are using the cache, and at
+some point `config.cache' contains results you don't want to keep, you
+may remove or edit it.
+
+   The file `configure.ac' (or `configure.in') is used to create
+`configure' by a program called `autoconf'.  You only need
+`configure.ac' if you want to change it or regenerate `configure' using
+a newer version of `autoconf'.
+
+The simplest way to compile this package is:
+
+  1. `cd' to the directory containing the package's source code and type
+     `./configure' to configure the package for your system.  If you're
+     using `csh' on an old version of System V, you might need to type
+     `sh ./configure' instead to prevent `csh' from trying to execute
+     `configure' itself.
+
+     Running `configure' takes awhile.  While running, it prints some
+     messages telling which features it is checking for.
+
+  2. Type `make' to compile the package.
+
+  3. Optionally, type `make check' to run any self-tests that come with
+     the package.
+
+  4. Type `make install' to install the programs and any data files and
+     documentation.
+
+  5. You can remove the program binaries and object files from the
+     source code directory by typing `make clean'.  To also remove the
+     files that `configure' created (so you can compile the package for
+     a different kind of computer), type `make distclean'.  There is
+     also a `make maintainer-clean' target, but that is intended mainly
+     for the package's developers.  If you use it, you may have to get
+     all sorts of other programs in order to regenerate files that came
+     with the distribution.
+
+Compilers and Options
+=====================
+
+Some systems require unusual options for compilation or linking that the
+`configure' script does not know about.  Run `./configure --help' for
+details on some of the pertinent environment variables.
+
+   You can give `configure' initial values for configuration parameters
+by setting variables in the command line or in the environment.  Here
+is an example:
+
+     ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix
+
+   *Note Defining Variables::, for more details.
+
+Compiling For Multiple Architectures
+====================================
+
+You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory.  To do this, you must use a version of `make' that
+supports the `VPATH' variable, such as GNU `make'.  `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script.  `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'.
+
+   If you have to use a `make' that does not support the `VPATH'
+variable, you have to compile the package for one architecture at a
+time in the source code directory.  After you have installed the
+package for one architecture, use `make distclean' before reconfiguring
+for another architecture.
+
+Installation Names
+==================
+
+By default, `make install' installs the package's commands under
+`/usr/local/bin', include files under `/usr/local/include', etc.  You
+can specify an installation prefix other than `/usr/local' by giving
+`configure' the option `--prefix=PREFIX'.
+
+   You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files.  If you
+pass the option `--exec-prefix=PREFIX' to `configure', the package uses
+PREFIX as the prefix for installing programs and libraries.
+Documentation and other data files still use the regular prefix.
+
+   In addition, if you use an unusual directory layout you can give
+options like `--bindir=DIR' to specify different values for particular
+kinds of files.  Run `configure --help' for a list of the directories
+you can set and what kinds of files go in them.
+
+   If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+Optional Features
+=================
+
+Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System).  The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+   For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+Specifying the System Type
+==========================
+
+There may be some features `configure' cannot figure out automatically,
+but needs to determine by the type of machine the package will run on.
+Usually, assuming the package is built to be run on the _same_
+architectures, `configure' can figure that out, but if it prints a
+message saying it cannot guess the machine type, give it the
+`--build=TYPE' option.  TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name which has the form:
+
+     CPU-COMPANY-SYSTEM
+
+where SYSTEM can have one of these forms:
+
+     OS KERNEL-OS
+
+   See the file `config.sub' for the possible values of each field.  If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the machine type.
+
+   If you are _building_ compiler tools for cross-compiling, you should
+use the option `--target=TYPE' to select the type of system they will
+produce code for.
+
+   If you want to _use_ a cross compiler, that generates code for a
+platform different from the build platform, you should specify the
+"host" platform (i.e., that on which the generated programs will
+eventually be run) with `--host=TYPE'.
+
+Sharing Defaults
+================
+
+If you want to set default values for `configure' scripts to share, you
+can create a site shell script called `config.site' that gives default
+values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists.  Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Defining Variables
+==================
+
+Variables not defined in a site shell script can be set in the
+environment passed to `configure'.  However, some packages may run
+configure again during the build, and the customized values of these
+variables may be lost.  In order to avoid this problem, you should set
+them in the `configure' command line, using `VAR=value'.  For example:
+
+     ./configure CC=/usr/local2/bin/gcc
+
+causes the specified `gcc' to be used as the C compiler (unless it is
+overridden in the site shell script).  Here is a another example:
+
+     /bin/bash ./configure CONFIG_SHELL=/bin/bash
+
+Here the `CONFIG_SHELL=/bin/bash' operand causes subsequent
+configuration-related scripts to be executed by `/bin/bash'.
+
+`configure' Invocation
+======================
+
+`configure' recognizes the following options to control how it operates.
+
+`--help'
+`-h'
+     Print a summary of the options to `configure', and exit.
+
+`--version'
+`-V'
+     Print the version of Autoconf used to generate the `configure'
+     script, and exit.
+
+`--cache-file=FILE'
+     Enable the cache: use and save the results of the tests in FILE,
+     traditionally `config.cache'.  FILE defaults to `/dev/null' to
+     disable caching.
+
+`--config-cache'
+`-C'
+     Alias for `--cache-file=config.cache'.
+
+`--quiet'
+`--silent'
+`-q'
+     Do not print messages saying which checks are being made.  To
+     suppress all normal output, redirect it to `/dev/null' (any error
+     messages will still be shown).
+
+`--srcdir=DIR'
+     Look for the package's source code in directory DIR.  Usually
+     `configure' can determine that directory automatically.
+
+`configure' also accepts some other, not widely useful, options.  Run
+`configure --help' for more details.
+
diff --git a/Makefile.am b/Makefile.am
new file mode 100644 (file)
index 0000000..9892d93
--- /dev/null
@@ -0,0 +1,34 @@
+MAINTAINERCLEANFILES = \
+       Makefile.in \
+       aclocal.m4 \
+       compile \
+       config.guess \
+       config.h.in \
+       config.sub \
+       configure \
+       depcomp \
+       install-sh \
+       ltmain.sh \
+       missing
+
+EXTRA_DIST = m4/Makefile.in \
+       README \
+       AUTHORS \
+       COPYING
+
+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/NEWS b/NEWS
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/TODO b/TODO
new file mode 100644 (file)
index 0000000..3270ef7
--- /dev/null
+++ b/TODO
@@ -0,0 +1,14 @@
+ * documentation (based on python bindings)
+   * Ethumb
+   * Ethumb_Client
+
+ * memory handling:
+   * zero pointer parameters before failing on SAFETY macros (file_get, etc)
+
+ * unit tests, be them in C or Python, covering:
+   * thumbnail generation respect parameters (size, format...)
+   * respect fdo standards (hash, location, etc, uri with spaces...)
+   * server died recovery, just add timeout and kill server before expires
+
+ * examples:
+   * error handling, including reconnection.
diff --git a/autogen.sh b/autogen.sh
new file mode 100755 (executable)
index 0000000..5bbd4d9
--- /dev/null
@@ -0,0 +1,14 @@
+#!/bin/sh
+
+rm -rf autom4te.cache
+rm -f aclocal.m4 ltmain.sh
+
+echo "Running aclocal..." ; aclocal $ACLOCAL_FLAGS -I m4 || exit 1
+echo "Running autoheader..." ; autoheader || exit 1
+echo "Running autoconf..." ; autoconf || exit 1
+echo "Running libtoolize..." ; (libtoolize --copy --automake || glibtoolize --automake) || exit 1
+echo "Running automake..." ; automake --add-missing --copy --gnu || exit 1
+
+if [ -z "$NOCONFIGURE" ]; then
+       ./configure "$@"
+fi
diff --git a/configure.ac b/configure.ac
new file mode 100644 (file)
index 0000000..4b93482
--- /dev/null
@@ -0,0 +1,113 @@
+AC_INIT(ethumb, 0.1, antognolli@profusion.mobi)
+AC_PREREQ(2.52)
+AC_CONFIG_SRCDIR(configure.ac)
+AC_CANONICAL_BUILD
+AC_CANONICAL_HOST
+AC_ISC_POSIX
+
+AM_INIT_AUTOMAKE(1.6 dist-bzip2)
+AM_CONFIG_HEADER(config.h)
+AC_SUBST(ACLOCAL_AMFLAGS, "-I m4")
+_XTERM_COLORS
+
+AC_PROG_CC
+AM_PROG_CC_STDC
+AM_PROG_CC_C_O
+AC_HEADER_STDC
+AC_C___ATTRIBUTE__
+dnl AC_C_CONST is bogus, its tests fails on -Wall -O1 ( uninitialized values)
+dnl AC_C_CONST
+
+define([AC_LIBTOOL_LANG_F77_CONFIG], [:])dnl
+AC_PROG_LIBTOOL
+
+VMAJ=`echo $PACKAGE_VERSION | awk -F. '{printf("%s", $1);}'`
+VMIN=`echo $PACKAGE_VERSION | awk -F. '{printf("%s", $2);}'`
+version_info=`expr $VMAJ + $VMIN`
+AC_SUBST(version_info)
+
+themesdir="${datadir}/ethumb/data/frames"
+AC_SUBST(themesdir)
+AS_AC_EXPAND(THEMESDIR, $themesdir)
+AC_DEFINE_UNQUOTED(THEMESDIR, ["$THEMESDIR"], [Where frame theme files are installed.]
+)
+
+AS_AC_EXPAND(SYSCONFDIR, $sysconfdir)
+AC_DEFINE_UNQUOTED(SYSCONFDIR, ["$SYSCONFDIR"], [Where system configuration is stored])
+
+pluginsdir="${libdir}/ethumb/plugins"
+AC_SUBST(pluginsdir)
+AS_AC_EXPAND(PLUGINSDIR, $pluginsdir)
+AC_DEFINE_UNQUOTED(PLUGINSDIR, ["$PLUGINSDIR"], [Where plugins are installed.])
+
+PKG_CHECK_MODULES(EINA, [eina-0])
+PKG_CHECK_MODULES(EVAS, [evas])
+PKG_CHECK_MODULES(ECORE, [ecore])
+PKG_CHECK_MODULES(ECORE_EVAS, [ecore-evas])
+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],
+[
+        AC_ETH_CHECK_PKG(EMOTION, emotion, [], [EMOTION=false])
+])
+
+AC_ETH_OPTIONAL_MODULE([emotion], true, [CHECK_MODULE_EMOTION])
+
+if $USE_MODULE_EMOTION ; then
+        requirement_ethumb="$requirement_ethumb emotion"
+fi
+
+AM_CONDITIONAL(HAVE_EPDF, false)
+define([CHECK_MODULE_EPDF],
+[
+        AC_ETH_CHECK_PKG(EPDF, epdf, [], [EPDF=false])
+])
+
+AC_ETH_OPTIONAL_MODULE([epdf], true, [CHECK_MODULE_EPDF])
+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/data/Makefile.am b/data/Makefile.am
new file mode 100644 (file)
index 0000000..1f3459f
--- /dev/null
@@ -0,0 +1,3 @@
+MAINTAINERCLEANFILES = Makefile.in
+
+SUBDIRS = frames
diff --git a/data/frames/Makefile.am b/data/frames/Makefile.am
new file mode 100644 (file)
index 0000000..256cda9
--- /dev/null
@@ -0,0 +1,20 @@
+MAINTAINERCLEANFILES = Makefile.in
+
+EDJE_CC = edje_cc
+EDJE_FLAGS = -v \
+       -id $(top_srcdir)/data/frames/images
+
+filesdir = $(themesdir)
+files_DATA = default.edj
+
+EXTRA_DIST = \
+       default.edc \
+       images/border-0.jpg
+
+default.edj: Makefile $(EXTRADIST)
+       $(EDJE_CC) $(EDJE_FLAGS) \
+               $(top_srcdir)/data/frames/default.edc \
+               $(top_builddir)/data/frames/default.edj
+
+clean-local:
+       rm -f *.edj
diff --git a/data/frames/default.edc b/data/frames/default.edc
new file mode 100644 (file)
index 0000000..5341263
--- /dev/null
@@ -0,0 +1,46 @@
+collections {
+   images {
+      image: "border-0.jpg" COMP;
+   }
+
+   group {
+      name: "frame/default";
+
+      parts {
+         part {
+            name: "img";
+            type: SWALLOW;
+            mouse_events: 0;
+            description {
+               state: "default" 0.0;
+            }
+         } // img
+
+         part {
+            name: "border";
+            type: IMAGE;
+            mouse_events: 0;
+            description {
+               state: "default" 0.0;
+               color: 224 224 224 255;
+               rel1 {
+                  to: "img";
+                  relative: 0.0 0.0;
+                  offset: 0 0;
+               }
+               rel2 {
+                  to: "img";
+                  relative: 1.0 1.0;
+                  offset: -1 -1;
+               }
+               image {
+                  normal: "border-0.jpg";
+                  border: 2 2 2 2;
+                  middle: 0;
+               }
+            }
+         } // border
+
+      }
+   }
+}
diff --git a/data/frames/images/border-0.jpg b/data/frames/images/border-0.jpg
new file mode 100644 (file)
index 0000000..ee66879
Binary files /dev/null and b/data/frames/images/border-0.jpg differ
diff --git a/debian/changelog b/debian/changelog
new file mode 100644 (file)
index 0000000..15dae93
--- /dev/null
@@ -0,0 +1,5 @@
+ethumb (0.1-1) unstable; urgency=low
+
+  * a SVN release.
+
+ -- quaker <quaker66@gmail.com> Sat, 10 Apr 2009 10:50:46 +0100
diff --git a/debian/compat b/debian/compat
new file mode 100644 (file)
index 0000000..1e8b314
--- /dev/null
@@ -0,0 +1 @@
+6
diff --git a/debian/control b/debian/control
new file mode 100644 (file)
index 0000000..ac84f1b
--- /dev/null
@@ -0,0 +1,14 @@
+Source: ethumb
+Section: x11
+Priority: optional
+Maintainer: quaker <quaker66@gmail.com>
+Build-Depends: cdbs, debhelper (>= 6), libevas-dev, libedje-dev, libeina-dev, libecore-dev, pkg-config, libtool
+Standards-Version: 3.8.1
+Homepage: http://www.enlightenment.org
+
+Package: ethumb
+Architecture: any
+Depends: ${shlibs:Depends}
+Description: Enlightenment thumbnailing library
+ Thumbnailing library meant to replace epsilon.
+
diff --git a/debian/copyright b/debian/copyright
new file mode 100644 (file)
index 0000000..065c959
--- /dev/null
@@ -0,0 +1,9 @@
+This package was debianized by quaker <quaker66@gmail.com> on
+Sat, 10 Apr 2009 10:50:46 +0100.
+
+Author(s): 
+ Rafael Antognolli <antognolli@profusion.mobi>
+
+License:
+ See the COPYING file
+
diff --git a/debian/rules b/debian/rules
new file mode 100755 (executable)
index 0000000..6acb8ff
--- /dev/null
@@ -0,0 +1,11 @@
+#!/usr/bin/make -f
+
+include /usr/share/cdbs/1/rules/debhelper.mk
+include /usr/share/cdbs/1/class/autotools.mk
+
+DEB_CONFIGURE_SCRIPT := ./autogen.sh
+DEB_MAKE_CLEAN_TARGET := distclean
+DEB_CONFIGURE_EXTRA_FLAGS := --disable-rpath
+
+clean::
+       [ ! -f Makefile ] || make distclean
diff --git a/ethumb.pc.in b/ethumb.pc.in
new file mode 100644 (file)
index 0000000..f1db1a1
--- /dev/null
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: ethumb
+Description: Thumbnail Generator Library
+Requires: @requirement_ethumb@
+Version: @VERSION@
+Libs: -L${libdir} -lethumb
+Cflags: -I${includedir}
diff --git a/ethumb_client.pc.in b/ethumb_client.pc.in
new file mode 100644 (file)
index 0000000..b1e44b7
--- /dev/null
@@ -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/m4/Makefile.am b/m4/Makefile.am
new file mode 100644 (file)
index 0000000..be8ee32
--- /dev/null
@@ -0,0 +1,8 @@
+MAINTAINERCLEANFILES = Makefile.in
+EXTRA_DIST = iconv.m4 \
+       lib-ld.m4 \
+       lib-link.m4 \
+       lib-prefix.m4 \
+       progtest.m4 \
+       as-expand.m4 \
+       ac-modules.m4
diff --git a/m4/ac-modules.m4 b/m4/ac-modules.m4
new file mode 100644 (file)
index 0000000..b1088f1
--- /dev/null
@@ -0,0 +1,168 @@
+dnl _XTERM_COLORS
+define([_XTERM_COLORS],
+[
+        # Check for XTerm and define some colors
+        if test "x$TERM" = "xxterm"; then
+                COLOR_PREF="\0033\0133"
+                COLOR_H="${COLOR_PREF}1m"
+                COLOR_HGREEN="${COLOR_PREF}1;32m"
+                COLOR_HRED="${COLOR_PREF}1;31m"
+                COLOR_GREEN="${COLOR_PREF}32m"
+                COLOR_RED="${COLOR_PREF}31m"
+                COLOR_YELLOW="${COLOR_PREF}1;33m"
+                COLOR_END="${COLOR_PREF}0m"
+        else
+                COLOR_H=""
+                COLOR_HGREEN=""
+                COLOR_HRED=""
+                COLOR_GREEN=""
+                COLOR_RED=""
+                COLOR_YELLOW=""
+                COLOR_END=""
+        fi
+])
+
+dnl AC_ETH_CHECK_PKG(name, lib [>= version], [action-if, [action-not]])
+dnl   improved version of PKG_CHECK_MODULES, it does the same checking
+dnl   and defines HAVE_[name]=yes/no and also exports
+dnl   [name]_CFLAGS and [name]_LIBS.
+dnl
+dnl   if action-not isn't provided, AC_MSG_ERROR will be used.
+dnl
+dnl   Checks:
+dnl       lib >= version
+dnl
+dnl   Provides:
+dnl       - HAVE_[name]=yes|no
+dnl       - [name]_CFLAGS: if HAVE_[name]=yes
+dnl       - [name]_LIBS: if HAVE_[name]=yes
+dnl       - [name]_VERSION: if HAVE_[name]=yes
+dnl
+AC_DEFUN([AC_ETH_CHECK_PKG],
+[
+# ----------------------------------------------------------------------
+# BEGIN: Check library with pkg-config: $1 (pkg-config=$2)
+#
+
+        PKG_CHECK_MODULES([$1], [$2],
+                          [
+                                HAVE_[$1]=yes
+                                [pkg_name]=$(echo "[$2]" | cut -d\   -f1)
+                                [$1]_VERSION=$($PKG_CONFIG --modversion $pkg_name)
+                                AC_SUBST([$1]_VERSION)
+                                AC_SUBST([$1]_CFLAGS)
+                                AC_SUBST([$1]_LIBS)
+                                ifelse([$3], , :, [$3])
+                          ],
+                          [
+                                HAVE_[$1]=no
+                                ifelse([$4], , AC_MSG_ERROR(you need [$2] development installed!), AC_MSG_RESULT(no); [$4])
+                          ])
+        AM_CONDITIONAL(HAVE_[$1], test x$HAVE_[$1] = xyes)
+        AC_SUBST(HAVE_[$1])
+        if test x$HAVE_[$1] = xyes; then
+                AC_DEFINE_UNQUOTED(HAVE_[$1], 1, Package [$1] ($2) found.)
+        fi
+
+#
+# END: Check library with pkg-config: $1 (pkg-config=$2)
+# ----------------------------------------------------------------------
+])
+
+dnl AC_ETH_OPTIONAL_MODULE(name, [initial-status, [check-if-enabled]])
+dnl   Defines configure argument --<enable|disable>-[name] to enable an
+dnl   optional module called 'name'.
+dnl
+dnl   If initial-status is true, then it's enabled by default and option
+dnl   will be called --disable-[name], otherwise it's disabled and option
+dnl   is --enable-[name].
+dnl
+dnl   If module is enabled, then check-if-enabled will be executed. This
+dnl   may change the contents of shell variable NAME (uppercase version of
+dnl   name, with underscores instead of dashed) to something different than
+dnl   "true" to disable module.
+dnl
+dnl Parameters:
+dnl     - name: module name to use. It will be converted to have dashes (-)
+dnl          instead of underscores, and will be in lowercase.
+dnl     - initial-status: true or false, states if module is enabled or
+dnl          disabled by default.
+dnl     - check-if-enabled: macro to be expanded inside check for enabled
+dnl           module.
+dnl
+dnl Provides:
+dnl     - USE_MODULE_[name]=true|false [make, shell]
+dnl     - USE_MODULE_[name]=1 if enabled [config.h]
+dnl
+AC_DEFUN([AC_ETH_OPTIONAL_MODULE],
+[
+# ----------------------------------------------------------------------
+# BEGIN: Check for optional module: $1 (default: $2)
+#
+        m4_pushdef([MODNAME], [m4_bpatsubst(m4_toupper([$1]), -, _)])dnl
+        m4_pushdef([modname_opt], [m4_bpatsubst(m4_tolower([$1]), _, -)])
+        m4_pushdef([INITVAL], [m4_default([$2], [false])])dnl
+        m4_pushdef([ENABLE_HELP], AS_HELP_STRING([--enable-modname_opt],
+                               [enable optional module modname_opt. Default is disabled.])
+                )dnl
+        m4_pushdef([DISABLE_HELP], AS_HELP_STRING([--disable-modname_opt],
+                               [disable optional module modname_opt. Default is enabled.])
+                )dnl
+        m4_pushdef([HELP_STR], m4_if(INITVAL, [true], [DISABLE_HELP], [ENABLE_HELP]))dnl
+        m4_pushdef([NOT_INITVAL], m4_if(INITVAL, [true], [false], [true]))dnl
+
+        USING_MODULES=1
+
+        MODNAME=INITVAL
+        AC_ARG_ENABLE(modname_opt, HELP_STR, [MODNAME=${enableval:-NOT_INITVAL}])
+        if test x[$]MODNAME = xyes || test x[$]MODNAME = x1; then
+                MODNAME=true
+        fi
+        if test x[$]MODNAME = xno || test x[$]MODNAME = x0; then
+                MODNAME=false
+        fi
+
+        _XTERM_COLORS
+
+        # Check list for optional module $1
+        if test x[$]MODNAME = xtrue; then
+                ifelse([$3], , , [
+echo
+echo "checking optional module modname_opt:"
+# BEGIN: User checks
+$3
+# END: User checks
+if test x[$]MODNAME = xfalse; then
+        echo -e "optional module modname_opt ${COLOR_HRED}failed${COLOR_END} checks."
+else
+        echo -e "optional module modname_opt passed checks."
+fi
+echo
+])
+
+                if test x[$]MODNAME = xfalse; then
+                        echo -e "${COLOR_YELLOW}Warning:${COLOR_END} optional module ${COLOR_H}modname_opt${COLOR_END} disabled by extra checks."
+                fi
+        fi
+
+        # Check if user checks succeeded
+        if test x[$]MODNAME = xtrue; then
+                [OPTIONAL_MODULES]="$[OPTIONAL_MODULES] modname_opt"
+                AC_DEFINE_UNQUOTED(USE_MODULE_[]MODNAME, 1, Use module modname_opt)
+        else
+                [UNUSED_OPTIONAL_MODULES]="$[UNUSED_OPTIONAL_MODULES] modname_opt"
+        fi
+
+        AM_CONDITIONAL(USE_MODULE_[]MODNAME, test x[$]MODNAME = xtrue)
+        AC_SUBST(USE_MODULE_[]MODNAME)
+        USE_MODULE_[]MODNAME=[$]MODNAME
+
+        m4_popdef([HELP_STR])dnl
+        m4_popdef([DISABLE_HELP])dnl
+        m4_popdef([ENABLE_HELP])dnl
+        m4_popdef([INITVAL])dnl
+        m4_popdef([MODNAME])
+#
+# END: Check for optional module: $1 ($2)
+# ----------------------------------------------------------------------
+])
diff --git a/m4/ac_attribute.m4 b/m4/ac_attribute.m4
new file mode 100644 (file)
index 0000000..23479a9
--- /dev/null
@@ -0,0 +1,47 @@
+dnl Copyright (C) 2004-2008 Kim Woelders
+dnl Copyright (C) 2008 Vincent Torri <vtorri at univ-evry dot fr>
+dnl That code is public domain and can be freely used or copied.
+dnl Originally snatched from somewhere...
+
+dnl Macro for checking if the compiler supports __attribute__
+
+dnl Usage: AC_C___ATTRIBUTE__
+dnl call AC_DEFINE for HAVE___ATTRIBUTE__ and __UNUSED__
+dnl if the compiler supports __attribute__, HAVE___ATTRIBUTE__ is
+dnl defined to 1 and __UNUSED__ is defined to __attribute__((unused))
+dnl otherwise, HAVE___ATTRIBUTE__ is not defined and __UNUSED__ is
+dnl defined to nothing.
+
+AC_DEFUN([AC_C___ATTRIBUTE__],
+[
+
+AC_MSG_CHECKING([for __attribute__])
+
+AC_CACHE_VAL([ac_cv___attribute__],
+   [AC_TRY_COMPILE(
+       [
+#include <stdlib.h>
+
+int func(int x);
+int foo(int x __attribute__ ((unused)))
+{
+   exit(1);
+}
+       ],
+       [],
+       [ac_cv___attribute__="yes"],
+       [ac_cv___attribute__="no"]
+    )])
+
+AC_MSG_RESULT($ac_cv___attribute__)
+
+if test "x${ac_cv___attribute__}" = "xyes" ; then
+   AC_DEFINE([HAVE___ATTRIBUTE__], [1], [Define to 1 if your compiler has __attribute__])
+   AC_DEFINE([__UNUSED__], [__attribute__((unused))], [Macro declaring a function argument to be unused])
+  else
+    AC_DEFINE([__UNUSED__], [], [Macro declaring a function argument to be unused])
+fi
+
+])
+
+dnl End of ac_attribute.m4
diff --git a/m4/as-expand.m4 b/m4/as-expand.m4
new file mode 100644 (file)
index 0000000..7b7e4a8
--- /dev/null
@@ -0,0 +1,43 @@
+dnl AS_AC_EXPAND(VAR, CONFIGURE_VAR)
+dnl
+dnl example
+dnl AS_AC_EXPAND(SYSCONFDIR, $sysconfdir)
+dnl will set SYSCONFDIR to /usr/local/etc if prefix=/usr/local
+
+AC_DEFUN([AS_AC_EXPAND],
+[
+  EXP_VAR=[$1]
+  FROM_VAR=[$2]
+
+  dnl first expand prefix and exec_prefix if necessary
+  prefix_save=$prefix
+  exec_prefix_save=$exec_prefix
+
+  dnl if no prefix given, then use /usr/local, the default prefix
+  if test "x$prefix" = "xNONE"; then
+    prefix=$ac_default_prefix
+  fi
+  dnl if no exec_prefix given, then use prefix
+  if test "x$exec_prefix" = "xNONE"; then
+    exec_prefix=$prefix
+  fi
+
+  full_var="$FROM_VAR"
+  dnl loop until it doesn't change anymore
+  while true; do
+    new_full_var="`eval echo $full_var`"
+    dnl if test "x$new_full_var" = "x$full_var"; then
+    if test "x${new_full_var:0:1}" != "x\$"; then
+        break;
+    fi
+    full_var=$new_full_var
+  done
+
+  dnl clean up
+  full_var=$new_full_var
+  AC_SUBST([$1], "$full_var")
+
+  dnl restore prefix and exec_prefix
+  prefix=$prefix_save
+  exec_prefix=$exec_prefix_save
+])
diff --git a/m4/iconv.m4 b/m4/iconv.m4
new file mode 100644 (file)
index 0000000..66bc76f
--- /dev/null
@@ -0,0 +1,180 @@
+# iconv.m4 serial AM6 (gettext-0.17)
+dnl Copyright (C) 2000-2002, 2007 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl From Bruno Haible.
+
+AC_DEFUN([AM_ICONV_LINKFLAGS_BODY],
+[
+  dnl Prerequisites of AC_LIB_LINKFLAGS_BODY.
+  AC_REQUIRE([AC_LIB_PREPARE_PREFIX])
+  AC_REQUIRE([AC_LIB_RPATH])
+
+  dnl Search for libiconv and define LIBICONV, LTLIBICONV and INCICONV
+  dnl accordingly.
+  AC_LIB_LINKFLAGS_BODY([iconv])
+])
+
+AC_DEFUN([AM_ICONV_LINK],
+[
+  dnl Some systems have iconv in libc, some have it in libiconv (OSF/1 and
+  dnl those with the standalone portable GNU libiconv installed).
+  AC_REQUIRE([AC_CANONICAL_HOST]) dnl for cross-compiles
+
+  dnl Search for libiconv and define LIBICONV, LTLIBICONV and INCICONV
+  dnl accordingly.
+  AC_REQUIRE([AM_ICONV_LINKFLAGS_BODY])
+
+  dnl Add $INCICONV to CPPFLAGS before performing the following checks,
+  dnl because if the user has installed libiconv and not disabled its use
+  dnl via --without-libiconv-prefix, he wants to use it. The first
+  dnl AC_TRY_LINK will then fail, the second AC_TRY_LINK will succeed.
+  am_save_CPPFLAGS="$CPPFLAGS"
+  AC_LIB_APPENDTOVAR([CPPFLAGS], [$INCICONV])
+
+  AC_CACHE_CHECK([for iconv], am_cv_func_iconv, [
+    am_cv_func_iconv="no, consider installing GNU libiconv"
+    am_cv_lib_iconv=no
+    AC_TRY_LINK([#include <stdlib.h>
+#include <iconv.h>],
+      [iconv_t cd = iconv_open("","");
+       iconv(cd,NULL,NULL,NULL,NULL);
+       iconv_close(cd);],
+      am_cv_func_iconv=yes)
+    if test "$am_cv_func_iconv" != yes; then
+      am_save_LIBS="$LIBS"
+      LIBS="$LIBS $LIBICONV"
+      AC_TRY_LINK([#include <stdlib.h>
+#include <iconv.h>],
+        [iconv_t cd = iconv_open("","");
+         iconv(cd,NULL,NULL,NULL,NULL);
+         iconv_close(cd);],
+        am_cv_lib_iconv=yes
+        am_cv_func_iconv=yes)
+      LIBS="$am_save_LIBS"
+    fi
+  ])
+  if test "$am_cv_func_iconv" = yes; then
+    AC_CACHE_CHECK([for working iconv], am_cv_func_iconv_works, [
+      dnl This tests against bugs in AIX 5.1 and HP-UX 11.11.
+      am_save_LIBS="$LIBS"
+      if test $am_cv_lib_iconv = yes; then
+        LIBS="$LIBS $LIBICONV"
+      fi
+      AC_TRY_RUN([
+#include <iconv.h>
+#include <string.h>
+int main ()
+{
+  /* Test against AIX 5.1 bug: Failures are not distinguishable from successful
+     returns.  */
+  {
+    iconv_t cd_utf8_to_88591 = iconv_open ("ISO8859-1", "UTF-8");
+    if (cd_utf8_to_88591 != (iconv_t)(-1))
+      {
+        static const char input[] = "\342\202\254"; /* EURO SIGN */
+        char buf[10];
+        const char *inptr = input;
+        size_t inbytesleft = strlen (input);
+        char *outptr = buf;
+        size_t outbytesleft = sizeof (buf);
+        size_t res = iconv (cd_utf8_to_88591,
+                            (char **) &inptr, &inbytesleft,
+                            &outptr, &outbytesleft);
+        if (res == 0)
+          return 1;
+      }
+  }
+#if 0 /* This bug could be worked around by the caller.  */
+  /* Test against HP-UX 11.11 bug: Positive return value instead of 0.  */
+  {
+    iconv_t cd_88591_to_utf8 = iconv_open ("utf8", "iso88591");
+    if (cd_88591_to_utf8 != (iconv_t)(-1))
+      {
+        static const char input[] = "\304rger mit b\366sen B\374bchen ohne Augenma\337";
+        char buf[50];
+        const char *inptr = input;
+        size_t inbytesleft = strlen (input);
+        char *outptr = buf;
+        size_t outbytesleft = sizeof (buf);
+        size_t res = iconv (cd_88591_to_utf8,
+                            (char **) &inptr, &inbytesleft,
+                            &outptr, &outbytesleft);
+        if ((int)res > 0)
+          return 1;
+      }
+  }
+#endif
+  /* Test against HP-UX 11.11 bug: No converter from EUC-JP to UTF-8 is
+     provided.  */
+  if (/* Try standardized names.  */
+      iconv_open ("UTF-8", "EUC-JP") == (iconv_t)(-1)
+      /* Try IRIX, OSF/1 names.  */
+      && iconv_open ("UTF-8", "eucJP") == (iconv_t)(-1)
+      /* Try AIX names.  */
+      && iconv_open ("UTF-8", "IBM-eucJP") == (iconv_t)(-1)
+      /* Try HP-UX names.  */
+      && iconv_open ("utf8", "eucJP") == (iconv_t)(-1))
+    return 1;
+  return 0;
+}], [am_cv_func_iconv_works=yes], [am_cv_func_iconv_works=no],
+        [case "$host_os" in
+           aix* | hpux*) am_cv_func_iconv_works="guessing no" ;;
+           *)            am_cv_func_iconv_works="guessing yes" ;;
+         esac])
+      LIBS="$am_save_LIBS"
+    ])
+    case "$am_cv_func_iconv_works" in
+      *no) am_func_iconv=no am_cv_lib_iconv=no ;;
+      *)   am_func_iconv=yes ;;
+    esac
+  else
+    am_func_iconv=no am_cv_lib_iconv=no
+  fi
+  if test "$am_func_iconv" = yes; then
+    AC_DEFINE(HAVE_ICONV, 1,
+      [Define if you have the iconv() function and it works.])
+  fi
+  if test "$am_cv_lib_iconv" = yes; then
+    AC_MSG_CHECKING([how to link with libiconv])
+    AC_MSG_RESULT([$LIBICONV])
+  else
+    dnl If $LIBICONV didn't lead to a usable library, we don't need $INCICONV
+    dnl either.
+    CPPFLAGS="$am_save_CPPFLAGS"
+    LIBICONV=
+    LTLIBICONV=
+  fi
+  AC_SUBST(LIBICONV)
+  AC_SUBST(LTLIBICONV)
+])
+
+AC_DEFUN([AM_ICONV],
+[
+  AM_ICONV_LINK
+  if test "$am_cv_func_iconv" = yes; then
+    AC_MSG_CHECKING([for iconv declaration])
+    AC_CACHE_VAL(am_cv_proto_iconv, [
+      AC_TRY_COMPILE([
+#include <stdlib.h>
+#include <iconv.h>
+extern
+#ifdef __cplusplus
+"C"
+#endif
+#if defined(__STDC__) || defined(__cplusplus)
+size_t iconv (iconv_t cd, char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);
+#else
+size_t iconv();
+#endif
+], [], am_cv_proto_iconv_arg1="", am_cv_proto_iconv_arg1="const")
+      am_cv_proto_iconv="extern size_t iconv (iconv_t cd, $am_cv_proto_iconv_arg1 char * *inbuf, size_t *inbytesleft, char * *outbuf, size_t *outbytesleft);"])
+    am_cv_proto_iconv=`echo "[$]am_cv_proto_iconv" | tr -s ' ' | sed -e 's/( /(/'`
+    AC_MSG_RESULT([$]{ac_t:-
+         }[$]am_cv_proto_iconv)
+    AC_DEFINE_UNQUOTED(ICONV_CONST, $am_cv_proto_iconv_arg1,
+      [Define as const if the declaration of iconv() needs const.])
+  fi
+])
diff --git a/m4/lib-ld.m4 b/m4/lib-ld.m4
new file mode 100644 (file)
index 0000000..96c4e2c
--- /dev/null
@@ -0,0 +1,110 @@
+# lib-ld.m4 serial 3 (gettext-0.13)
+dnl Copyright (C) 1996-2003 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl Subroutines of libtool.m4,
+dnl with replacements s/AC_/AC_LIB/ and s/lt_cv/acl_cv/ to avoid collision
+dnl with libtool.m4.
+
+dnl From libtool-1.4. Sets the variable with_gnu_ld to yes or no.
+AC_DEFUN([AC_LIB_PROG_LD_GNU],
+[AC_CACHE_CHECK([if the linker ($LD) is GNU ld], acl_cv_prog_gnu_ld,
+[# I'd rather use --version here, but apparently some GNU ld's only accept -v.
+case `$LD -v 2>&1 </dev/null` in
+*GNU* | *'with BFD'*)
+  acl_cv_prog_gnu_ld=yes ;;
+*)
+  acl_cv_prog_gnu_ld=no ;;
+esac])
+with_gnu_ld=$acl_cv_prog_gnu_ld
+])
+
+dnl From libtool-1.4. Sets the variable LD.
+AC_DEFUN([AC_LIB_PROG_LD],
+[AC_ARG_WITH(gnu-ld,
+[  --with-gnu-ld           assume the C compiler uses GNU ld [default=no]],
+test "$withval" = no || with_gnu_ld=yes, with_gnu_ld=no)
+AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([AC_CANONICAL_HOST])dnl
+# Prepare PATH_SEPARATOR.
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+  echo "#! /bin/sh" >conf$$.sh
+  echo  "exit 0"   >>conf$$.sh
+  chmod +x conf$$.sh
+  if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then
+    PATH_SEPARATOR=';'
+  else
+    PATH_SEPARATOR=:
+  fi
+  rm -f conf$$.sh
+fi
+ac_prog=ld
+if test "$GCC" = yes; then
+  # Check if gcc -print-prog-name=ld gives a path.
+  AC_MSG_CHECKING([for ld used by GCC])
+  case $host in
+  *-*-mingw*)
+    # gcc leaves a trailing carriage return which upsets mingw
+    ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
+  *)
+    ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
+  esac
+  case $ac_prog in
+    # Accept absolute paths.
+    [[\\/]* | [A-Za-z]:[\\/]*)]
+      [re_direlt='/[^/][^/]*/\.\./']
+      # Canonicalize the path of ld
+      ac_prog=`echo $ac_prog| sed 's%\\\\%/%g'`
+      while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do
+       ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"`
+      done
+      test -z "$LD" && LD="$ac_prog"
+      ;;
+  "")
+    # If it fails, then pretend we aren't using GCC.
+    ac_prog=ld
+    ;;
+  *)
+    # If it is relative, then search for the first ld in PATH.
+    with_gnu_ld=unknown
+    ;;
+  esac
+elif test "$with_gnu_ld" = yes; then
+  AC_MSG_CHECKING([for GNU ld])
+else
+  AC_MSG_CHECKING([for non-GNU ld])
+fi
+AC_CACHE_VAL(acl_cv_path_LD,
+[if test -z "$LD"; then
+  IFS="${IFS=  }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR-:}"
+  for ac_dir in $PATH; do
+    test -z "$ac_dir" && ac_dir=.
+    if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
+      acl_cv_path_LD="$ac_dir/$ac_prog"
+      # Check to see if the program is GNU ld.  I'd rather use --version,
+      # but apparently some GNU ld's only accept -v.
+      # Break only if it was the GNU/non-GNU ld that we prefer.
+      case `"$acl_cv_path_LD" -v 2>&1 < /dev/null` in
+      *GNU* | *'with BFD'*)
+       test "$with_gnu_ld" != no && break ;;
+      *)
+       test "$with_gnu_ld" != yes && break ;;
+      esac
+    fi
+  done
+  IFS="$ac_save_ifs"
+else
+  acl_cv_path_LD="$LD" # Let the user override the test with a path.
+fi])
+LD="$acl_cv_path_LD"
+if test -n "$LD"; then
+  AC_MSG_RESULT($LD)
+else
+  AC_MSG_RESULT(no)
+fi
+test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH])
+AC_LIB_PROG_LD_GNU
+])
diff --git a/m4/lib-link.m4 b/m4/lib-link.m4
new file mode 100644 (file)
index 0000000..e3d26fc
--- /dev/null
@@ -0,0 +1,709 @@
+# lib-link.m4 serial 13 (gettext-0.17)
+dnl Copyright (C) 2001-2007 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl From Bruno Haible.
+
+AC_PREREQ(2.54)
+
+dnl AC_LIB_LINKFLAGS(name [, dependencies]) searches for libname and
+dnl the libraries corresponding to explicit and implicit dependencies.
+dnl Sets and AC_SUBSTs the LIB${NAME} and LTLIB${NAME} variables and
+dnl augments the CPPFLAGS variable.
+dnl Sets and AC_SUBSTs the LIB${NAME}_PREFIX variable to nonempty if libname
+dnl was found in ${LIB${NAME}_PREFIX}/$acl_libdirstem.
+AC_DEFUN([AC_LIB_LINKFLAGS],
+[
+  AC_REQUIRE([AC_LIB_PREPARE_PREFIX])
+  AC_REQUIRE([AC_LIB_RPATH])
+  define([Name],[translit([$1],[./-], [___])])
+  define([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-],
+                               [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])])
+  AC_CACHE_CHECK([how to link with lib[]$1], [ac_cv_lib[]Name[]_libs], [
+    AC_LIB_LINKFLAGS_BODY([$1], [$2])
+    ac_cv_lib[]Name[]_libs="$LIB[]NAME"
+    ac_cv_lib[]Name[]_ltlibs="$LTLIB[]NAME"
+    ac_cv_lib[]Name[]_cppflags="$INC[]NAME"
+    ac_cv_lib[]Name[]_prefix="$LIB[]NAME[]_PREFIX"
+  ])
+  LIB[]NAME="$ac_cv_lib[]Name[]_libs"
+  LTLIB[]NAME="$ac_cv_lib[]Name[]_ltlibs"
+  INC[]NAME="$ac_cv_lib[]Name[]_cppflags"
+  LIB[]NAME[]_PREFIX="$ac_cv_lib[]Name[]_prefix"
+  AC_LIB_APPENDTOVAR([CPPFLAGS], [$INC]NAME)
+  AC_SUBST([LIB]NAME)
+  AC_SUBST([LTLIB]NAME)
+  AC_SUBST([LIB]NAME[_PREFIX])
+  dnl Also set HAVE_LIB[]NAME so that AC_LIB_HAVE_LINKFLAGS can reuse the
+  dnl results of this search when this library appears as a dependency.
+  HAVE_LIB[]NAME=yes
+  undefine([Name])
+  undefine([NAME])
+])
+
+dnl AC_LIB_HAVE_LINKFLAGS(name, dependencies, includes, testcode)
+dnl searches for libname and the libraries corresponding to explicit and
+dnl implicit dependencies, together with the specified include files and
+dnl the ability to compile and link the specified testcode. If found, it
+dnl sets and AC_SUBSTs HAVE_LIB${NAME}=yes and the LIB${NAME} and
+dnl LTLIB${NAME} variables and augments the CPPFLAGS variable, and
+dnl #defines HAVE_LIB${NAME} to 1. Otherwise, it sets and AC_SUBSTs
+dnl HAVE_LIB${NAME}=no and LIB${NAME} and LTLIB${NAME} to empty.
+dnl Sets and AC_SUBSTs the LIB${NAME}_PREFIX variable to nonempty if libname
+dnl was found in ${LIB${NAME}_PREFIX}/$acl_libdirstem.
+AC_DEFUN([AC_LIB_HAVE_LINKFLAGS],
+[
+  AC_REQUIRE([AC_LIB_PREPARE_PREFIX])
+  AC_REQUIRE([AC_LIB_RPATH])
+  define([Name],[translit([$1],[./-], [___])])
+  define([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-],
+                               [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])])
+
+  dnl Search for lib[]Name and define LIB[]NAME, LTLIB[]NAME and INC[]NAME
+  dnl accordingly.
+  AC_LIB_LINKFLAGS_BODY([$1], [$2])
+
+  dnl Add $INC[]NAME to CPPFLAGS before performing the following checks,
+  dnl because if the user has installed lib[]Name and not disabled its use
+  dnl via --without-lib[]Name-prefix, he wants to use it.
+  ac_save_CPPFLAGS="$CPPFLAGS"
+  AC_LIB_APPENDTOVAR([CPPFLAGS], [$INC]NAME)
+
+  AC_CACHE_CHECK([for lib[]$1], [ac_cv_lib[]Name], [
+    ac_save_LIBS="$LIBS"
+    LIBS="$LIBS $LIB[]NAME"
+    AC_TRY_LINK([$3], [$4], [ac_cv_lib[]Name=yes], [ac_cv_lib[]Name=no])
+    LIBS="$ac_save_LIBS"
+  ])
+  if test "$ac_cv_lib[]Name" = yes; then
+    HAVE_LIB[]NAME=yes
+    AC_DEFINE([HAVE_LIB]NAME, 1, [Define if you have the $1 library.])
+    AC_MSG_CHECKING([how to link with lib[]$1])
+    AC_MSG_RESULT([$LIB[]NAME])
+  else
+    HAVE_LIB[]NAME=no
+    dnl If $LIB[]NAME didn't lead to a usable library, we don't need
+    dnl $INC[]NAME either.
+    CPPFLAGS="$ac_save_CPPFLAGS"
+    LIB[]NAME=
+    LTLIB[]NAME=
+    LIB[]NAME[]_PREFIX=
+  fi
+  AC_SUBST([HAVE_LIB]NAME)
+  AC_SUBST([LIB]NAME)
+  AC_SUBST([LTLIB]NAME)
+  AC_SUBST([LIB]NAME[_PREFIX])
+  undefine([Name])
+  undefine([NAME])
+])
+
+dnl Determine the platform dependent parameters needed to use rpath:
+dnl   acl_libext,
+dnl   acl_shlibext,
+dnl   acl_hardcode_libdir_flag_spec,
+dnl   acl_hardcode_libdir_separator,
+dnl   acl_hardcode_direct,
+dnl   acl_hardcode_minus_L.
+AC_DEFUN([AC_LIB_RPATH],
+[
+  dnl Tell automake >= 1.10 to complain if config.rpath is missing.
+  m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([config.rpath])])
+  AC_REQUIRE([AC_PROG_CC])                dnl we use $CC, $GCC, $LDFLAGS
+  AC_REQUIRE([AC_LIB_PROG_LD])            dnl we use $LD, $with_gnu_ld
+  AC_REQUIRE([AC_CANONICAL_HOST])         dnl we use $host
+  AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT]) dnl we use $ac_aux_dir
+  AC_CACHE_CHECK([for shared library run path origin], acl_cv_rpath, [
+    CC="$CC" GCC="$GCC" LDFLAGS="$LDFLAGS" LD="$LD" with_gnu_ld="$with_gnu_ld" \
+    ${CONFIG_SHELL-/bin/sh} "$ac_aux_dir/config.rpath" "$host" > conftest.sh
+    . ./conftest.sh
+    rm -f ./conftest.sh
+    acl_cv_rpath=done
+  ])
+  wl="$acl_cv_wl"
+  acl_libext="$acl_cv_libext"
+  acl_shlibext="$acl_cv_shlibext"
+  acl_libname_spec="$acl_cv_libname_spec"
+  acl_library_names_spec="$acl_cv_library_names_spec"
+  acl_hardcode_libdir_flag_spec="$acl_cv_hardcode_libdir_flag_spec"
+  acl_hardcode_libdir_separator="$acl_cv_hardcode_libdir_separator"
+  acl_hardcode_direct="$acl_cv_hardcode_direct"
+  acl_hardcode_minus_L="$acl_cv_hardcode_minus_L"
+  dnl Determine whether the user wants rpath handling at all.
+  AC_ARG_ENABLE(rpath,
+    [  --disable-rpath         do not hardcode runtime library paths],
+    :, enable_rpath=yes)
+])
+
+dnl AC_LIB_LINKFLAGS_BODY(name [, dependencies]) searches for libname and
+dnl the libraries corresponding to explicit and implicit dependencies.
+dnl Sets the LIB${NAME}, LTLIB${NAME} and INC${NAME} variables.
+dnl Also, sets the LIB${NAME}_PREFIX variable to nonempty if libname was found
+dnl in ${LIB${NAME}_PREFIX}/$acl_libdirstem.
+AC_DEFUN([AC_LIB_LINKFLAGS_BODY],
+[
+  AC_REQUIRE([AC_LIB_PREPARE_MULTILIB])
+  define([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-],
+                               [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])])
+  dnl Autoconf >= 2.61 supports dots in --with options.
+  define([N_A_M_E],[m4_if(m4_version_compare(m4_defn([m4_PACKAGE_VERSION]),[2.61]),[-1],[translit([$1],[.],[_])],[$1])])
+  dnl By default, look in $includedir and $libdir.
+  use_additional=yes
+  AC_LIB_WITH_FINAL_PREFIX([
+    eval additional_includedir=\"$includedir\"
+    eval additional_libdir=\"$libdir\"
+  ])
+  AC_LIB_ARG_WITH([lib]N_A_M_E[-prefix],
+[  --with-lib]N_A_M_E[-prefix[=DIR]  search for lib$1 in DIR/include and DIR/lib
+  --without-lib]N_A_M_E[-prefix     don't search for lib$1 in includedir and libdir],
+[
+    if test "X$withval" = "Xno"; then
+      use_additional=no
+    else
+      if test "X$withval" = "X"; then
+        AC_LIB_WITH_FINAL_PREFIX([
+          eval additional_includedir=\"$includedir\"
+          eval additional_libdir=\"$libdir\"
+        ])
+      else
+        additional_includedir="$withval/include"
+        additional_libdir="$withval/$acl_libdirstem"
+      fi
+    fi
+])
+  dnl Search the library and its dependencies in $additional_libdir and
+  dnl $LDFLAGS. Using breadth-first-seach.
+  LIB[]NAME=
+  LTLIB[]NAME=
+  INC[]NAME=
+  LIB[]NAME[]_PREFIX=
+  rpathdirs=
+  ltrpathdirs=
+  names_already_handled=
+  names_next_round='$1 $2'
+  while test -n "$names_next_round"; do
+    names_this_round="$names_next_round"
+    names_next_round=
+    for name in $names_this_round; do
+      already_handled=
+      for n in $names_already_handled; do
+        if test "$n" = "$name"; then
+          already_handled=yes
+          break
+        fi
+      done
+      if test -z "$already_handled"; then
+        names_already_handled="$names_already_handled $name"
+        dnl See if it was already located by an earlier AC_LIB_LINKFLAGS
+        dnl or AC_LIB_HAVE_LINKFLAGS call.
+        uppername=`echo "$name" | sed -e 'y|abcdefghijklmnopqrstuvwxyz./-|ABCDEFGHIJKLMNOPQRSTUVWXYZ___|'`
+        eval value=\"\$HAVE_LIB$uppername\"
+        if test -n "$value"; then
+          if test "$value" = yes; then
+            eval value=\"\$LIB$uppername\"
+            test -z "$value" || LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$value"
+            eval value=\"\$LTLIB$uppername\"
+            test -z "$value" || LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }$value"
+          else
+            dnl An earlier call to AC_LIB_HAVE_LINKFLAGS has determined
+            dnl that this library doesn't exist. So just drop it.
+            :
+          fi
+        else
+          dnl Search the library lib$name in $additional_libdir and $LDFLAGS
+          dnl and the already constructed $LIBNAME/$LTLIBNAME.
+          found_dir=
+          found_la=
+          found_so=
+          found_a=
+          eval libname=\"$acl_libname_spec\"    # typically: libname=lib$name
+          if test -n "$acl_shlibext"; then
+            shrext=".$acl_shlibext"             # typically: shrext=.so
+          else
+            shrext=
+          fi
+          if test $use_additional = yes; then
+            dir="$additional_libdir"
+            dnl The same code as in the loop below:
+            dnl First look for a shared library.
+            if test -n "$acl_shlibext"; then
+              if test -f "$dir/$libname$shrext"; then
+                found_dir="$dir"
+                found_so="$dir/$libname$shrext"
+              else
+                if test "$acl_library_names_spec" = '$libname$shrext$versuffix'; then
+                  ver=`(cd "$dir" && \
+                        for f in "$libname$shrext".*; do echo "$f"; done \
+                        | sed -e "s,^$libname$shrext\\\\.,," \
+                        | sort -t '.' -n -r -k1,1 -k2,2 -k3,3 -k4,4 -k5,5 \
+                        | sed 1q ) 2>/dev/null`
+                  if test -n "$ver" && test -f "$dir/$libname$shrext.$ver"; then
+                    found_dir="$dir"
+                    found_so="$dir/$libname$shrext.$ver"
+                  fi
+                else
+                  eval library_names=\"$acl_library_names_spec\"
+                  for f in $library_names; do
+                    if test -f "$dir/$f"; then
+                      found_dir="$dir"
+                      found_so="$dir/$f"
+                      break
+                    fi
+                  done
+                fi
+              fi
+            fi
+            dnl Then look for a static library.
+            if test "X$found_dir" = "X"; then
+              if test -f "$dir/$libname.$acl_libext"; then
+                found_dir="$dir"
+                found_a="$dir/$libname.$acl_libext"
+              fi
+            fi
+            if test "X$found_dir" != "X"; then
+              if test -f "$dir/$libname.la"; then
+                found_la="$dir/$libname.la"
+              fi
+            fi
+          fi
+          if test "X$found_dir" = "X"; then
+            for x in $LDFLAGS $LTLIB[]NAME; do
+              AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
+              case "$x" in
+                -L*)
+                  dir=`echo "X$x" | sed -e 's/^X-L//'`
+                  dnl First look for a shared library.
+                  if test -n "$acl_shlibext"; then
+                    if test -f "$dir/$libname$shrext"; then
+                      found_dir="$dir"
+                      found_so="$dir/$libname$shrext"
+                    else
+                      if test "$acl_library_names_spec" = '$libname$shrext$versuffix'; then
+                        ver=`(cd "$dir" && \
+                              for f in "$libname$shrext".*; do echo "$f"; done \
+                              | sed -e "s,^$libname$shrext\\\\.,," \
+                              | sort -t '.' -n -r -k1,1 -k2,2 -k3,3 -k4,4 -k5,5 \
+                              | sed 1q ) 2>/dev/null`
+                        if test -n "$ver" && test -f "$dir/$libname$shrext.$ver"; then
+                          found_dir="$dir"
+                          found_so="$dir/$libname$shrext.$ver"
+                        fi
+                      else
+                        eval library_names=\"$acl_library_names_spec\"
+                        for f in $library_names; do
+                          if test -f "$dir/$f"; then
+                            found_dir="$dir"
+                            found_so="$dir/$f"
+                            break
+                          fi
+                        done
+                      fi
+                    fi
+                  fi
+                  dnl Then look for a static library.
+                  if test "X$found_dir" = "X"; then
+                    if test -f "$dir/$libname.$acl_libext"; then
+                      found_dir="$dir"
+                      found_a="$dir/$libname.$acl_libext"
+                    fi
+                  fi
+                  if test "X$found_dir" != "X"; then
+                    if test -f "$dir/$libname.la"; then
+                      found_la="$dir/$libname.la"
+                    fi
+                  fi
+                  ;;
+              esac
+              if test "X$found_dir" != "X"; then
+                break
+              fi
+            done
+          fi
+          if test "X$found_dir" != "X"; then
+            dnl Found the library.
+            LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-L$found_dir -l$name"
+            if test "X$found_so" != "X"; then
+              dnl Linking with a shared library. We attempt to hardcode its
+              dnl directory into the executable's runpath, unless it's the
+              dnl standard /usr/lib.
+              if test "$enable_rpath" = no || test "X$found_dir" = "X/usr/$acl_libdirstem"; then
+                dnl No hardcoding is needed.
+                LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so"
+              else
+                dnl Use an explicit option to hardcode DIR into the resulting
+                dnl binary.
+                dnl Potentially add DIR to ltrpathdirs.
+                dnl The ltrpathdirs will be appended to $LTLIBNAME at the end.
+                haveit=
+                for x in $ltrpathdirs; do
+                  if test "X$x" = "X$found_dir"; then
+                    haveit=yes
+                    break
+                  fi
+                done
+                if test -z "$haveit"; then
+                  ltrpathdirs="$ltrpathdirs $found_dir"
+                fi
+                dnl The hardcoding into $LIBNAME is system dependent.
+                if test "$acl_hardcode_direct" = yes; then
+                  dnl Using DIR/libNAME.so during linking hardcodes DIR into the
+                  dnl resulting binary.
+                  LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so"
+                else
+                  if test -n "$acl_hardcode_libdir_flag_spec" && test "$acl_hardcode_minus_L" = no; then
+                    dnl Use an explicit option to hardcode DIR into the resulting
+                    dnl binary.
+                    LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so"
+                    dnl Potentially add DIR to rpathdirs.
+                    dnl The rpathdirs will be appended to $LIBNAME at the end.
+                    haveit=
+                    for x in $rpathdirs; do
+                      if test "X$x" = "X$found_dir"; then
+                        haveit=yes
+                        break
+                      fi
+                    done
+                    if test -z "$haveit"; then
+                      rpathdirs="$rpathdirs $found_dir"
+                    fi
+                  else
+                    dnl Rely on "-L$found_dir".
+                    dnl But don't add it if it's already contained in the LDFLAGS
+                    dnl or the already constructed $LIBNAME
+                    haveit=
+                    for x in $LDFLAGS $LIB[]NAME; do
+                      AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
+                      if test "X$x" = "X-L$found_dir"; then
+                        haveit=yes
+                        break
+                      fi
+                    done
+                    if test -z "$haveit"; then
+                      LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$found_dir"
+                    fi
+                    if test "$acl_hardcode_minus_L" != no; then
+                      dnl FIXME: Not sure whether we should use
+                      dnl "-L$found_dir -l$name" or "-L$found_dir $found_so"
+                      dnl here.
+                      LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so"
+                    else
+                      dnl We cannot use $acl_hardcode_runpath_var and LD_RUN_PATH
+                      dnl here, because this doesn't fit in flags passed to the
+                      dnl compiler. So give up. No hardcoding. This affects only
+                      dnl very old systems.
+                      dnl FIXME: Not sure whether we should use
+                      dnl "-L$found_dir -l$name" or "-L$found_dir $found_so"
+                      dnl here.
+                      LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-l$name"
+                    fi
+                  fi
+                fi
+              fi
+            else
+              if test "X$found_a" != "X"; then
+                dnl Linking with a static library.
+                LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_a"
+              else
+                dnl We shouldn't come here, but anyway it's good to have a
+                dnl fallback.
+                LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$found_dir -l$name"
+              fi
+            fi
+            dnl Assume the include files are nearby.
+            additional_includedir=
+            case "$found_dir" in
+              */$acl_libdirstem | */$acl_libdirstem/)
+                basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e "s,/$acl_libdirstem/"'*$,,'`
+                LIB[]NAME[]_PREFIX="$basedir"
+                additional_includedir="$basedir/include"
+                ;;
+            esac
+            if test "X$additional_includedir" != "X"; then
+              dnl Potentially add $additional_includedir to $INCNAME.
+              dnl But don't add it
+              dnl   1. if it's the standard /usr/include,
+              dnl   2. if it's /usr/local/include and we are using GCC on Linux,
+              dnl   3. if it's already present in $CPPFLAGS or the already
+              dnl      constructed $INCNAME,
+              dnl   4. if it doesn't exist as a directory.
+              if test "X$additional_includedir" != "X/usr/include"; then
+                haveit=
+                if test "X$additional_includedir" = "X/usr/local/include"; then
+                  if test -n "$GCC"; then
+                    case $host_os in
+                      linux* | gnu* | k*bsd*-gnu) haveit=yes;;
+                    esac
+                  fi
+                fi
+                if test -z "$haveit"; then
+                  for x in $CPPFLAGS $INC[]NAME; do
+                    AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
+                    if test "X$x" = "X-I$additional_includedir"; then
+                      haveit=yes
+                      break
+                    fi
+                  done
+                  if test -z "$haveit"; then
+                    if test -d "$additional_includedir"; then
+                      dnl Really add $additional_includedir to $INCNAME.
+                      INC[]NAME="${INC[]NAME}${INC[]NAME:+ }-I$additional_includedir"
+                    fi
+                  fi
+                fi
+              fi
+            fi
+            dnl Look for dependencies.
+            if test -n "$found_la"; then
+              dnl Read the .la file. It defines the variables
+              dnl dlname, library_names, old_library, dependency_libs, current,
+              dnl age, revision, installed, dlopen, dlpreopen, libdir.
+              save_libdir="$libdir"
+              case "$found_la" in
+                */* | *\\*) . "$found_la" ;;
+                *) . "./$found_la" ;;
+              esac
+              libdir="$save_libdir"
+              dnl We use only dependency_libs.
+              for dep in $dependency_libs; do
+                case "$dep" in
+                  -L*)
+                    additional_libdir=`echo "X$dep" | sed -e 's/^X-L//'`
+                    dnl Potentially add $additional_libdir to $LIBNAME and $LTLIBNAME.
+                    dnl But don't add it
+                    dnl   1. if it's the standard /usr/lib,
+                    dnl   2. if it's /usr/local/lib and we are using GCC on Linux,
+                    dnl   3. if it's already present in $LDFLAGS or the already
+                    dnl      constructed $LIBNAME,
+                    dnl   4. if it doesn't exist as a directory.
+                    if test "X$additional_libdir" != "X/usr/$acl_libdirstem"; then
+                      haveit=
+                      if test "X$additional_libdir" = "X/usr/local/$acl_libdirstem"; then
+                        if test -n "$GCC"; then
+                          case $host_os in
+                            linux* | gnu* | k*bsd*-gnu) haveit=yes;;
+                          esac
+                        fi
+                      fi
+                      if test -z "$haveit"; then
+                        haveit=
+                        for x in $LDFLAGS $LIB[]NAME; do
+                          AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
+                          if test "X$x" = "X-L$additional_libdir"; then
+                            haveit=yes
+                            break
+                          fi
+                        done
+                        if test -z "$haveit"; then
+                          if test -d "$additional_libdir"; then
+                            dnl Really add $additional_libdir to $LIBNAME.
+                            LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$additional_libdir"
+                          fi
+                        fi
+                        haveit=
+                        for x in $LDFLAGS $LTLIB[]NAME; do
+                          AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
+                          if test "X$x" = "X-L$additional_libdir"; then
+                            haveit=yes
+                            break
+                          fi
+                        done
+                        if test -z "$haveit"; then
+                          if test -d "$additional_libdir"; then
+                            dnl Really add $additional_libdir to $LTLIBNAME.
+                            LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-L$additional_libdir"
+                          fi
+                        fi
+                      fi
+                    fi
+                    ;;
+                  -R*)
+                    dir=`echo "X$dep" | sed -e 's/^X-R//'`
+                    if test "$enable_rpath" != no; then
+                      dnl Potentially add DIR to rpathdirs.
+                      dnl The rpathdirs will be appended to $LIBNAME at the end.
+                      haveit=
+                      for x in $rpathdirs; do
+                        if test "X$x" = "X$dir"; then
+                          haveit=yes
+                          break
+                        fi
+                      done
+                      if test -z "$haveit"; then
+                        rpathdirs="$rpathdirs $dir"
+                      fi
+                      dnl Potentially add DIR to ltrpathdirs.
+                      dnl The ltrpathdirs will be appended to $LTLIBNAME at the end.
+                      haveit=
+                      for x in $ltrpathdirs; do
+                        if test "X$x" = "X$dir"; then
+                          haveit=yes
+                          break
+                        fi
+                      done
+                      if test -z "$haveit"; then
+                        ltrpathdirs="$ltrpathdirs $dir"
+                      fi
+                    fi
+                    ;;
+                  -l*)
+                    dnl Handle this in the next round.
+                    names_next_round="$names_next_round "`echo "X$dep" | sed -e 's/^X-l//'`
+                    ;;
+                  *.la)
+                    dnl Handle this in the next round. Throw away the .la's
+                    dnl directory; it is already contained in a preceding -L
+                    dnl option.
+                    names_next_round="$names_next_round "`echo "X$dep" | sed -e 's,^X.*/,,' -e 's,^lib,,' -e 's,\.la$,,'`
+                    ;;
+                  *)
+                    dnl Most likely an immediate library name.
+                    LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$dep"
+                    LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }$dep"
+                    ;;
+                esac
+              done
+            fi
+          else
+            dnl Didn't find the library; assume it is in the system directories
+            dnl known to the linker and runtime loader. (All the system
+            dnl directories known to the linker should also be known to the
+            dnl runtime loader, otherwise the system is severely misconfigured.)
+            LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-l$name"
+            LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-l$name"
+          fi
+        fi
+      fi
+    done
+  done
+  if test "X$rpathdirs" != "X"; then
+    if test -n "$acl_hardcode_libdir_separator"; then
+      dnl Weird platform: only the last -rpath option counts, the user must
+      dnl pass all path elements in one option. We can arrange that for a
+      dnl single library, but not when more than one $LIBNAMEs are used.
+      alldirs=
+      for found_dir in $rpathdirs; do
+        alldirs="${alldirs}${alldirs:+$acl_hardcode_libdir_separator}$found_dir"
+      done
+      dnl Note: acl_hardcode_libdir_flag_spec uses $libdir and $wl.
+      acl_save_libdir="$libdir"
+      libdir="$alldirs"
+      eval flag=\"$acl_hardcode_libdir_flag_spec\"
+      libdir="$acl_save_libdir"
+      LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$flag"
+    else
+      dnl The -rpath options are cumulative.
+      for found_dir in $rpathdirs; do
+        acl_save_libdir="$libdir"
+        libdir="$found_dir"
+        eval flag=\"$acl_hardcode_libdir_flag_spec\"
+        libdir="$acl_save_libdir"
+        LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$flag"
+      done
+    fi
+  fi
+  if test "X$ltrpathdirs" != "X"; then
+    dnl When using libtool, the option that works for both libraries and
+    dnl executables is -R. The -R options are cumulative.
+    for found_dir in $ltrpathdirs; do
+      LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-R$found_dir"
+    done
+  fi
+])
+
+dnl AC_LIB_APPENDTOVAR(VAR, CONTENTS) appends the elements of CONTENTS to VAR,
+dnl unless already present in VAR.
+dnl Works only for CPPFLAGS, not for LIB* variables because that sometimes
+dnl contains two or three consecutive elements that belong together.
+AC_DEFUN([AC_LIB_APPENDTOVAR],
+[
+  for element in [$2]; do
+    haveit=
+    for x in $[$1]; do
+      AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
+      if test "X$x" = "X$element"; then
+        haveit=yes
+        break
+      fi
+    done
+    if test -z "$haveit"; then
+      [$1]="${[$1]}${[$1]:+ }$element"
+    fi
+  done
+])
+
+dnl For those cases where a variable contains several -L and -l options
+dnl referring to unknown libraries and directories, this macro determines the
+dnl necessary additional linker options for the runtime path.
+dnl AC_LIB_LINKFLAGS_FROM_LIBS([LDADDVAR], [LIBSVALUE], [USE-LIBTOOL])
+dnl sets LDADDVAR to linker options needed together with LIBSVALUE.
+dnl If USE-LIBTOOL evaluates to non-empty, linking with libtool is assumed,
+dnl otherwise linking without libtool is assumed.
+AC_DEFUN([AC_LIB_LINKFLAGS_FROM_LIBS],
+[
+  AC_REQUIRE([AC_LIB_RPATH])
+  AC_REQUIRE([AC_LIB_PREPARE_MULTILIB])
+  $1=
+  if test "$enable_rpath" != no; then
+    if test -n "$acl_hardcode_libdir_flag_spec" && test "$acl_hardcode_minus_L" = no; then
+      dnl Use an explicit option to hardcode directories into the resulting
+      dnl binary.
+      rpathdirs=
+      next=
+      for opt in $2; do
+        if test -n "$next"; then
+          dir="$next"
+          dnl No need to hardcode the standard /usr/lib.
+          if test "X$dir" != "X/usr/$acl_libdirstem"; then
+            rpathdirs="$rpathdirs $dir"
+          fi
+          next=
+        else
+          case $opt in
+            -L) next=yes ;;
+            -L*) dir=`echo "X$opt" | sed -e 's,^X-L,,'`
+                 dnl No need to hardcode the standard /usr/lib.
+                 if test "X$dir" != "X/usr/$acl_libdirstem"; then
+                   rpathdirs="$rpathdirs $dir"
+                 fi
+                 next= ;;
+            *) next= ;;
+          esac
+        fi
+      done
+      if test "X$rpathdirs" != "X"; then
+        if test -n ""$3""; then
+          dnl libtool is used for linking. Use -R options.
+          for dir in $rpathdirs; do
+            $1="${$1}${$1:+ }-R$dir"
+          done
+        else
+          dnl The linker is used for linking directly.
+          if test -n "$acl_hardcode_libdir_separator"; then
+            dnl Weird platform: only the last -rpath option counts, the user
+            dnl must pass all path elements in one option.
+            alldirs=
+            for dir in $rpathdirs; do
+              alldirs="${alldirs}${alldirs:+$acl_hardcode_libdir_separator}$dir"
+            done
+            acl_save_libdir="$libdir"
+            libdir="$alldirs"
+            eval flag=\"$acl_hardcode_libdir_flag_spec\"
+            libdir="$acl_save_libdir"
+            $1="$flag"
+          else
+            dnl The -rpath options are cumulative.
+            for dir in $rpathdirs; do
+              acl_save_libdir="$libdir"
+              libdir="$dir"
+              eval flag=\"$acl_hardcode_libdir_flag_spec\"
+              libdir="$acl_save_libdir"
+              $1="${$1}${$1:+ }$flag"
+            done
+          fi
+        fi
+      fi
+    fi
+  fi
+  AC_SUBST([$1])
+])
diff --git a/m4/lib-prefix.m4 b/m4/lib-prefix.m4
new file mode 100644 (file)
index 0000000..a8684e1
--- /dev/null
@@ -0,0 +1,185 @@
+# lib-prefix.m4 serial 5 (gettext-0.15)
+dnl Copyright (C) 2001-2005 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl From Bruno Haible.
+
+dnl AC_LIB_ARG_WITH is synonymous to AC_ARG_WITH in autoconf-2.13, and
+dnl similar to AC_ARG_WITH in autoconf 2.52...2.57 except that is doesn't
+dnl require excessive bracketing.
+ifdef([AC_HELP_STRING],
+[AC_DEFUN([AC_LIB_ARG_WITH], [AC_ARG_WITH([$1],[[$2]],[$3],[$4])])],
+[AC_DEFUN([AC_][LIB_ARG_WITH], [AC_ARG_WITH([$1],[$2],[$3],[$4])])])
+
+dnl AC_LIB_PREFIX adds to the CPPFLAGS and LDFLAGS the flags that are needed
+dnl to access previously installed libraries. The basic assumption is that
+dnl a user will want packages to use other packages he previously installed
+dnl with the same --prefix option.
+dnl This macro is not needed if only AC_LIB_LINKFLAGS is used to locate
+dnl libraries, but is otherwise very convenient.
+AC_DEFUN([AC_LIB_PREFIX],
+[
+  AC_BEFORE([$0], [AC_LIB_LINKFLAGS])
+  AC_REQUIRE([AC_PROG_CC])
+  AC_REQUIRE([AC_CANONICAL_HOST])
+  AC_REQUIRE([AC_LIB_PREPARE_MULTILIB])
+  AC_REQUIRE([AC_LIB_PREPARE_PREFIX])
+  dnl By default, look in $includedir and $libdir.
+  use_additional=yes
+  AC_LIB_WITH_FINAL_PREFIX([
+    eval additional_includedir=\"$includedir\"
+    eval additional_libdir=\"$libdir\"
+  ])
+  AC_LIB_ARG_WITH([lib-prefix],
+[  --with-lib-prefix[=DIR] search for libraries in DIR/include and DIR/lib
+  --without-lib-prefix    don't search for libraries in includedir and libdir],
+[
+    if test "X$withval" = "Xno"; then
+      use_additional=no
+    else
+      if test "X$withval" = "X"; then
+        AC_LIB_WITH_FINAL_PREFIX([
+          eval additional_includedir=\"$includedir\"
+          eval additional_libdir=\"$libdir\"
+        ])
+      else
+        additional_includedir="$withval/include"
+        additional_libdir="$withval/$acl_libdirstem"
+      fi
+    fi
+])
+  if test $use_additional = yes; then
+    dnl Potentially add $additional_includedir to $CPPFLAGS.
+    dnl But don't add it
+    dnl   1. if it's the standard /usr/include,
+    dnl   2. if it's already present in $CPPFLAGS,
+    dnl   3. if it's /usr/local/include and we are using GCC on Linux,
+    dnl   4. if it doesn't exist as a directory.
+    if test "X$additional_includedir" != "X/usr/include"; then
+      haveit=
+      for x in $CPPFLAGS; do
+        AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
+        if test "X$x" = "X-I$additional_includedir"; then
+          haveit=yes
+          break
+        fi
+      done
+      if test -z "$haveit"; then
+        if test "X$additional_includedir" = "X/usr/local/include"; then
+          if test -n "$GCC"; then
+            case $host_os in
+              linux* | gnu* | k*bsd*-gnu) haveit=yes;;
+            esac
+          fi
+        fi
+        if test -z "$haveit"; then
+          if test -d "$additional_includedir"; then
+            dnl Really add $additional_includedir to $CPPFLAGS.
+            CPPFLAGS="${CPPFLAGS}${CPPFLAGS:+ }-I$additional_includedir"
+          fi
+        fi
+      fi
+    fi
+    dnl Potentially add $additional_libdir to $LDFLAGS.
+    dnl But don't add it
+    dnl   1. if it's the standard /usr/lib,
+    dnl   2. if it's already present in $LDFLAGS,
+    dnl   3. if it's /usr/local/lib and we are using GCC on Linux,
+    dnl   4. if it doesn't exist as a directory.
+    if test "X$additional_libdir" != "X/usr/$acl_libdirstem"; then
+      haveit=
+      for x in $LDFLAGS; do
+        AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
+        if test "X$x" = "X-L$additional_libdir"; then
+          haveit=yes
+          break
+        fi
+      done
+      if test -z "$haveit"; then
+        if test "X$additional_libdir" = "X/usr/local/$acl_libdirstem"; then
+          if test -n "$GCC"; then
+            case $host_os in
+              linux*) haveit=yes;;
+            esac
+          fi
+        fi
+        if test -z "$haveit"; then
+          if test -d "$additional_libdir"; then
+            dnl Really add $additional_libdir to $LDFLAGS.
+            LDFLAGS="${LDFLAGS}${LDFLAGS:+ }-L$additional_libdir"
+          fi
+        fi
+      fi
+    fi
+  fi
+])
+
+dnl AC_LIB_PREPARE_PREFIX creates variables acl_final_prefix,
+dnl acl_final_exec_prefix, containing the values to which $prefix and
+dnl $exec_prefix will expand at the end of the configure script.
+AC_DEFUN([AC_LIB_PREPARE_PREFIX],
+[
+  dnl Unfortunately, prefix and exec_prefix get only finally determined
+  dnl at the end of configure.
+  if test "X$prefix" = "XNONE"; then
+    acl_final_prefix="$ac_default_prefix"
+  else
+    acl_final_prefix="$prefix"
+  fi
+  if test "X$exec_prefix" = "XNONE"; then
+    acl_final_exec_prefix='${prefix}'
+  else
+    acl_final_exec_prefix="$exec_prefix"
+  fi
+  acl_save_prefix="$prefix"
+  prefix="$acl_final_prefix"
+  eval acl_final_exec_prefix=\"$acl_final_exec_prefix\"
+  prefix="$acl_save_prefix"
+])
+
+dnl AC_LIB_WITH_FINAL_PREFIX([statement]) evaluates statement, with the
+dnl variables prefix and exec_prefix bound to the values they will have
+dnl at the end of the configure script.
+AC_DEFUN([AC_LIB_WITH_FINAL_PREFIX],
+[
+  acl_save_prefix="$prefix"
+  prefix="$acl_final_prefix"
+  acl_save_exec_prefix="$exec_prefix"
+  exec_prefix="$acl_final_exec_prefix"
+  $1
+  exec_prefix="$acl_save_exec_prefix"
+  prefix="$acl_save_prefix"
+])
+
+dnl AC_LIB_PREPARE_MULTILIB creates a variable acl_libdirstem, containing
+dnl the basename of the libdir, either "lib" or "lib64".
+AC_DEFUN([AC_LIB_PREPARE_MULTILIB],
+[
+  dnl There is no formal standard regarding lib and lib64. The current
+  dnl practice is that on a system supporting 32-bit and 64-bit instruction
+  dnl sets or ABIs, 64-bit libraries go under $prefix/lib64 and 32-bit
+  dnl libraries go under $prefix/lib. We determine the compiler's default
+  dnl mode by looking at the compiler's library search path. If at least
+  dnl of its elements ends in /lib64 or points to a directory whose absolute
+  dnl pathname ends in /lib64, we assume a 64-bit ABI. Otherwise we use the
+  dnl default, namely "lib".
+  acl_libdirstem=lib
+  searchpath=`(LC_ALL=C $CC -print-search-dirs) 2>/dev/null | sed -n -e 's,^libraries: ,,p' | sed -e 's,^=,,'`
+  if test -n "$searchpath"; then
+    acl_save_IFS="${IFS=       }"; IFS=":"
+    for searchdir in $searchpath; do
+      if test -d "$searchdir"; then
+        case "$searchdir" in
+          */lib64/ | */lib64 ) acl_libdirstem=lib64 ;;
+          *) searchdir=`cd "$searchdir" && pwd`
+             case "$searchdir" in
+               */lib64 ) acl_libdirstem=lib64 ;;
+             esac ;;
+        esac
+      fi
+    done
+    IFS="$acl_save_IFS"
+  fi
+])
diff --git a/m4/progtest.m4 b/m4/progtest.m4
new file mode 100644 (file)
index 0000000..a56365c
--- /dev/null
@@ -0,0 +1,92 @@
+# progtest.m4 serial 4 (gettext-0.14.2)
+dnl Copyright (C) 1996-2003, 2005 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+dnl
+dnl This file can can be used in projects which are not available under
+dnl the GNU General Public License or the GNU Library General Public
+dnl License but which still want to provide support for the GNU gettext
+dnl functionality.
+dnl Please note that the actual code of the GNU gettext library is covered
+dnl by the GNU Library General Public License, and the rest of the GNU
+dnl gettext package package is covered by the GNU General Public License.
+dnl They are *not* in the public domain.
+
+dnl Authors:
+dnl   Ulrich Drepper <drepper@cygnus.com>, 1996.
+
+AC_PREREQ(2.50)
+
+# Search path for a program which passes the given test.
+
+dnl AM_PATH_PROG_WITH_TEST(VARIABLE, PROG-TO-CHECK-FOR,
+dnl   TEST-PERFORMED-ON-FOUND_PROGRAM [, VALUE-IF-NOT-FOUND [, PATH]])
+AC_DEFUN([AM_PATH_PROG_WITH_TEST],
+[
+# Prepare PATH_SEPARATOR.
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+  echo "#! /bin/sh" >conf$$.sh
+  echo  "exit 0"   >>conf$$.sh
+  chmod +x conf$$.sh
+  if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then
+    PATH_SEPARATOR=';'
+  else
+    PATH_SEPARATOR=:
+  fi
+  rm -f conf$$.sh
+fi
+
+# Find out how to test for executable files. Don't use a zero-byte file,
+# as systems may use methods other than mode bits to determine executability.
+cat >conf$$.file <<_ASEOF
+#! /bin/sh
+exit 0
+_ASEOF
+chmod +x conf$$.file
+if test -x conf$$.file >/dev/null 2>&1; then
+  ac_executable_p="test -x"
+else
+  ac_executable_p="test -f"
+fi
+rm -f conf$$.file
+
+# Extract the first word of "$2", so it can be a program name with args.
+set dummy $2; ac_word=[$]2
+AC_MSG_CHECKING([for $ac_word])
+AC_CACHE_VAL(ac_cv_path_$1,
+[case "[$]$1" in
+  [[\\/]]* | ?:[[\\/]]*)
+    ac_cv_path_$1="[$]$1" # Let the user override the test with a path.
+    ;;
+  *)
+    ac_save_IFS="$IFS"; IFS=$PATH_SEPARATOR
+    for ac_dir in ifelse([$5], , $PATH, [$5]); do
+      IFS="$ac_save_IFS"
+      test -z "$ac_dir" && ac_dir=.
+      for ac_exec_ext in '' $ac_executable_extensions; do
+        if $ac_executable_p "$ac_dir/$ac_word$ac_exec_ext"; then
+          echo "$as_me: trying $ac_dir/$ac_word..." >&AS_MESSAGE_LOG_FD
+          if [$3]; then
+            ac_cv_path_$1="$ac_dir/$ac_word$ac_exec_ext"
+            break 2
+          fi
+        fi
+      done
+    done
+    IFS="$ac_save_IFS"
+dnl If no 4th arg is given, leave the cache variable unset,
+dnl so AC_PATH_PROGS will keep looking.
+ifelse([$4], , , [  test -z "[$]ac_cv_path_$1" && ac_cv_path_$1="$4"
+])dnl
+    ;;
+esac])dnl
+$1="$ac_cv_path_$1"
+if test ifelse([$4], , [-n "[$]$1"], ["[$]$1" != "$4"]); then
+  AC_MSG_RESULT([$]$1)
+else
+  AC_MSG_RESULT(no)
+fi
+AC_SUBST($1)dnl
+])
diff --git a/org.enlightenment.Ethumb.service.in b/org.enlightenment.Ethumb.service.in
new file mode 100644 (file)
index 0000000..ece2e03
--- /dev/null
@@ -0,0 +1,3 @@
+[D-BUS Service]
+Name=org.enlightenment.Ethumb
+Exec=@prefix@/bin/ethumbd
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644 (file)
index 0000000..31c7f28
--- /dev/null
@@ -0,0 +1,3 @@
+MAINTAINERCLEANFILES = Makefile.in
+
+SUBDIRS = lib bin plugins tests
diff --git a/src/bin/Makefile.am b/src/bin/Makefile.am
new file mode 100644 (file)
index 0000000..c733455
--- /dev/null
@@ -0,0 +1,38 @@
+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@
+
+bin_PROGRAMS = ethumb
+noinst_HEADERS =
+
+ethumb_SOURCES = ethumb.c
+ethumb_LDADD = \
+       @EINA_LIBS@ @ECORE_LIBS@ \
+       $(top_builddir)/src/lib/libethumb.la
+ethumb_DEPENDENCIES = $(top_builddir)/config.h
+
+
+
+if USE_MODULE_ETHUMBD
+
+AM_CPPFLAGS += @EDBUS_CFLAGS@
+bin_PROGRAMS += ethumbd ethumbd_client
+noinst_HEADERS += ethumbd_private.h
+
+ethumbd_SOURCES = ethumbd.c ethumbd_child.c
+ethumbd_LDADD = \
+       @EINA_LIBS@ @ECORE_LIBS@ @EDBUS_LIBS@ \
+       $(top_builddir)/src/lib/libethumb.la
+ethumbd_DEPENDENCIES = $(top_builddir)/config.h
+
+ethumbd_client_SOURCES = ethumbd_client.c
+ethumbd_client_LDADD = \
+       @EINA_LIBS@ @ECORE_LIBS@ \
+       $(top_builddir)/src/lib/client/libethumb_client.la
+ethumbd_client_DEPENDENCIES = $(top_builddir)/config.h
+
+endif
diff --git a/src/bin/ethumb.c b/src/bin/ethumb.c
new file mode 100644 (file)
index 0000000..0e31942
--- /dev/null
@@ -0,0 +1,279 @@
+/**
+ * @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 <antognolli@profusion.mobi>
+ * @author Gustavo Sverzut Barbieri <barbieri@profusion.mobi>
+ */
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <Ethumb.h>
+#include <Eina.h>
+#include <Ecore_Getopt.h>
+#include <Ecore.h>
+
+const char *aspect_opt[] = { "keep", "ignore", "crop", NULL };
+const char *format_opt[] = { "png", "jpg", "eet", NULL };
+struct frame
+{
+   const char *file;
+   const char *group;
+   const char *swallow;
+};
+
+static unsigned char
+_ethumb_getopt_callback_frame_parse(const Ecore_Getopt *parser __UNUSED__, const Ecore_Getopt_Desc *desc __UNUSED__, const char *str, void *data __UNUSED__, Ecore_Getopt_Value *storage)
+{
+   struct frame *f = (struct frame *)storage->ptrp;
+   const char *tfile, *tgroup, *tswallow, *base, *sep;
+
+   base = str;
+   sep = strchr(base, ':');
+   if (!sep)
+       goto error;
+   tfile = eina_stringshare_add_length(base, sep - base);
+   base = sep + 1;
+
+   sep = strchr(base, ':');
+   if (!sep)
+     {
+       eina_stringshare_del(tfile);
+       goto error;
+     }
+   tgroup = eina_stringshare_add_length(base, sep - base);
+   base = sep + 1;
+   if (base[0] == '\0')
+     {
+       eina_stringshare_del(tfile);
+       eina_stringshare_del(tgroup);
+       goto error;
+     }
+   tswallow = eina_stringshare_add(base);
+
+   f->file = tfile;
+   f->group = tgroup;
+   f->swallow = tswallow;
+   return 1;
+
+ error:
+   fprintf(stderr,
+          "ERROR: invalid theme, not in format "
+          "'file:group:swallow_part': '%s'\n",
+          str);
+   return 0;
+}
+
+const Ecore_Getopt optdesc = {
+  "ethumb",
+  NULL,
+  PACKAGE_VERSION,
+  "(C) 2009 - ProFUSION embedded systems",
+  "LGPL v3 - GNU Lesser General Public License",
+  "Thumbnails generator.\n"
+     "\n"
+     "This program uses ethumb to create thumbnails from pictures. "
+     "It's an example of use and a test for ethumb.\n",
+  0,
+  {
+     ECORE_GETOPT_CALLBACK_ARGS
+     ('s', "size", "thumbnail size expected.",
+      "WxH", ecore_getopt_callback_size_parse, NULL),
+     ECORE_GETOPT_CHOICE
+     ('f', "format", "file format to save.", format_opt),
+     ECORE_GETOPT_CHOICE
+     ('a', "aspect", "original image aspect ratio.", aspect_opt),
+     ECORE_GETOPT_STORE_STR
+     ('d', "directory", "directory to save thumbnails."),
+     ECORE_GETOPT_STORE_STR
+     ('c', "category", "thumbnails category."),
+     ECORE_GETOPT_CALLBACK_ARGS
+     ('t', "theme", "path to theme file, group and swallow part.",
+      "file:group:swallow_part", _ethumb_getopt_callback_frame_parse, NULL),
+     ECORE_GETOPT_STORE_STR
+     ('k', "key", "key inside eet file to read image from."),
+     ECORE_GETOPT_STORE_DOUBLE
+     ('v', "video_time", "time of video frame to use as thumbnail."),
+     ECORE_GETOPT_STORE_INT
+     ('p', "document_page", "document page to use as thumbnail."),
+     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
+_thumb_report(const char *mode, Ethumb *e)
+{
+   const char *ap, *ak, *gp, *gk;
+   ethumb_file_get(e, &ap, &ak);
+   ethumb_thumb_path_get(e, &gp, &gk);
+   printf("%s '%s' '%s' => '%s' '%s'\n",
+         mode, ap, ak ? ak : "", gp, gk ? gk : "");
+}
+
+static void
+_finished_thumb( void *data __UNUSED__, Ethumb *e, Eina_Bool success)
+{
+   const char *mode = success ? "GENERATED" : "FAILED";
+   _thumb_report(mode, e);
+   ecore_main_loop_quit();
+}
+
+int
+main(int argc, char *argv[])
+{
+   Ethumb *e;
+   Eina_Bool quit_option = 0;
+   Eina_Rectangle geometry = {-1, -1, -1, -1};
+   unsigned int format = 0, aspect = 0;
+   char *format_str = NULL;
+   char *aspect_str = NULL;
+   char *directory = NULL;
+   char *category = NULL;
+   char *src_key = NULL;
+   struct frame frame = {NULL, NULL, NULL};
+   const char *thumb_path = NULL;
+   const char *thumb_key = NULL;
+   double video_time = 0;
+   int page = 0;
+   int arg_index;
+   int i;
+
+   int r = 1;
+
+   ethumb_init();
+   ecore_init();
+
+   Ecore_Getopt_Value values[] = {
+       ECORE_GETOPT_VALUE_PTR_CAST(geometry),
+       ECORE_GETOPT_VALUE_PTR_CAST(format_str),
+       ECORE_GETOPT_VALUE_PTR_CAST(aspect_str),
+       ECORE_GETOPT_VALUE_STR(directory),
+       ECORE_GETOPT_VALUE_STR(category),
+       ECORE_GETOPT_VALUE_PTR_CAST(frame),
+       ECORE_GETOPT_VALUE_STR(src_key),
+       ECORE_GETOPT_VALUE_DOUBLE(video_time),
+       ECORE_GETOPT_VALUE_INT(page),
+       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)
+     {
+       fprintf(stderr, "Could not parse arguments.\n");
+       if (frame.file)
+         {
+            eina_stringshare_del(frame.file);
+            eina_stringshare_del(frame.group);
+            eina_stringshare_del(frame.swallow);
+         }
+       ecore_shutdown();
+       ethumb_shutdown();
+       return -1;
+     }
+
+   if (quit_option)
+     {
+       if (frame.file)
+         {
+            eina_stringshare_del(frame.file);
+            eina_stringshare_del(frame.group);
+            eina_stringshare_del(frame.swallow);
+         }
+       ecore_shutdown();
+       ethumb_shutdown();
+       return 0;
+     }
+
+   for (i = 0; i < 3; i++)
+     if (format_opt[i] == format_str)
+       {
+         format = i;
+         break;
+       }
+
+   for (i = 0; i < 3; i++)
+     if (aspect_opt[i] == aspect_str)
+       {
+         aspect = i;
+         break;
+       }
+
+   e = ethumb_new();
+
+   ethumb_thumb_format_set(e, format);
+   ethumb_thumb_aspect_set(e, aspect);
+   if (directory) ethumb_thumb_dir_path_set(e, directory);
+   if (category) ethumb_thumb_category_set(e, category);
+   if (geometry.w > 0 && geometry.h > 0)
+     ethumb_thumb_size_set(e, geometry.w, geometry.h);
+   if (frame.file)
+     {
+       ethumb_frame_set(e, frame.file, frame.group, frame.swallow);
+       eina_stringshare_del(frame.file);
+       eina_stringshare_del(frame.group);
+       eina_stringshare_del(frame.swallow);
+     }
+   if (video_time > 0)
+     ethumb_video_time_set(e, video_time);
+   if (page > 0)
+     ethumb_document_page_set(e, page);
+
+   if (r && arg_index < argc)
+     r = ethumb_file_set(e, argv[arg_index++], src_key);
+   else
+     r = 0;
+   if (r && arg_index < argc)
+     thumb_path = argv[arg_index++];
+   if (r && arg_index < argc)
+     thumb_key = argv[arg_index];
+
+   if (r)
+     {
+       ethumb_thumb_path_set(e, thumb_path, thumb_key);
+       if (ethumb_exists(e))
+         {
+            _thumb_report("EXISTS", e);
+            quit_option = 1;
+            r = 1;
+         }
+       else
+         r = ethumb_generate(e, _finished_thumb, NULL, NULL);
+     }
+
+   if (r && !quit_option)
+     ecore_main_loop_begin();
+
+   ethumb_file_free(e);
+   ethumb_free(e);
+
+   ecore_shutdown();
+   ethumb_shutdown();
+
+   return !r;
+}
diff --git a/src/bin/ethumbd.c b/src/bin/ethumbd.c
new file mode 100644 (file)
index 0000000..0cce3ec
--- /dev/null
@@ -0,0 +1,1836 @@
+/**
+ * @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 <antognolli@profusion.mobi>
+ */
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <Ethumb.h>
+#include <Eina.h>
+#include <Ecore_Getopt.h>
+#include <Ecore.h>
+#include <E_DBus.h>
+
+#include "ethumbd_private.h"
+
+#ifndef PATH_MAX
+#define PATH_MAX 4096
+#endif
+
+#define MAX_ID 2000000
+
+#define DBG(...) EINA_LOG_DBG(__VA_ARGS__)
+#define INF(...) EINA_LOG_INFO(__VA_ARGS__)
+#define WRN(...) EINA_LOG_WARN(__VA_ARGS__)
+#define ERR(...) EINA_LOG_ERR(__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
+   {
+      Eina_Bool fdo : 1;
+      Eina_Bool size : 1;
+      Eina_Bool format : 1;
+      Eina_Bool aspect : 1;
+      Eina_Bool crop : 1;
+      Eina_Bool quality : 1;
+      Eina_Bool compress : 1;
+      Eina_Bool directory : 1;
+      Eina_Bool category : 1;
+      Eina_Bool frame : 1;
+      Eina_Bool video_time : 1;
+      Eina_Bool video_start : 1;
+      Eina_Bool video_interval : 1;
+      Eina_Bool video_ntimes : 1;
+      Eina_Bool video_fps : 1;
+      Eina_Bool document_page : 1;
+   } flags;
+   int fdo;
+   int tw, th;
+   int format;
+   int aspect;
+   float cx, cy;
+   int quality;
+   int compress;
+   const char *directory;
+   const char *category;
+   const char *theme_file;
+   const char *group;
+   const char *swallow;
+   float video_time;
+   float video_start;
+   float video_interval;
+   int video_ntimes;
+   int video_fps;
+   int document_page;
+};
+
+struct _Ethumb_Request
+{
+   int 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;
+   int id_count;
+   int max_id;
+   int 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 <timeout> 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, int *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, int 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, int 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_QUALITY:
+      case ETHUMBD_COMPRESS:
+      case ETHUMBD_SIZE_W:
+      case ETHUMBD_SIZE_H:
+      case ETHUMBD_DOCUMENT_PAGE:
+      case ETHUMBD_VIDEO_NTIMES:
+      case ETHUMBD_VIDEO_FPS:
+        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:
+      case ETHUMBD_VIDEO_START:
+      case ETHUMBD_VIDEO_INTERVAL:
+        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.quality)
+     _ethumbd_pipe_write_setup(fd, ETHUMBD_QUALITY, &setup->quality);
+   if (setup->flags.compress)
+     _ethumbd_pipe_write_setup(fd, ETHUMBD_COMPRESS, &setup->compress);
+   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.video_start)
+     _ethumbd_pipe_write_setup(fd, ETHUMBD_VIDEO_START, &setup->video_start);
+   if (setup->flags.video_interval)
+     _ethumbd_pipe_write_setup(fd, ETHUMBD_VIDEO_INTERVAL,
+                              &setup->video_interval);
+   if (setup->flags.video_ntimes)
+     _ethumbd_pipe_write_setup(fd, ETHUMBD_VIDEO_NTIMES, &setup->video_ntimes);
+   if (setup->flags.video_fps)
+     _ethumbd_pipe_write_setup(fd, ETHUMBD_VIDEO_FPS, &setup->video_fps);
+   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},
+    {NULL, NULL, NULL, NULL}
+  };
+
+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;
+   dbus_int32_t 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_INT32, &id);
+   return reply;
+}
+
+DBusMessage *
+_ethumb_dbus_queue_remove_cb(E_DBus_Object *object, DBusMessage *msg)
+{
+   DBusMessage *reply;
+   DBusMessageIter iter;
+   dbus_int32_t id;
+   struct _Ethumb_Object_Data *odata;
+   struct _Ethumb_Object *eobject;
+   struct _Ethumb_Request *request;
+   struct _Ethumbd *ed;
+   dbus_bool_t 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 __UNUSED__, DBusMessageIter *iter, struct _Ethumb_Request *request __UNUSED__)
+{
+   int type;
+   dbus_int32_t fdo;
+
+   type = dbus_message_iter_get_arg_type(iter);
+   if (type != DBUS_TYPE_INT32)
+     {
+       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 __UNUSED__, DBusMessageIter *iter, struct _Ethumb_Request *request)
+{
+   DBusMessageIter oiter;
+   int type;
+   dbus_int32_t 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 __UNUSED__, DBusMessageIter *iter, struct _Ethumb_Request *request)
+{
+   int type;
+   dbus_int32_t format;
+
+   type = dbus_message_iter_get_arg_type(iter);
+   if (type != DBUS_TYPE_INT32)
+     {
+       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 __UNUSED__, DBusMessageIter *iter, struct _Ethumb_Request *request)
+{
+   int type;
+   dbus_int32_t aspect;
+
+   type = dbus_message_iter_get_arg_type(iter);
+   if (type != DBUS_TYPE_INT32)
+     {
+       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 __UNUSED__, DBusMessageIter *iter, struct _Ethumb_Request *request)
+{
+   DBusMessageIter oiter;
+   int type;
+   double 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_quality_set(struct _Ethumb_Object *eobject __UNUSED__, DBusMessageIter *iter, struct _Ethumb_Request *request)
+{
+   int type;
+   dbus_int32_t quality;
+
+   type = dbus_message_iter_get_arg_type(iter);
+   if (type != DBUS_TYPE_INT32)
+     {
+       ERR("invalid param for quality_set.\n");
+       return 0;
+     }
+
+   dbus_message_iter_get_basic(iter, &quality);
+   DBG("setting quality to: %d\n", quality);
+   request->setup.flags.quality = 1;
+   request->setup.quality = quality;
+
+   return 1;
+}
+
+
+static int
+_ethumb_dbus_compress_set(struct _Ethumb_Object *eobject __UNUSED__, DBusMessageIter *iter, struct _Ethumb_Request *request)
+{
+   int type;
+   dbus_int32_t compress;
+
+   type = dbus_message_iter_get_arg_type(iter);
+   if (type != DBUS_TYPE_INT32)
+     {
+       ERR("invalid param for compress_set.\n");
+       return 0;
+     }
+
+   dbus_message_iter_get_basic(iter, &compress);
+   DBG("setting compress to: %d\n", compress);
+   request->setup.flags.compress = 1;
+   request->setup.compress = compress;
+
+   return 1;
+}
+
+static int
+_ethumb_dbus_frame_set(struct _Ethumb_Object *eobject __UNUSED__, 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 __UNUSED__, 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 __UNUSED__, 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 __UNUSED__, 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_video_start_set(struct _Ethumb_Object *eobject __UNUSED__, DBusMessageIter *iter, struct _Ethumb_Request *request)
+{
+   int type;
+   double video_start;
+
+   type = dbus_message_iter_get_arg_type(iter);
+   if (type != DBUS_TYPE_DOUBLE)
+     {
+       ERR("invalid param for video_start_set.\n");
+       return 0;
+     }
+
+   dbus_message_iter_get_basic(iter, &video_start);
+   DBG("setting video_start to: %3.2f\n", video_start);
+   request->setup.flags.video_start = 1;
+   request->setup.video_start = video_start;
+
+   return 1;
+}
+
+static int
+_ethumb_dbus_video_interval_set(struct _Ethumb_Object *eobject __UNUSED__, DBusMessageIter *iter, struct _Ethumb_Request *request)
+{
+   int type;
+   double video_interval;
+
+   type = dbus_message_iter_get_arg_type(iter);
+   if (type != DBUS_TYPE_DOUBLE)
+     {
+       ERR("invalid param for video_interval_set.\n");
+       return 0;
+     }
+
+   dbus_message_iter_get_basic(iter, &video_interval);
+   DBG("setting video_interval to: %3.2f\n", video_interval);
+   request->setup.flags.video_interval = 1;
+   request->setup.video_interval = video_interval;
+
+   return 1;
+}
+
+static int
+_ethumb_dbus_video_ntimes_set(struct _Ethumb_Object *eobject __UNUSED__, DBusMessageIter *iter, struct _Ethumb_Request *request)
+{
+   int type;
+   int video_ntimes;
+
+   type = dbus_message_iter_get_arg_type(iter);
+   if (type != DBUS_TYPE_INT32)
+     {
+       ERR("invalid param for video_ntimes_set.\n");
+       return 0;
+     }
+
+   dbus_message_iter_get_basic(iter, &video_ntimes);
+   DBG("setting video_ntimes to: %3.2d\n", video_ntimes);
+   request->setup.flags.video_ntimes = 1;
+   request->setup.video_ntimes = video_ntimes;
+
+   return 1;
+}
+
+static int
+_ethumb_dbus_video_fps_set(struct _Ethumb_Object *eobject __UNUSED__, DBusMessageIter *iter, struct _Ethumb_Request *request)
+{
+   int type;
+   int video_fps;
+
+   type = dbus_message_iter_get_arg_type(iter);
+   if (type != DBUS_TYPE_INT32)
+     {
+       ERR("invalid param for video_fps_set.\n");
+       return 0;
+     }
+
+   dbus_message_iter_get_basic(iter, &video_fps);
+   DBG("setting video_fps to: %3.2d\n", video_fps);
+   request->setup.flags.video_fps = 1;
+   request->setup.video_fps = video_fps;
+
+   return 1;
+}
+
+static int
+_ethumb_dbus_document_page_set(struct _Ethumb_Object *eobject __UNUSED__, DBusMessageIter *iter, struct _Ethumb_Request *request)
+{
+   int type;
+   dbus_int32_t document_page;
+
+   type = dbus_message_iter_get_arg_type(iter);
+   if (type != DBUS_TYPE_INT32)
+     {
+       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},
+  {"quality", _ethumb_dbus_quality_set},
+  {"compress", _ethumb_dbus_compress_set},
+  {"frame", _ethumb_dbus_frame_set},
+  {"directory", _ethumb_dbus_directory_set},
+  {"category", _ethumb_dbus_category_set},
+  {"video_time", _ethumb_dbus_video_time_set},
+  {"video_start", _ethumb_dbus_video_start_set},
+  {"video_interval", _ethumb_dbus_video_interval_set},
+  {"video_ntimes", _ethumb_dbus_video_ntimes_set},
+  {"video_fps", _ethumb_dbus_video_fps_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;
+   dbus_bool_t 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, int *id, const char *thumb_path, const char *thumb_key, Eina_Bool success)
+{
+   DBusMessage *signal;
+   int current;
+   const char *opath;
+   DBusMessageIter iter;
+   dbus_bool_t value;
+   dbus_int32_t id32;
+
+   value = success;
+   id32 = *id;
+
+   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_INT32, &id32);
+   _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", "iayayayay", "i", _ethumb_dbus_queue_add_cb},
+  {"queue_remove", "i", "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},
+  {NULL, NULL, NULL, NULL}
+};
+
+static struct _Ethumb_DBus_Signal_Table _ethumb_dbus_objects_signals[] = {
+  {"generated", "xayayb"},
+  {NULL, NULL}
+};
+
+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 __UNUSED__, 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;
+   int child;
+   double timeout = -1;
+
+   memset(&ed, 0, sizeof(ed));
+   ecore_init();
+   eina_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_init();
+   ecore_shutdown();
+   return exit_value;
+}
diff --git a/src/bin/ethumbd_child.c b/src/bin/ethumbd_child.c
new file mode 100644 (file)
index 0000000..4851605
--- /dev/null
@@ -0,0 +1,721 @@
+/**
+ * @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 <antognolli@profusion.mobi>
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <limits.h>
+#include <string.h>
+#include <errno.h>
+
+#include <Ecore.h>
+#include <Ethumb.h>
+#include <Eina.h>
+
+#include "ethumbd_private.h"
+
+#define DBG(...) EINA_LOG_DBG(__VA_ARGS__)
+#define INF(...) EINA_LOG_INFO(__VA_ARGS__)
+#define WRN(...) EINA_LOG_WARN(__VA_ARGS__)
+#define ERR(...) EINA_LOG_ERR(__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(void *data, Ethumb *e, Eina_Bool success)
+{
+   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, NULL);
+
+   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_quality_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_quality_set(e, value);
+   DBG("quality = %d\n", value);
+
+   return 1;
+}
+
+static int
+_ec_compress_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_compress_set(e, value);
+   DBG("compress = %d\n", value);
+
+   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_video_start_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_start_set(e, value);
+   DBG("video_start = %f\n", value);
+
+   return 1;
+}
+
+static int
+_ec_video_interval_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_interval_set(e, value);
+   DBG("video_interval = %f\n", value);
+
+   return 1;
+}
+
+static int
+_ec_video_ntimes_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_video_ntimes_set(e, value);
+   DBG("video_ntimes = %d\n", value);
+
+   return 1;
+}
+
+static int
+_ec_video_fps_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_video_fps_set(e, value);
+   DBG("video_fps = %d\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_QUALITY:
+        _ec_quality_set(ec, e);
+        break;
+      case ETHUMBD_COMPRESS:
+        _ec_compress_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_VIDEO_START:
+        _ec_video_start_set(ec, e);
+        break;
+      case ETHUMBD_VIDEO_INTERVAL:
+        _ec_video_interval_set(ec, e);
+        break;
+      case ETHUMBD_VIDEO_NTIMES:
+        _ec_video_ntimes_set(ec, e);
+        break;
+      case ETHUMBD_VIDEO_FPS:
+        _ec_video_fps_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/src/bin/ethumbd_client.c b/src/bin/ethumbd_client.c
new file mode 100644 (file)
index 0000000..685cb9b
--- /dev/null
@@ -0,0 +1,319 @@
+/**
+ * @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 <antognolli@profusion.mobi>
+ * @author Gustavo Sverzut Barbieri <barbieri@profusion.mobi>
+ */
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <Ethumb_Client.h>
+#include <Eina.h>
+#include <Ecore_Getopt.h>
+#include <Ecore.h>
+
+const char *aspect_opt[] = { "keep", "ignore", "crop", NULL };
+const char *format_opt[] = { "png", "jpg", "eet", NULL };
+struct frame
+{
+   const char *file;
+   const char *group;
+   const char *swallow;
+};
+
+struct options
+{
+   Eina_Rectangle geometry;
+   unsigned int format, aspect;
+   char *format_str;
+   char *aspect_str;
+   char *directory;
+   char *category;
+   struct frame frame;
+   char *src_path;
+   char *src_key;
+   const char *thumb_path;
+   const char *thumb_key;
+   double video_time;
+   int page;
+};
+
+static unsigned char
+_ethumb_getopt_callback_frame_parse(const Ecore_Getopt *parser __UNUSED__, const Ecore_Getopt_Desc *desc __UNUSED__, const char *str, void *data __UNUSED__, Ecore_Getopt_Value *storage)
+{
+   struct frame *f = (struct frame *)storage->ptrp;
+   const char *tfile, *tgroup, *tswallow, *base, *sep;
+
+   base = str;
+   sep = strchr(base, ':');
+   if (!sep)
+       goto error;
+   tfile = eina_stringshare_add_length(base, sep - base);
+   base = sep + 1;
+
+   sep = strchr(base, ':');
+   if (!sep)
+     {
+       eina_stringshare_del(tfile);
+       goto error;
+     }
+   tgroup = eina_stringshare_add_length(base, sep - base);
+   base = sep + 1;
+   if (base[0] == '\0')
+     {
+       eina_stringshare_del(tfile);
+       eina_stringshare_del(tgroup);
+       goto error;
+     }
+   tswallow = eina_stringshare_add(base);
+
+   f->file = tfile;
+   f->group = tgroup;
+   f->swallow = tswallow;
+   return 1;
+
+ error:
+   fprintf(stderr,
+          "ERROR: invalid theme, not in format "
+          "'file:group:swallow_part': '%s'\n",
+          str);
+   return 0;
+}
+
+const Ecore_Getopt optdesc = {
+  "ethumbd_client",
+  NULL,
+  PACKAGE_VERSION,
+  "(C) 2009 - ProFUSION embedded systems",
+  "LGPL v3 - GNU Lesser General Public License",
+  "Thumbnails generator client using DBus and ethumbd.\n"
+  "\n"
+  "This program uses ethumbd server to create thumbnails from pictures. "
+  "It's an example of use and a test for ethumbd.\n",
+  0,
+  {
+     ECORE_GETOPT_CALLBACK_ARGS
+     ('s', "size", "thumbnail size expected.",
+      "WxH", ecore_getopt_callback_size_parse, NULL),
+     ECORE_GETOPT_CHOICE
+     ('f', "format", "file format to save.", format_opt),
+     ECORE_GETOPT_CHOICE
+     ('a', "aspect", "original image aspect ratio.", aspect_opt),
+     ECORE_GETOPT_STORE_STR
+     ('d', "directory", "directory to save thumbnails."),
+     ECORE_GETOPT_STORE_STR
+     ('c', "category", "thumbnails category."),
+     ECORE_GETOPT_CALLBACK_ARGS
+     ('t', "theme", "path to theme file, group and swallow part.",
+      "file:group:swallow_part", _ethumb_getopt_callback_frame_parse, NULL),
+     ECORE_GETOPT_STORE_STR
+     ('k', "key", "key inside eet file to read image from."),
+     ECORE_GETOPT_STORE_DOUBLE
+     ('v', "video_time", "time of video frame to use as thumbnail."),
+     ECORE_GETOPT_STORE_INT
+     ('p', "document_page", "document page to use as thumbnail."),
+     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
+_thumb_report(const char *mode, const char *src_path, const char *src_key, const char *thumb_path, const char *thumb_key)
+{
+   printf("%s '%s' '%s' => '%s' '%s'\n",
+         mode,
+         src_path, src_key ? src_key : "",
+         thumb_path, thumb_key ? thumb_key : "");
+}
+
+static void
+_finished_thumb(void *data __UNUSED__, Ethumb_Client *client __UNUSED__, int id __UNUSED__, const char *src_path, const char *src_key, const char *thumb_path, const char *thumb_key, Eina_Bool success)
+{
+   const char *mode = success ? "GENERATED" : "FAILED";
+   _thumb_report(mode, src_path, src_key, thumb_path, thumb_key);
+   ecore_main_loop_quit();
+}
+
+static void
+_connected(void *data, Ethumb_Client *c, Eina_Bool success)
+{
+   struct options *opts = data;
+   const char *thumb_path, *thumb_key;
+   long id;
+
+   if (!success)
+     {
+       fputs("ERROR: could not connect to DBus server.\n", stderr);
+       ecore_main_loop_quit();
+       return;
+     }
+
+   fputs("connected to DBus server, setup parameters...\n", stdout);
+
+   ethumb_client_format_set(c, opts->format);
+   ethumb_client_aspect_set(c, opts->aspect);
+
+   if (opts->directory) ethumb_client_dir_path_set(c, opts->directory);
+   if (opts->category) ethumb_client_category_set(c, opts->category);
+   if (opts->geometry.w > 0 && opts->geometry.h > 0)
+     ethumb_client_size_set(c, opts->geometry.w, opts->geometry.h);
+   if (opts->frame.file)
+     ethumb_client_frame_set
+       (c, opts->frame.file, opts->frame.group, opts->frame.swallow);
+   if (opts->video_time > 0)
+     ethumb_client_video_time_set(c, opts->video_time);
+   if (opts->page > 0)
+     ethumb_client_document_page_set(c, opts->page);
+
+   if (!ethumb_client_file_set(c, opts->src_path, opts->src_key))
+     {
+       fprintf(stderr, "ERROR: could not set file '%s', key '%s'\n",
+               opts->src_path, opts->src_key ? opts->src_key : "");
+       ecore_main_loop_quit();
+       return;
+     }
+
+   ethumb_client_thumb_path_set(c, opts->thumb_path, opts->thumb_key);
+   ethumb_client_thumb_path_get(c, &thumb_path, &thumb_key);
+   if (ethumb_client_thumb_exists(c))
+     {
+       _thumb_report
+         ("EXISTS", opts->src_path, opts->src_key, thumb_path, thumb_key);
+       ecore_main_loop_quit();
+       return;
+     }
+
+   id = ethumb_client_generate(c, _finished_thumb, NULL, NULL);
+   if (id < 0)
+     {
+       fputs("ERROR: could not request thumbnail to be generated.\n", stderr);
+       ecore_main_loop_quit();
+       return;
+     }
+   printf("request id=%ld, file='%s', key='%s'\n",
+         id, opts->src_path, opts->src_key ? opts->src_key : "");
+}
+
+int
+main(int argc, char *argv[])
+{
+   Ethumb_Client *c;
+   Eina_Bool quit_option = 0;
+   const char *format_str, *aspect_str;
+   struct options opts = {
+     {-1, -1, -1, -1},
+     0, 0,
+     NULL, NULL, NULL, NULL,
+     {NULL, NULL, NULL},
+     NULL, NULL, NULL, NULL,
+     0.0,
+     0
+   };
+   int arg_index;
+   int i, ret = 0;
+
+   ethumb_client_init();
+   ecore_init();
+
+   Ecore_Getopt_Value values[] = {
+     ECORE_GETOPT_VALUE_PTR_CAST(opts.geometry),
+     ECORE_GETOPT_VALUE_PTR_CAST(format_str),
+     ECORE_GETOPT_VALUE_PTR_CAST(aspect_str),
+     ECORE_GETOPT_VALUE_STR(opts.directory),
+     ECORE_GETOPT_VALUE_STR(opts.category),
+     ECORE_GETOPT_VALUE_PTR_CAST(opts.frame),
+     ECORE_GETOPT_VALUE_STR(opts.src_key),
+     ECORE_GETOPT_VALUE_DOUBLE(opts.video_time),
+     ECORE_GETOPT_VALUE_INT(opts.page),
+     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) || (arg_index == argc))
+     {
+       if (arg_index < 0)
+         fprintf(stderr, "Could not parse arguments.\n");
+       else
+         fprintf(stderr, "Missing source file to thumbnail.\n");
+
+       ret = 1;
+       goto end;
+     }
+
+   if (quit_option)
+     {
+       ret = 0;
+       goto end;
+     }
+
+   for (i = 0; i < 3; i++)
+     if (format_opt[i] == format_str)
+       {
+         opts.format = i;
+         break;
+       }
+
+   for (i = 0; i < 3; i++)
+     if (aspect_opt[i] == aspect_str)
+       {
+         opts.aspect = i;
+         break;
+       }
+
+   opts.src_path = argv[arg_index++];
+   if (arg_index < argc)
+     {
+       opts.thumb_path = argv[arg_index++];
+       if (arg_index < argc)
+         opts.thumb_key = argv[arg_index];
+     }
+
+   c = ethumb_client_connect(_connected, &opts, NULL);
+   if (!c)
+     {
+       fputs("ERROR: could not connect to server.\n", stderr);
+       ret = 2;
+       goto end;
+     }
+
+   ecore_main_loop_begin();
+   ethumb_client_disconnect(c);
+
+ end:
+   if (opts.frame.file)
+     {
+       eina_stringshare_del(opts.frame.file);
+       eina_stringshare_del(opts.frame.group);
+       eina_stringshare_del(opts.frame.swallow);
+     }
+   ecore_shutdown();
+   ethumb_client_shutdown();
+
+   return ret;
+}
diff --git a/src/bin/ethumbd_private.h b/src/bin/ethumbd_private.h
new file mode 100644 (file)
index 0000000..c8ac4d0
--- /dev/null
@@ -0,0 +1,40 @@
+#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_QUALITY,
+   ETHUMBD_COMPRESS,
+   ETHUMBD_DIRECTORY,
+   ETHUMBD_CATEGORY,
+   ETHUMBD_FRAME_FILE,
+   ETHUMBD_FRAME_GROUP,
+   ETHUMBD_FRAME_SWALLOW,
+   ETHUMBD_VIDEO_TIME,
+   ETHUMBD_VIDEO_START,
+   ETHUMBD_VIDEO_INTERVAL,
+   ETHUMBD_VIDEO_NTIMES,
+   ETHUMBD_VIDEO_FPS,
+   ETHUMBD_DOCUMENT_PAGE,
+   ETHUMBD_SETUP_FINISHED
+};
+
+void ethumbd_child_start(int pipein, int pipeout);
+
+#endif
diff --git a/src/lib/Ethumb.c b/src/lib/Ethumb.c
new file mode 100644 (file)
index 0000000..00326b3
--- /dev/null
@@ -0,0 +1,1308 @@
+/**
+ * @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 <antognolli@profusion.mobi>
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <Eina.h>
+#include <eina_safety_checks.h>
+#include "Ethumb.h"
+#include "ethumb_private.h"
+#include "Ethumb_Plugin.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <dlfcn.h>
+#include "md5.h"
+
+#ifndef PATH_MAX
+#define PATH_MAX 4096
+#endif
+
+#include <Ecore.h>
+#include <Evas.h>
+#include <Ecore_Evas.h>
+#include <Ecore_File.h>
+#include <Edje.h>
+
+static int _log_dom = -1;
+#define DBG(...) EINA_LOG_DOM_DBG(_log_dom, __VA_ARGS__)
+#define INF(...) EINA_LOG_DOM_INFO(_log_dom, __VA_ARGS__)
+#define WRN(...) EINA_LOG_DOM_WARN(_log_dom, __VA_ARGS__)
+#define ERR(...) EINA_LOG_DOM_ERR(_log_dom, __VA_ARGS__)
+
+static int initcount = 0;
+static const char *_home_thumb_dir = NULL;
+static const char *_thumb_category_normal = NULL;
+static const char *_thumb_category_large = NULL;
+
+static const int THUMB_SIZE_NORMAL = 128;
+static const int THUMB_SIZE_LARGE = 256;
+
+static Eina_Hash *_plugins_ext = NULL;
+static Eina_Array *_plugins = NULL;
+
+static Eina_Bool
+_ethumb_plugin_list_cb(Eina_Module *m, void *data __UNUSED__)
+{
+   const char *file;
+   const char **ext;
+   Ethumb_Plugin *plugin;
+   Ethumb_Plugin *(*plugin_get)(void);
+
+   file = eina_module_file_get(m);
+   if (!eina_module_load(m))
+     {
+       ERR("could not load module \"%s\": %s\n",
+           file, eina_error_msg_get(eina_error_get()));
+       return EINA_FALSE;
+     }
+
+   plugin_get = eina_module_symbol_get(m, "ethumb_plugin_get");
+   if (!plugin_get)
+     {
+       ERR("could not find ethumb_plugin_get() in module \"%s\": %s\n",
+           file, eina_error_msg_get(eina_error_get()));
+       eina_module_unload(m);
+       return EINA_FALSE;
+     }
+
+   plugin = plugin_get();
+   if (!plugin)
+     {
+       ERR("plugin \"%s\" failed to init.\n", file);
+       eina_module_unload(m);
+       return EINA_FALSE;
+     }
+
+   DBG("loaded plugin \"%s\" (%p) with extensions:\n", file, plugin);
+   for (ext = plugin->extensions; *ext; ext++)
+     {
+       DBG("   extension \"%s\"\n", *ext);
+       eina_hash_add(_plugins_ext, *ext, plugin);
+     }
+
+   return EINA_TRUE;
+}
+
+static void
+_ethumb_plugins_load(void)
+{
+   _plugins_ext = eina_hash_string_small_new(NULL);
+   EINA_SAFETY_ON_NULL_RETURN(_plugins_ext);
+
+   _plugins = eina_module_list_get(_plugins, PLUGINSDIR, 1,
+                                  &_ethumb_plugin_list_cb, NULL);
+}
+
+static void
+_ethumb_plugins_unload(void)
+{
+   eina_hash_free(_plugins_ext);
+   _plugins_ext = NULL;
+   eina_module_list_unload(_plugins);
+   eina_module_list_flush(_plugins);
+   eina_array_free(_plugins);
+   _plugins = NULL;
+}
+
+EAPI int
+ethumb_init(void)
+{
+   const char *home;
+   char buf[PATH_MAX];
+
+   if (initcount)
+     return ++initcount;
+
+   if (!eina_init())
+     {
+       fprintf(stderr, "ERROR: Could not initialize eina.\n");
+       return 0;
+     }
+   _log_dom = eina_log_domain_register("ethumb", EINA_COLOR_GREEN);
+   if (_log_dom < 0)
+     {
+       EINA_LOG_ERR("Could not register log domain: ethumb");
+       eina_shutdown();
+       return 0;
+     }
+
+   evas_init();
+   ecore_init();
+   ecore_evas_init();
+   edje_init();
+
+   home = getenv("HOME");
+   snprintf(buf, sizeof(buf), "%s/.thumbnails", home);
+
+   _home_thumb_dir = eina_stringshare_add(buf);
+   _thumb_category_normal = eina_stringshare_add("normal");
+   _thumb_category_large = eina_stringshare_add("large");
+
+   _ethumb_plugins_load();
+   return ++initcount;
+}
+
+EAPI int
+ethumb_shutdown(void)
+{
+   initcount--;
+   if (initcount == 0)
+     {
+       _ethumb_plugins_unload();
+       eina_stringshare_del(_home_thumb_dir);
+       eina_stringshare_del(_thumb_category_normal);
+       eina_stringshare_del(_thumb_category_large);
+       evas_shutdown();
+       ecore_shutdown();
+       ecore_evas_shutdown();
+       edje_shutdown();
+       eina_log_domain_unregister(_log_dom);
+       _log_dom = -1;
+       eina_shutdown();
+     }
+
+   return initcount;
+}
+
+EAPI Ethumb *
+ethumb_new(void)
+{
+   Ethumb *ethumb;
+   Ecore_Evas *ee, *sub_ee;
+   Evas *e, *sub_e;
+   Evas_Object *o, *img;
+
+   ethumb = calloc(1, sizeof(Ethumb));
+   EINA_SAFETY_ON_NULL_RETURN_VAL(ethumb, NULL);
+
+   ethumb->tw = THUMB_SIZE_NORMAL;
+   ethumb->th = THUMB_SIZE_NORMAL;
+   ethumb->crop_x = 0.5;
+   ethumb->crop_y = 0.5;
+   ethumb->quality = 80;
+   ethumb->compress = 9;
+   ethumb->video.start = 0.1;
+   ethumb->video.time = 3;
+   ethumb->video.interval = 0.05;
+   ethumb->video.ntimes = 3;
+   ethumb->video.fps = 10;
+
+   ee = ecore_evas_buffer_new(1, 1);
+   e = ecore_evas_get(ee);
+   if (!e)
+     {
+       ERR("could not create ecore evas buffer\n");
+       return NULL;
+     }
+
+   evas_image_cache_set(e, 0);
+   evas_font_cache_set(e, 0);
+
+   o = ecore_evas_object_image_new(ee);
+   if (!o)
+     {
+       ERR("could not create sub ecore evas buffer\n");
+       ecore_evas_free(ee);
+       free(ethumb);
+       return NULL;
+     }
+
+   sub_ee = evas_object_data_get(o, "Ecore_Evas");
+   sub_e = ecore_evas_get(sub_ee);
+
+   evas_image_cache_set(sub_e, 0);
+   evas_font_cache_set(sub_e, 0);
+
+   img = evas_object_image_add(sub_e);
+   if (!img)
+     {
+       ERR("could not create source objects.\n");
+       ecore_evas_free(ee);
+       free(ethumb);
+       return NULL;
+     }
+
+   ethumb->ee = ee;
+   ethumb->e = e;
+   ethumb->sub_ee = sub_ee;
+   ethumb->sub_e = sub_e;
+   ethumb->o = o;
+   ethumb->img = img;
+
+   DBG("ethumb=%p\n", ethumb);
+
+   return ethumb;
+}
+
+static void
+_ethumb_frame_free(Ethumb_Frame *frame)
+{
+   Evas_Object *o;
+
+   if (!frame)
+     return;
+
+   if (frame->swallow && frame->edje)
+     {
+     o = edje_object_part_swallow_get(frame->edje, frame->swallow);
+     if (o)
+       edje_object_part_unswallow(frame->edje, o);
+     }
+   eina_stringshare_del(frame->file);
+   eina_stringshare_del(frame->group);
+   eina_stringshare_del(frame->swallow);
+
+   if (frame->edje)
+     evas_object_del(frame->edje);
+
+   free(frame);
+}
+
+EAPI void
+ethumb_free(Ethumb *ethumb)
+{
+   EINA_SAFETY_ON_NULL_RETURN(ethumb);
+
+   DBG("ethumb=%p", ethumb);
+
+   if (ethumb->frame)
+     _ethumb_frame_free(ethumb->frame);
+   ethumb_file_free(ethumb);
+   ecore_evas_free(ethumb->ee);
+   eina_stringshare_del(ethumb->thumb_dir);
+   eina_stringshare_del(ethumb->category);
+   if (ethumb->finished_idler)
+     ecore_idler_del(ethumb->finished_idler);
+   free(ethumb);
+}
+
+EAPI void
+ethumb_thumb_fdo_set(Ethumb *e, Ethumb_Thumb_FDO_Size s)
+{
+   EINA_SAFETY_ON_NULL_RETURN(e);
+   EINA_SAFETY_ON_FALSE_RETURN(s == ETHUMB_THUMB_NORMAL ||
+                              s == ETHUMB_THUMB_LARGE);
+   DBG("ethumb=%p, size=%d", e, s);
+
+   if (s == ETHUMB_THUMB_NORMAL)
+     {
+       e->tw = THUMB_SIZE_NORMAL;
+       e->th = THUMB_SIZE_NORMAL;
+     }
+   else
+     {
+       e->tw = THUMB_SIZE_LARGE;
+       e->th = THUMB_SIZE_LARGE;
+     }
+
+   e->format = ETHUMB_THUMB_FDO;
+   e->aspect = ETHUMB_THUMB_KEEP_ASPECT;
+   _ethumb_frame_free(e->frame);
+   e->frame = NULL;
+   eina_stringshare_del(e->thumb_dir);
+   eina_stringshare_del(e->category);
+   e->thumb_dir = NULL;
+   e->category = NULL;
+}
+
+EAPI void
+ethumb_thumb_size_set(Ethumb *e, int tw, int th)
+{
+   EINA_SAFETY_ON_NULL_RETURN(e);
+   EINA_SAFETY_ON_FALSE_RETURN(tw > 0);
+   EINA_SAFETY_ON_FALSE_RETURN(th > 0);
+
+   DBG("ethumb=%p, w=%d, h=%d", e, tw, th);
+   e->tw = tw;
+   e->th = th;
+}
+
+EAPI void
+ethumb_thumb_size_get(const Ethumb *e, int *tw, int *th)
+{
+   EINA_SAFETY_ON_NULL_RETURN(e);
+
+   if (tw) *tw = e->tw;
+   if (th) *th = e->th;
+}
+
+EAPI void
+ethumb_thumb_format_set(Ethumb *e, Ethumb_Thumb_Format f)
+{
+   EINA_SAFETY_ON_NULL_RETURN(e);
+   EINA_SAFETY_ON_FALSE_RETURN(f == ETHUMB_THUMB_FDO ||
+                              f == ETHUMB_THUMB_JPEG ||
+                              f == ETHUMB_THUMB_EET);
+
+   DBG("ethumb=%p, format=%d", e, f);
+   e->format = f;
+}
+
+EAPI Ethumb_Thumb_Format
+ethumb_thumb_format_get(const Ethumb *e)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(e, 0);
+   return e->format;
+}
+
+EAPI void
+ethumb_thumb_aspect_set(Ethumb *e, Ethumb_Thumb_Aspect a)
+{
+   EINA_SAFETY_ON_NULL_RETURN(e);
+   EINA_SAFETY_ON_FALSE_RETURN(a == ETHUMB_THUMB_KEEP_ASPECT ||
+                              a == ETHUMB_THUMB_IGNORE_ASPECT ||
+                              a == ETHUMB_THUMB_CROP);
+
+   DBG("ethumb=%p, aspect=%d", e, a);
+   e->aspect = a;
+}
+
+EAPI Ethumb_Thumb_Aspect
+ethumb_thumb_aspect_get(const Ethumb *e)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(e, 0);
+   return e->aspect;
+}
+
+EAPI void
+ethumb_thumb_crop_align_set(Ethumb *e, float x, float y)
+{
+   EINA_SAFETY_ON_NULL_RETURN(e);
+
+   DBG("ethumb=%p, x=%f, y=%f", e, x, y);
+   e->crop_x = x;
+   e->crop_y = y;
+}
+
+EAPI void
+ethumb_thumb_crop_align_get(const Ethumb *e, float *x, float *y)
+{
+   EINA_SAFETY_ON_NULL_RETURN(e);
+
+   if (x) *x = e->crop_x;
+   if (y) *y = e->crop_y;
+}
+
+EAPI void
+ethumb_thumb_quality_set(Ethumb *e, int quality)
+{
+   EINA_SAFETY_ON_NULL_RETURN(e);
+
+   DBG("ethumb=%p, quality=%d", e, quality);
+   e->quality = quality;
+}
+
+EAPI int
+ethumb_thumb_quality_get(const Ethumb *e)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(e, 0);
+   return e->quality;
+}
+
+EAPI void
+ethumb_thumb_compress_set(Ethumb *e, int compress)
+{
+   EINA_SAFETY_ON_NULL_RETURN(e);
+
+   DBG("ethumb=%p, compress=%d", e, compress);
+   e->compress = compress;
+}
+
+EAPI int
+ethumb_thumb_compress_get(const Ethumb *e)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(e, 0);
+   return e->compress;
+}
+
+EAPI Eina_Bool
+ethumb_frame_set(Ethumb *e, const char *theme_file, const char *group, const char *swallow)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(e, 0);
+
+   Ethumb_Frame *frame;
+   frame = e->frame;
+
+   DBG("ethumb=%p, theme_file=%s, group=%s, swallow=%s",
+       e, theme_file ? theme_file : "", group ? group : "",
+       swallow ? swallow : "");
+
+   if (frame)
+     {
+       edje_object_part_unswallow(frame->edje, e->img);
+       if (!theme_file)
+         _ethumb_frame_free(frame);
+     }
+
+   if (!theme_file)
+     {
+       e->frame = NULL;
+       return EINA_TRUE;
+     }
+
+   if (!frame)
+     {
+       frame = calloc(1, sizeof(Ethumb_Frame));
+       if (!frame)
+         {
+            ERR("could not allocate Ethumb_Frame structure.\n");
+            return EINA_FALSE;
+         }
+
+       frame->edje = edje_object_add(e->sub_e);
+       if (!frame->edje)
+         {
+            ERR("could not create edje frame object.\n");
+            _ethumb_frame_free(frame);
+            e->frame = NULL;
+            return EINA_FALSE;
+         }
+     }
+
+   if (!edje_object_file_set(frame->edje, theme_file, group))
+     {
+       ERR("could not load frame theme.\n");
+       _ethumb_frame_free(frame);
+       e->frame = NULL;
+       return EINA_FALSE;
+     }
+
+   edje_object_part_swallow(frame->edje, swallow, e->img);
+   if (!edje_object_part_swallow_get(frame->edje, swallow))
+     {
+       ERR("could not swallow image to edje frame.\n");
+       _ethumb_frame_free(frame);
+       e->frame = NULL;
+       return EINA_FALSE;
+     }
+
+   eina_stringshare_replace(&frame->file, theme_file);
+   eina_stringshare_replace(&frame->group, group);
+   eina_stringshare_replace(&frame->swallow, swallow);
+
+   e->frame = frame;
+
+   return EINA_TRUE;
+}
+
+EAPI void
+ethumb_frame_get(const Ethumb *e, const char **theme_file, const char **group, const char **swallow)
+{
+   EINA_SAFETY_ON_NULL_RETURN(e);
+
+   if (e->frame)
+     {
+       if (theme_file) *theme_file = e->frame->file;
+       if (group) *group = e->frame->group;
+       if (swallow) *swallow = e->frame->swallow;
+     }
+   else
+     {
+       if (theme_file) *theme_file = NULL;
+       if (group) *group = NULL;
+       if (swallow) *swallow = NULL;
+     }
+}
+
+static const char *
+_ethumb_build_absolute_path(const char *path, char buf[])
+{
+   char *p;
+   int len;
+
+   if (!path)
+     return NULL;
+
+   p = buf;
+
+   if (path[0] == '/')
+     strcpy(p, path);
+   else if (path[0] == '~')
+     {
+       strcpy(p, getenv("HOME"));
+       len = strlen(p);
+       p += len;
+       p[0] = '/';
+       p++;
+       strcpy(p, path + 2);
+     }
+   else
+     {
+       getcwd(p, PATH_MAX);
+       len = strlen(p);
+       p += len;
+       p[0] = '/';
+       p++;
+       strcpy(p, path);
+     }
+
+   return buf;
+}
+
+EAPI void
+ethumb_thumb_dir_path_set(Ethumb *e, const char *path)
+{
+   char buf[PATH_MAX];
+   EINA_SAFETY_ON_NULL_RETURN(e);
+
+   DBG("ethumb=%p, path=%s", e, path ? path : "");
+   path = _ethumb_build_absolute_path(path, buf);
+   eina_stringshare_replace(&e->thumb_dir, path);
+}
+
+EAPI const char *
+ethumb_thumb_dir_path_get(const Ethumb *e)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(e, NULL);
+
+   return e->thumb_dir;
+}
+
+EAPI void
+ethumb_thumb_category_set(Ethumb *e, const char *category)
+{
+   EINA_SAFETY_ON_NULL_RETURN(e);
+
+   DBG("ethumb=%p, category=%s", e, category ? category : "");
+   eina_stringshare_replace(&e->category, category);
+}
+
+EAPI const char *
+ethumb_thumb_category_get(const Ethumb *e)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(e, NULL);
+
+   return e->category;
+}
+
+EAPI void
+ethumb_video_start_set(Ethumb *e, float start)
+{
+   EINA_SAFETY_ON_NULL_RETURN(e);
+
+   DBG("ethumb=%p, video_start=%f", e, start);
+   e->video.start = start;
+}
+
+EAPI float
+ethumb_video_start_get(const Ethumb *e)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(e, 0);
+
+   return e->video.start;
+}
+
+EAPI void
+ethumb_video_time_set(Ethumb *e, float time)
+{
+   EINA_SAFETY_ON_NULL_RETURN(e);
+
+   DBG("ethumb=%p, video_start=%f", e, time);
+   e->video.time = time;
+}
+
+EAPI float
+ethumb_video_time_get(const Ethumb *e)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(e, 0);
+
+   return e->video.time;
+}
+
+EAPI void
+ethumb_video_interval_set(Ethumb *e, float interval)
+{
+   EINA_SAFETY_ON_NULL_RETURN(e);
+
+   DBG("ethumb=%p, video_interval=%f", e, interval);
+   e->video.interval = interval;
+}
+
+EAPI float
+ethumb_video_interval_get(const Ethumb *e)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(e, 0);
+
+   return e->video.interval;
+}
+
+EAPI void
+ethumb_video_ntimes_set(Ethumb *e, int ntimes)
+{
+   EINA_SAFETY_ON_NULL_RETURN(e);
+
+   DBG("ethumb=%p, video_ntimes=%d", e, ntimes);
+   e->video.ntimes = ntimes;
+}
+
+EAPI int
+ethumb_video_ntimes_get(const Ethumb *e)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(e, 0);
+
+   return e->video.ntimes;
+}
+
+EAPI void
+ethumb_video_fps_set(Ethumb *e, int fps)
+{
+   EINA_SAFETY_ON_NULL_RETURN(e);
+
+   DBG("ethumb=%p, video_fps=%d", e, fps);
+   e->video.fps = fps;
+}
+
+EAPI int
+ethumb_video_fps_get(const Ethumb *e)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(e, 0);
+
+   return e->video.fps;
+}
+
+EAPI void
+ethumb_document_page_set(Ethumb *e, int page)
+{
+   EINA_SAFETY_ON_NULL_RETURN(e);
+
+   DBG("ethumb=%p, document_page=%d", e, page);
+   e->document.page = page;
+}
+
+EAPI int
+ethumb_document_page_get(const Ethumb *e)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(e, 0);
+
+   return e->document.page;
+}
+
+EAPI Eina_Bool
+ethumb_file_set(Ethumb *e, const char *path, const char *key)
+{
+   char buf[PATH_MAX];
+   EINA_SAFETY_ON_NULL_RETURN_VAL(e, 0);
+
+   DBG("ethumb=%p, path=%s, key=%s", e, path ? path : "", key ? key : "");
+   if (path && access(path, R_OK))
+     {
+       ERR("couldn't access file \"%s\"\n", path);
+       return EINA_FALSE;
+     }
+
+   path = _ethumb_build_absolute_path(path, buf);
+   eina_stringshare_replace(&e->src_path, path);
+   eina_stringshare_replace(&e->src_key, key);
+   eina_stringshare_replace(&e->thumb_path, NULL);
+   eina_stringshare_replace(&e->thumb_key, NULL);
+
+   return EINA_TRUE;
+}
+
+EAPI void
+ethumb_file_get(const Ethumb *e, const char **path, const char **key)
+{
+   EINA_SAFETY_ON_NULL_RETURN(e);
+
+   if (path) *path = e->src_path;
+   if (key) *key = e->src_key;
+}
+
+static const char ACCEPTABLE_URI_CHARS[96] = {
+     /*      !    "    #    $    %    &    '    (    )    *    +    ,    -    .    / */ 
+     0x00,0x3F,0x20,0x20,0x28,0x00,0x2C,0x3F,0x3F,0x3F,0x3F,0x2A,0x28,0x3F,0x3F,0x1C,
+     /* 0    1    2    3    4    5    6    7    8    9    :    ;    <    =    >    ? */
+     0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x38,0x20,0x20,0x2C,0x20,0x20,
+     /* @    A    B    C    D    E    F    G    H    I    J    K    L    M    N    O */
+     0x38,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,
+     /* P    Q    R    S    T    U    V    W    X    Y    Z    [    \    ]    ^    _ */
+     0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x20,0x20,0x20,0x20,0x3F,
+     /* `    a    b    c    d    e    f    g    h    i    j    k    l    m    n    o */
+     0x20,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,
+     /* p    q    r    s    t    u    v    w    x    y    z    {    |    }    ~  DEL */
+     0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x20,0x20,0x20,0x3F,0x20
+};
+
+static const char *
+_ethumb_generate_hash(const char *file)
+{
+  int n;
+  MD5_CTX ctx;
+  char md5out[(2 * MD5_HASHBYTES) + 1];
+  unsigned char hash[MD5_HASHBYTES];
+  static const char hex[] = "0123456789abcdef";
+
+  char *uri;
+  char *t;
+  const unsigned char *c;
+
+#define _check_uri_char(c) \
+  ((c) >= 32 && (c) < 128 && (ACCEPTABLE_URI_CHARS[(c) - 32] & 0x08))
+
+  EINA_SAFETY_ON_NULL_RETURN_VAL(file, NULL);
+
+  uri = alloca(3 * strlen(file) + 9);
+  strncpy(uri, "file://", sizeof(uri));
+  t = uri + 7;
+
+  for (c = (const unsigned char *)file; *c != '\0'; c++)
+    {
+       if (!_check_uri_char(*c))
+        {
+           *t++ = '%';
+           *t++ = hex[*c >> 4];
+           *t++ = hex[*c & 15];
+        }
+       else
+        *t++ = *c;
+    }
+  *t = '\0';
+
+#undef _check_uri_char
+
+  MD5Init (&ctx);
+  MD5Update (&ctx, (unsigned char const*)uri, (unsigned)strlen (uri));
+  MD5Final (hash, &ctx);
+
+  for (n = 0; n < MD5_HASHBYTES; n++)
+    {
+      md5out[2 * n] = hex[hash[n] >> 4];
+      md5out[2 * n + 1] = hex[hash[n] & 0x0f];
+    }
+  md5out[2 * n] = '\0';
+
+  DBG("md5=%s, file=%s\n", md5out, file);
+  return eina_stringshare_add(md5out);
+}
+
+static int
+_ethumb_file_check_fdo(Ethumb *e)
+{
+   if (!((e->tw == THUMB_SIZE_NORMAL && e->th == THUMB_SIZE_NORMAL) ||
+       (e->tw == THUMB_SIZE_LARGE && e->th == THUMB_SIZE_LARGE)))
+     return 0;
+
+   if (e->format != ETHUMB_THUMB_FDO)
+     return 0;
+
+   if (e->aspect != ETHUMB_THUMB_KEEP_ASPECT)
+     return 0;
+
+   if (e->frame)
+     return 0;
+
+   return 1;
+}
+
+static const char *
+_ethumb_file_generate_custom_category(Ethumb *e)
+{
+   char buf[PATH_MAX];
+   const char *aspect, *format;
+   const char *frame;
+
+   if (e->aspect == ETHUMB_THUMB_KEEP_ASPECT)
+     aspect = "keep_aspect";
+   else if (e->aspect == ETHUMB_THUMB_IGNORE_ASPECT)
+     aspect = "ignore_aspect";
+   else
+     aspect = "crop";
+
+   if (e->format == ETHUMB_THUMB_FDO)
+     format = "png";
+   else if (e->format == ETHUMB_THUMB_JPEG)
+     format = "jpg";
+   else
+     format = "eet";
+
+   if (e->frame)
+     frame = "-framed";
+   else
+     frame = "";
+
+   snprintf(buf, sizeof(buf), "%dx%d-%s%s-%s",
+           e->tw, e->th, aspect, frame, format);
+
+   return eina_stringshare_add(buf);
+}
+
+static void
+_ethumb_file_generate_path(Ethumb *e)
+{
+   char buf[PATH_MAX];
+   char *fullname;
+   const char *hash;
+   const char *thumb_dir, *category;
+   const char *ext;
+   int fdo_format;
+
+
+   fdo_format = _ethumb_file_check_fdo(e);
+
+   if (e->thumb_dir)
+     thumb_dir = eina_stringshare_ref(e->thumb_dir);
+   else
+     thumb_dir = eina_stringshare_ref(_home_thumb_dir);
+
+   if (e->category)
+     category = eina_stringshare_ref(e->category);
+   else if (!fdo_format)
+     category = _ethumb_file_generate_custom_category(e);
+   else
+     {
+       if (e->tw == THUMB_SIZE_NORMAL)
+         category = eina_stringshare_ref(_thumb_category_normal);
+       else if (e->tw == THUMB_SIZE_LARGE)
+         category = eina_stringshare_ref(_thumb_category_large);
+     }
+
+   if (e->format == ETHUMB_THUMB_FDO)
+     ext = "png";
+   else if (e->format == ETHUMB_THUMB_JPEG)
+     ext = "jpg";
+   else
+     ext = "eet";
+
+
+   fullname = ecore_file_realpath(e->src_path);
+   hash = _ethumb_generate_hash(fullname);
+   snprintf(buf, sizeof(buf), "%s/%s/%s.%s", thumb_dir, category, hash, ext);
+   free(fullname);
+   DBG("ethumb=%p, path=%s", e, buf);
+   eina_stringshare_replace(&e->thumb_path, buf);
+   if (e->format == ETHUMB_THUMB_EET)
+     eina_stringshare_replace(&e->thumb_key, "thumbnail");
+   else
+     {
+       eina_stringshare_del(e->thumb_key);
+       e->thumb_key = NULL;
+     }
+
+   eina_stringshare_del(thumb_dir);
+   eina_stringshare_del(category);
+   eina_stringshare_del(hash);
+}
+
+EAPI void
+ethumb_file_free(Ethumb *e)
+{
+   EINA_SAFETY_ON_NULL_RETURN(e);
+   DBG("ethumb=%p", e);
+
+   eina_stringshare_replace(&e->src_path, NULL);
+   eina_stringshare_replace(&e->src_key, NULL);
+   eina_stringshare_replace(&e->thumb_path, NULL);
+   eina_stringshare_replace(&e->thumb_key, NULL);
+}
+
+EAPI void
+ethumb_thumb_path_set(Ethumb *e, const char *path, const char *key)
+{
+   char buf[PATH_MAX];
+
+   EINA_SAFETY_ON_NULL_RETURN(e);
+   DBG("ethumb=%p, path=%s, key=%s", e, path ? path : "", key ? key : "");
+
+   if (!path)
+     {
+       eina_stringshare_replace(&e->thumb_path, NULL);
+       eina_stringshare_replace(&e->thumb_key, NULL);
+     }
+   else
+     {
+       path = _ethumb_build_absolute_path(path, buf);
+       eina_stringshare_replace(&e->thumb_path, path);
+       eina_stringshare_replace(&e->thumb_key, key);
+     }
+}
+
+EAPI void
+ethumb_thumb_path_get(Ethumb *e, const char **path, const char **key)
+{
+   EINA_SAFETY_ON_NULL_RETURN(e);
+   if (!e->thumb_path)
+     _ethumb_file_generate_path(e);
+
+   if (path) *path = e->thumb_path;
+   if (key) *key = e->thumb_key;
+}
+
+void
+ethumb_calculate_aspect_from_ratio(Ethumb *e, float ia, int *w, int *h)
+{
+   float a;
+
+   *w = e->tw;
+   *h = e->th;
+
+   if (ia == 0)
+     return;
+
+   a = e->tw / (float)e->th;
+
+   if (e->aspect == ETHUMB_THUMB_KEEP_ASPECT)
+     {
+       if ((ia > a && e->tw > 0) || e->th <= 0)
+         *h = e->tw / ia;
+       else
+         *w = e->th * ia;
+     }
+}
+
+void
+ethumb_calculate_aspect(Ethumb *e, int iw, int ih, int *w, int *h)
+{
+   float ia;
+
+   ia = iw / (float)ih;
+
+   ethumb_calculate_aspect_from_ratio(e, ia, w, h);
+}
+
+void
+ethumb_calculate_fill_from_ratio(Ethumb *e, float ia, int *fx, int *fy, int *fw, int *fh)
+{
+   float a;
+
+   if (ia == 0)
+     return;
+
+   *fw = e->tw;
+   *fh = e->th;
+   *fx = 0;
+   *fy = 0;
+   a = e->tw / (float)e->th;
+
+   if (e->aspect == ETHUMB_THUMB_CROP)
+     {
+       if ((ia > a && e->tw > 0) || e->th <= 0)
+         *fw = e->th * ia;
+       else
+         *fh = e->tw / ia;
+
+       *fx = - e->crop_x * (*fw - e->tw);
+       *fy = - e->crop_y * (*fh - e->th);
+     }
+   else if (e->aspect == ETHUMB_THUMB_KEEP_ASPECT)
+     {
+       if ((ia > a && e->tw > 0) || e->th <= 0)
+         *fh = e->tw / ia;
+       else
+         *fw = e->th * ia;
+     }
+}
+
+void
+ethumb_calculate_fill(Ethumb *e, int iw, int ih, int *fx, int *fy, int *fw, int *fh)
+{
+   float ia;
+   ia = iw / (float)ih;
+
+   ethumb_calculate_fill_from_ratio(e, ia, fx, fy, fw, fh);
+}
+
+static Eina_Bool
+_ethumb_plugin_generate(Ethumb *e)
+{
+   const char *ext;
+   Ethumb_Plugin *plugin;
+
+   ext = strrchr(e->src_path, '.');
+   if (!ext)
+     {
+       ERR("could not get extension for file \"%s\"\n", e->src_path);
+       return EINA_FALSE;
+     }
+
+   plugin = eina_hash_find(_plugins_ext, ext + 1);
+   if (!plugin)
+     {
+       DBG("no plugin for extension: \"%s\"\n", ext + 1);
+       return EINA_FALSE;
+     }
+
+   if (e->frame)
+     evas_object_hide(e->frame->edje);
+   else
+     evas_object_hide(e->img);
+
+   plugin->generate_thumb(e);
+
+   return EINA_TRUE;
+}
+
+Eina_Bool
+ethumb_plugin_image_resize(Ethumb *e, int w, int h)
+{
+   Evas_Object *img;
+
+   img = e->img;
+
+   if (e->frame)
+     {
+       edje_extern_object_min_size_set(img, w, h);
+       edje_extern_object_max_size_set(img, w, h);
+       edje_object_calc_force(e->frame->edje);
+       evas_object_move(e->frame->edje, 0, 0);
+       evas_object_resize(e->frame->edje, w, h);
+     }
+   else
+     {
+       evas_object_move(img, 0, 0);
+       evas_object_resize(img, w, h);
+     }
+
+   evas_object_image_size_set(e->o, w, h);
+   ecore_evas_resize(e->sub_ee, w, h);
+
+   e->rw = w;
+   e->rh = h;
+
+   return EINA_TRUE;
+}
+
+Eina_Bool
+ethumb_image_save(Ethumb *e)
+{
+   Eina_Bool r;
+   char *dname;
+   char flags[256];
+
+   evas_damage_rectangle_add(e->sub_e, 0, 0, e->rw, e->rh);
+   evas_render(e->sub_e);
+
+   if (!e->thumb_path)
+     _ethumb_file_generate_path(e);
+
+   if (!e->thumb_path)
+     {
+       ERR("could not create file path...\n");
+       return EINA_FALSE;
+     }
+
+   dname = ecore_file_dir_get(e->thumb_path);
+   r = ecore_file_mkpath(dname);
+   free(dname);
+   if (!r)
+     {
+       ERR("could not create directory '%s'\n", dname);
+       return EINA_FALSE;
+     }
+
+   snprintf(flags, sizeof(flags), "quality=%d compress=%d",
+           e->quality, e->compress);
+   r = evas_object_image_save(e->o, e->thumb_path, e->thumb_key, flags);
+
+   if (!r)
+     {
+       ERR("could not save image.\n");
+       return EINA_FALSE;
+     }
+
+   return EINA_TRUE;
+}
+
+static int
+_ethumb_image_load(Ethumb *e)
+{
+   int error;
+   Evas_Coord w, h, ww, hh, fx, fy, fw, fh;
+   Evas_Object *img;
+
+   img = e->img;
+
+   if (e->frame)
+     evas_object_hide(e->frame->edje);
+   else
+     evas_object_hide(img);
+   evas_object_image_file_set(img, NULL, NULL);
+   evas_object_image_load_size_set(img, e->tw, e->th);
+   evas_object_image_file_set(img, e->src_path, e->src_key);
+
+   if (e->frame)
+     evas_object_show(e->frame->edje);
+   else
+     evas_object_show(img);
+
+   error = evas_object_image_load_error_get(img);
+   if (error != EVAS_LOAD_ERROR_NONE)
+     {
+       ERR("could not load image '%s': %d\n", e->src_path, error);
+       return 0;
+     }
+
+   evas_object_image_size_get(img, &w, &h);
+   if ((w <= 0) || (h <= 0))
+     return 0;
+
+   ethumb_calculate_aspect(e, w, h, &ww, &hh);
+
+   if (e->frame)
+     {
+       edje_extern_object_min_size_set(img, ww, hh);
+       edje_extern_object_max_size_set(img, ww, hh);
+       edje_object_calc_force(e->frame->edje);
+       evas_object_move(e->frame->edje, 0, 0);
+       evas_object_resize(e->frame->edje, ww, hh);
+     }
+   else
+     {
+       evas_object_move(img, 0, 0);
+       evas_object_resize(img, ww, hh);
+     }
+
+   ethumb_calculate_fill(e, w, h, &fx, &fy, &fw, &fh);
+   evas_object_image_fill_set(img, fx, fy, fw, fh);
+
+   evas_object_image_size_set(e->o, ww, hh);
+   ecore_evas_resize(e->sub_ee, ww, hh);
+
+   e->rw = ww;
+   e->rh = hh;
+
+   return 1;
+}
+
+static int
+_ethumb_finished_idler_cb(void *data)
+{
+   Ethumb *e = data;
+
+   e->finished_cb(e->cb_data, e, e->cb_result);
+   if (e->cb_data_free)
+     e->cb_data_free(e->cb_data);
+   e->finished_idler = NULL;
+   e->finished_cb = NULL;
+   e->cb_data = NULL;
+   e->cb_data_free = NULL;
+
+   return 0;
+}
+
+void
+ethumb_finished_callback_call(Ethumb *e, int result)
+{
+   EINA_SAFETY_ON_NULL_RETURN(e);
+
+   e->cb_result = result;
+   if (e->finished_idler)
+     ecore_idler_del(e->finished_idler);
+   e->finished_idler = ecore_idler_add(_ethumb_finished_idler_cb, e);
+}
+
+EAPI Eina_Bool
+ethumb_generate(Ethumb *e, Ethumb_Generate_Cb finished_cb, const void *data, Eina_Free_Cb free_data)
+{
+   int r;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(e, 0);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(finished_cb, 0);
+   DBG("ethumb=%p, finished_cb=%p, data=%p, free_data=%p, path=%s, key=%s",
+       e, finished_cb, data, free_data,
+       e->src_path ? e->src_path : "", e->src_key ? e->src_key : "");
+
+   if (e->finished_idler)
+     {
+       ERR("thumbnail generation already in progress.\n");
+       return EINA_FALSE;
+     }
+   e->finished_cb = finished_cb;
+   e->cb_data = (void *)data;
+   e->cb_data_free = free_data;
+
+   if (!e->src_path)
+     {
+       ERR("no file set.\n");
+       ethumb_finished_callback_call(e, 0);
+       return EINA_TRUE;
+     }
+
+   r = _ethumb_plugin_generate(e);
+   if (r)
+     return EINA_TRUE;
+
+   if (!_ethumb_image_load(e))
+     {
+       ERR("could not load input image.\n");
+       ethumb_finished_callback_call(e, 0);
+       return EINA_TRUE;
+     }
+
+   r = ethumb_image_save(e);
+
+   ethumb_finished_callback_call(e, r);
+
+   return EINA_TRUE;
+}
+
+EAPI Eina_Bool
+ethumb_exists(Ethumb *e)
+{
+   struct stat thumb, src;
+   int r_thumb, r_src;
+   Eina_Bool r = EINA_FALSE;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(e, 0);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(e->src_path, 0);
+   DBG("ethumb=%p, path=%s", e, e->src_path ? e->src_path : "");
+
+   if (!e->thumb_path)
+     _ethumb_file_generate_path(e);
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(e->thumb_path, 0);
+
+   r_thumb = stat(e->thumb_path, &thumb);
+   r_src = stat(e->src_path, &src);
+
+   EINA_SAFETY_ON_TRUE_RETURN_VAL(r_src, 0);
+
+   if (r_thumb && errno != ENOENT)
+     ERR("could not access file \"%s\": %s\n", e->thumb_path, strerror(errno));
+   else if (!r_thumb && thumb.st_mtime > src.st_mtime)
+     r = EINA_TRUE;
+
+   return r;
+}
+
+Evas *
+ethumb_evas_get(const Ethumb *e)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(e, NULL);
+
+   return e->sub_e;
+}
+
+Ecore_Evas *
+ethumb_ecore_evas_get(const Ethumb *e)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(e, NULL);
+
+   return e->sub_ee;
+}
diff --git a/src/lib/Ethumb.h b/src/lib/Ethumb.h
new file mode 100644 (file)
index 0000000..8d95304
--- /dev/null
@@ -0,0 +1,135 @@
+#ifndef __ETHUMB_H__
+#define __ETHUMB_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 <Ecore.h>
+#include <Ecore_Evas.h>
+#include <Evas.h>
+#include <Eina.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum _Ethumb_Thumb_FDO_Size
+{
+   ETHUMB_THUMB_NORMAL,
+   ETHUMB_THUMB_LARGE
+};
+
+typedef enum _Ethumb_Thumb_FDO_Size Ethumb_Thumb_FDO_Size;
+
+enum _Ethumb_Thumb_Format
+{
+   ETHUMB_THUMB_FDO,
+   ETHUMB_THUMB_JPEG,
+   ETHUMB_THUMB_EET
+};
+
+typedef enum _Ethumb_Thumb_Format Ethumb_Thumb_Format;
+
+enum _Ethumb_Thumb_Aspect
+{
+   ETHUMB_THUMB_KEEP_ASPECT,
+   ETHUMB_THUMB_IGNORE_ASPECT,
+   ETHUMB_THUMB_CROP
+};
+
+typedef enum _Ethumb_Thumb_Aspect Ethumb_Thumb_Aspect;
+
+typedef struct _Ethumb_Frame Ethumb_Frame;
+typedef struct _Ethumb Ethumb;
+typedef void (*Ethumb_Generate_Cb)(void *data, Ethumb *e, Eina_Bool success);
+
+EAPI int ethumb_init(void);
+EAPI int ethumb_shutdown(void);
+
+EAPI Ethumb * ethumb_new(void) EINA_MALLOC EINA_WARN_UNUSED_RESULT;
+EAPI void ethumb_free(Ethumb *e);
+
+EAPI void ethumb_thumb_fdo_set(Ethumb *e, Ethumb_Thumb_FDO_Size s) EINA_ARG_NONNULL(1);
+
+EAPI void ethumb_thumb_size_set(Ethumb *e, int tw, int th) EINA_ARG_NONNULL(1);
+EAPI void ethumb_thumb_size_get(const Ethumb *e, int *tw, int *th) EINA_ARG_NONNULL(1);
+
+EAPI void ethumb_thumb_format_set(Ethumb *e, Ethumb_Thumb_Format f) EINA_ARG_NONNULL(1);
+EAPI Ethumb_Thumb_Format ethumb_thumb_format_get(const Ethumb *e) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1) EINA_PURE;
+
+EAPI void ethumb_thumb_aspect_set(Ethumb *e, Ethumb_Thumb_Aspect a) EINA_ARG_NONNULL(1);
+EAPI Ethumb_Thumb_Aspect ethumb_thumb_aspect_get(const Ethumb *e) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1) EINA_PURE;
+
+EAPI void ethumb_thumb_crop_align_set(Ethumb *e, float x, float y) EINA_ARG_NONNULL(1);
+EAPI void ethumb_thumb_crop_align_get(const Ethumb *e, float *x, float *y) EINA_ARG_NONNULL(1);
+
+EAPI void ethumb_thumb_quality_set(Ethumb *e, int quality) EINA_ARG_NONNULL(1);
+EAPI int ethumb_thumb_quality_get(const Ethumb *e) EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT EINA_PURE;
+
+EAPI void ethumb_thumb_compress_set(Ethumb *e, int compress) EINA_ARG_NONNULL(1);
+EAPI int ethumb_thumb_compress_get(const Ethumb *e) EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT EINA_PURE;
+
+EAPI Eina_Bool ethumb_frame_set(Ethumb *e, const char *theme_file, const char *group, const char *swallow) EINA_ARG_NONNULL(1);
+EAPI void ethumb_frame_get(const Ethumb *e, const char **theme_file, const char **group, const char **swallow) EINA_ARG_NONNULL(1);
+
+EAPI void ethumb_thumb_dir_path_set(Ethumb *e, const char *path) EINA_ARG_NONNULL(1);
+EAPI const char * ethumb_thumb_dir_path_get(const Ethumb *e) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1) EINA_PURE;
+
+EAPI void ethumb_thumb_category_set(Ethumb *e, const char *category) EINA_ARG_NONNULL(1);
+EAPI const char * ethumb_thumb_category_get(const Ethumb *e) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1) EINA_PURE;
+
+
+EAPI void ethumb_video_start_set(Ethumb *e, float start) EINA_ARG_NONNULL(1);
+EAPI float ethumb_video_start_get(const Ethumb *e) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1) EINA_PURE;
+EAPI void ethumb_video_time_set(Ethumb *e, float time) EINA_ARG_NONNULL(1);
+EAPI float ethumb_video_time_get(const Ethumb *e) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1) EINA_PURE;
+EAPI void ethumb_video_interval_set(Ethumb *e, float interval) EINA_ARG_NONNULL(1);
+EAPI float ethumb_video_interval_get(const Ethumb *e) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1) EINA_PURE;
+EAPI void ethumb_video_ntimes_set(Ethumb *e, int ntimes) EINA_ARG_NONNULL(1);
+EAPI int ethumb_video_ntimes_get(const Ethumb *e) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1) EINA_PURE;
+EAPI void ethumb_video_fps_set(Ethumb *e, int fps) EINA_ARG_NONNULL(1);
+EAPI int ethumb_video_fps_get(const Ethumb *e) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1) EINA_PURE;
+
+
+EAPI void ethumb_document_page_set(Ethumb *e, int page) EINA_ARG_NONNULL(1);
+EAPI int ethumb_document_page_get(const Ethumb *e) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1) EINA_PURE;
+
+EAPI Eina_Bool ethumb_file_set(Ethumb *e, const char *path, const char *key) EINA_ARG_NONNULL(1, 2);
+EAPI void ethumb_file_get(const Ethumb *e, const char **path, const char **key) EINA_ARG_NONNULL(1);
+EAPI void ethumb_file_free(Ethumb *e) EINA_ARG_NONNULL(1);
+EAPI void ethumb_thumb_path_set(Ethumb *e, const char *path, const char *key) EINA_ARG_NONNULL(1);
+EAPI void ethumb_thumb_path_get(Ethumb *e, const char **path, const char **key) EINA_ARG_NONNULL(1);
+EAPI Eina_Bool ethumb_generate(Ethumb *e, Ethumb_Generate_Cb finished_cb, const void *data, Eina_Free_Cb free_data) EINA_ARG_NONNULL(1, 2);
+EAPI Eina_Bool ethumb_exists(Ethumb *e) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1) EINA_PURE;
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* __ETHUMB_H__ */
diff --git a/src/lib/Ethumb_Plugin.h b/src/lib/Ethumb_Plugin.h
new file mode 100644 (file)
index 0000000..e9e4331
--- /dev/null
@@ -0,0 +1,27 @@
+#ifndef _ETHUMB_PLUGIN_H_
+#define _ETHUMB_PLUGIN_H_
+
+#include <Ethumb.h>
+#include <Eina.h>
+#include <Evas.h>
+#include <Ecore_Evas.h>
+
+typedef struct _Ethumb_Plugin Ethumb_Plugin;
+
+struct _Ethumb_Plugin
+{
+   const char **extensions;
+   void (*generate_thumb)(Ethumb *);
+};
+
+EAPI void ethumb_calculate_aspect_from_ratio(Ethumb *e, float ia, int *w, int *h);
+EAPI void ethumb_calculate_aspect(Ethumb *e, int iw, int ih, int *w, int *h);
+EAPI void ethumb_calculate_fill_from_ratio(Ethumb *e, float ia, int *fx, int *fy, int *fw, int *fh);
+EAPI void ethumb_calculate_fill(Ethumb *e, int iw, int ih, int *fx, int *fy, int *fw, int *fh);
+EAPI Eina_Bool ethumb_plugin_image_resize(Ethumb *e, int w, int h);
+EAPI Eina_Bool ethumb_image_save(Ethumb *e);
+EAPI void ethumb_finished_callback_call(Ethumb *e, int result);
+EAPI Evas * ethumb_evas_get(const Ethumb *e);
+EAPI Ecore_Evas * ethumb_ecore_evas_get(const Ethumb *e);
+
+#endif /* _ETHUMB_PLUGIN_H_ */
diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am
new file mode 100644 (file)
index 0000000..3508f7e
--- /dev/null
@@ -0,0 +1,27 @@
+MAINTAINERCLEANFILES = Makefile.in
+
+SUBDIRS = .
+
+AM_CPPFLAGS = \
+       -I$(top_srcdir) \
+       -I$(top_builddir) \
+       @EVAS_CFLAGS@ @ECORE_EVAS_CFLAGS@ @ECORE_FILE_CFLAGS@ @EDJE_CFLAGS@
+
+include_HEADERS = Ethumb.h Ethumb_Plugin.h
+noinst_HEADERS = md5.h ethumb_private.h
+
+lib_LTLIBRARIES = libethumb.la
+
+
+libethumb_la_SOURCES = \
+       Ethumb.c \
+       md5.c
+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/src/lib/client/Ethumb_Client.c b/src/lib/client/Ethumb_Client.c
new file mode 100644 (file)
index 0000000..6c83c17
--- /dev/null
@@ -0,0 +1,1612 @@
+/**
+ * @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 <antognolli@profusion.mobi>
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <Eina.h>
+#include <eina_safety_checks.h>
+#include <Ethumb.h>
+#include "Ethumb_Client.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <stdbool.h>
+
+#ifndef PATH_MAX
+#define PATH_MAX 4096
+#endif
+
+#include <E_DBus.h>
+
+#define MAX_ID 2000000
+
+static int _log_dom = -1;
+#define DBG(...) EINA_LOG_DOM_DBG(_log_dom, __VA_ARGS__)
+#define INF(...) EINA_LOG_DOM_INFO(_log_dom, __VA_ARGS__)
+#define WRN(...) EINA_LOG_DOM_WARN(_log_dom, __VA_ARGS__)
+#define ERR(...) EINA_LOG_DOM_ERR(_log_dom, __VA_ARGS__)
+
+struct _Ethumb_Client
+{
+   Ethumb *ethumb;
+   int 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;
+   DBusPendingCall *pending_start_service_by_name;
+   const char *unique_name;
+   DBusPendingCall *pending_new;
+   struct {
+      Ethumb_Client_Connect_Cb cb;
+      void *data;
+      Eina_Free_Cb free_data;
+   } connect;
+   Eina_List *pending_add;
+   Eina_List *pending_remove;
+   Eina_List *pending_gen;
+   DBusPendingCall *pending_clear;
+   DBusPendingCall *pending_setup;
+   struct {
+      Ethumb_Client_Die_Cb cb;
+      void *data;
+      Eina_Free_Cb free_data;
+   } die;
+   const char *object_path;
+
+   Eina_Bool ethumb_dirty : 1;
+   Eina_Bool connected : 1;
+   Eina_Bool server_started : 1;
+};
+
+struct _ethumb_pending_add
+{
+   dbus_int32_t id;
+   const char *file;
+   const char *key;
+   const char *thumb;
+   const char *thumb_key;
+   Ethumb_Client_Generate_Cb generated_cb;
+   void *data;
+   Eina_Free_Cb free_data;
+   DBusPendingCall *pending_call;
+   Ethumb_Client *client;
+};
+
+struct _ethumb_pending_remove
+{
+   dbus_int32_t id;
+   Ethumb_Client_Generate_Cancel_Cb cancel_cb;
+   void *data;
+   Eina_Free_Cb free_data;
+   DBusPendingCall *pending_call;
+   Ethumb_Client *client;
+};
+
+struct _ethumb_pending_gen
+{
+   dbus_int32_t id;
+   const char *file;
+   const char *key;
+   const char *thumb;
+   const char *thumb_key;
+   Ethumb_Client_Generate_Cb generated_cb;
+   void *data;
+   Eina_Free_Cb free_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 void _ethumb_client_get_name_owner(void *data, DBusMessage *msg, DBusError *err);
+
+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->die.cb)
+              {
+                 client->die.cb(client->die.data, client);
+                 client->die.cb = NULL;
+              }
+            if (client->die.free_data)
+              {
+                 client->die.free_data(client->die.data);
+                 client->die.free_data = NULL;
+                 client->die.data = NULL;
+              }
+         }
+     }
+   else
+     DBG("unknown change from %s to %s\n", from, to);
+}
+
+static void
+_ethumb_client_report_connect(Ethumb_Client *client, Eina_Bool success)
+{
+   if (!client->connect.cb)
+     {
+       ERR("already called?!");
+       return;
+     }
+
+   client->connect.cb(client->connect.data, client, success);
+   if (client->connect.free_data)
+     {
+       client->connect.free_data(client->connect.data);
+       client->connect.free_data = NULL;
+     }
+   client->connect.cb = NULL;
+   client->connect.data = NULL;
+}
+
+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);
+
+   _ethumb_client_report_connect(client, 1);
+   return;
+
+end_error:
+   _ethumb_client_report_connect(client, 0);
+}
+
+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_start_server_cb(void *data, DBusMessage *msg, DBusError *err)
+{
+   Ethumb_Client *client = data;
+   DBusMessageIter iter;
+   dbus_uint32_t ret;
+   int t;
+
+   client->pending_start_service_by_name = 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_UINT32))
+     goto error;
+
+   dbus_message_iter_get_basic(&iter, &ret);
+   if ((ret != 1) && (ret != 2))
+     {
+       ERR("Error starting Ethumbd DBus service by its name: retcode %u\n",
+           ret);
+       goto error;
+     }
+
+   client->server_started = 1;
+   DBG("Ethumbd DBus service started successfully (%d), now request its name\n",
+       ret);
+
+   if (client->pending_get_name_owner)
+     {
+       DBG("already requesting name owner, cancel and try again\n");
+       dbus_pending_call_cancel(client->pending_get_name_owner);
+     }
+
+   client->pending_get_name_owner = e_dbus_get_name_owner
+     (client->conn, _ethumb_dbus_bus_name, _ethumb_client_get_name_owner,
+      client);
+   if (!client->pending_get_name_owner)
+     {
+       ERR("could not create a get_name_owner request.\n");
+       goto error;
+     }
+
+   return;
+
+ error:
+   ERR("failed to start Ethumbd DBus service by its name.\n");
+   _ethumb_client_report_connect(client, 0);
+}
+
+static void
+_ethumb_client_start_server(Ethumb_Client *client)
+{
+   if (client->pending_start_service_by_name)
+     {
+       DBG("already pending start service by name.\n");
+       return;
+     }
+
+   client->server_started = 0;
+   client->pending_start_service_by_name = e_dbus_start_service_by_name
+     (client->conn, _ethumb_dbus_bus_name, 0, _ethumb_client_start_server_cb,
+      client);
+   if (!client->pending_start_service_by_name)
+     {
+       ERR("could not start service by name!\n");
+       _ethumb_client_report_connect(client, 0);
+     }
+}
+
+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_error_is_set(err) && (!client->server_started))
+     {
+       DBG("could not find server (%s), try to start it...\n", err->message);
+       _ethumb_client_start_server(client);
+       return;
+     }
+
+   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:
+   _ethumb_client_report_connect(client, 0);
+}
+
+EAPI int
+ethumb_client_init(void)
+{
+   if (_initcount)
+     return ++_initcount;
+
+   if (!eina_init())
+     {
+       fprintf(stderr, "ERROR: Could not initialize log module.\n");
+       return 0;
+     }
+   _log_dom = eina_log_domain_register("ethumb_client", EINA_COLOR_YELLOW);
+   if (_log_dom < 0)
+     {
+       EINA_LOG_ERR("Could not register log domain: ethumb_client");
+       eina_shutdown();
+       return 0;
+     }
+
+   ethumb_init();
+   e_dbus_init();
+
+   return ++_initcount;
+}
+
+EAPI int
+ethumb_client_shutdown(void)
+{
+   _initcount--;
+   if (_initcount > 0)
+     return _initcount;
+
+   e_dbus_shutdown();
+   ethumb_shutdown();
+   eina_log_domain_unregister(_log_dom);
+   _log_dom = -1;
+   eina_shutdown();
+   return _initcount;
+}
+
+/**
+ * Connects to Ethumb server and return the client instance.
+ *
+ * This is the "constructor" of Ethumb_Client, where everything
+ * starts.
+ *
+ * If server was down, it is tried to start it using DBus activation,
+ * then the connection is retried.
+ *
+ * This call is asynchronous and will not block, instead it will be in
+ * "not connected" state until @a connect_cb is called with either
+ * success or failure. On failure, then no methods should be
+ * called. On success you're now able to setup and then ask generation
+ * of thumbnails.
+ *
+ * Usually you should listen for server death/disconenction with
+ * ethumb_client_on_server_die_callback_set().
+ *
+ * @param connect_cb function to call to report connection success or
+ *        failure. Do not call any other ethumb_client method until
+ *        this function returns. The first received parameter is the
+ *        given argument @a data. Must @b not be @c NULL. This
+ *        function will not be called if user explicitly calls
+ *        ethumb_client_disconnect().
+ * @param data context to give back to @a connect_cb. May be @c NULL.
+ * @param free_data function used to release @a data resources, if
+ *        any. May be @c NULL. If this function exists, it will be
+ *        called immediately after @a connect_cb is called or if user
+ *        explicitly calls ethumb_client_disconnect() before such
+ *        (that is, don't rely on @a data after @a connect_cb was
+ *        called!)
+ *
+ * @return client instance or NULL if failed. If @a connect_cb is
+ *         missing it returns @c NULL. If it fail for other
+ *         conditions, @c NULL is also returned and @a connect_cb is
+ *         called with @c success=EINA_FALSE. The client instance is
+ *         not ready to be used until @a connect_cb is called.
+ */
+EAPI Ethumb_Client *
+ethumb_client_connect(Ethumb_Client_Connect_Cb connect_cb, const void *data, Eina_Free_Cb free_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.data = (void *)data;
+   eclient->connect.free_data = free_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:
+   connect_cb((void *)data, NULL, EINA_FALSE);
+   if (free_data)
+     free_data((void *)data);
+   return NULL;
+}
+
+/**
+ * Disconnect the client, releasing all client resources.
+ *
+ * This is the destructor of Ethumb_Client, after it's disconnected
+ * the client handle is now gone and should not be used.
+ */
+EAPI void
+ethumb_client_disconnect(Ethumb_Client *client)
+{
+   void *data;
+
+   EINA_SAFETY_ON_NULL_RETURN(client);
+
+   if (!client->connected)
+     goto end_connection;
+
+   EINA_LIST_FREE(client->pending_add, data)
+     {
+       struct _ethumb_pending_add *pending = data;
+       eina_stringshare_del(pending->file);
+       eina_stringshare_del(pending->key);
+       eina_stringshare_del(pending->thumb);
+       eina_stringshare_del(pending->thumb_key);
+       dbus_pending_call_cancel(pending->pending_call);
+       dbus_pending_call_unref(pending->pending_call);
+       if (pending->free_data)
+         pending->free_data(pending->data);
+       free(pending);
+     }
+
+   EINA_LIST_FREE(client->pending_gen, data)
+     {
+       struct _ethumb_pending_gen *pending = data;
+       eina_stringshare_del(pending->file);
+       eina_stringshare_del(pending->key);
+       eina_stringshare_del(pending->thumb);
+       eina_stringshare_del(pending->thumb_key);
+       if (pending->free_data)
+         pending->free_data(pending->data);
+       free(pending);
+     }
+
+   EINA_LIST_FREE(client->pending_remove, data)
+     {
+       struct _ethumb_pending_remove *pending = data;
+       dbus_pending_call_cancel(pending->pending_call);
+       dbus_pending_call_unref(pending->pending_call);
+       if (pending->free_data)
+         pending->free_data(pending->data);
+       free(pending);
+     }
+
+   if (client->pending_clear)
+     {
+       dbus_pending_call_cancel(client->pending_clear);
+       dbus_pending_call_unref(client->pending_clear);
+     }
+
+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);
+
+   if (client->pending_start_service_by_name)
+     dbus_pending_call_cancel(client->pending_start_service_by_name);
+
+   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);
+
+   if (client->connect.free_data)
+     client->connect.free_data(client->connect.data);
+   if (client->die.free_data)
+     client->die.free_data(client->die.data);
+
+   free(client);
+}
+
+/**
+ * Sets the callback to report server died.
+ *
+ * When server dies there is nothing you can do, just release
+ * resources with ethumb_client_disconnect() and probably try to
+ * connect again.
+ *
+ * Usually you should set this callback and handle this case, it does
+ * happen!
+ *
+ * @param client the client instance to monitor. Must @b not be @c
+ *        NULL.
+ * @param server_die_cb function to call back when server dies. The
+ *        first parameter will be the argument @a data. May be @c
+ *        NULL.
+ * @param data context to give back to @a server_die_cb. May be @c
+ *        NULL.
+ * @param free_data used to release @a data resources after @a
+ *        server_die_cb is called or user calls
+ *        ethumb_client_disconnect().
+ */
+EAPI void
+ethumb_client_on_server_die_callback_set(Ethumb_Client *client, Ethumb_Client_Die_Cb server_die_cb, const void *data, Eina_Free_Cb free_data)
+{
+   EINA_SAFETY_ON_NULL_RETURN(client);
+
+   if (client->die.free_data)
+     client->die.free_data(client->die.data);
+
+   client->die.cb = server_die_cb;
+   client->die.data = (void *)data;
+   client->die.free_data = free_data;
+}
+
+static void
+_ethumb_client_ethumb_setup_cb(void *data, DBusMessage *msg, DBusError *error)
+{
+   DBusMessageIter iter;
+   int t;
+   dbus_bool_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);
+}
+
+/**
+ * Send setup to server.
+ *
+ * This method is called automatically by ethumb_client_generate() if
+ * any property was changed. No need to call it manually.
+ *
+ * @param client client instance. Must @b not be @c NULL and client
+ *        must be connected (after connected_cb is called).
+ */
+EAPI void
+ethumb_client_ethumb_setup(Ethumb_Client *client)
+{
+   DBusMessage *msg;
+   DBusMessageIter iter, aiter, diter, viter, vaiter;
+   Ethumb *e = client->ethumb;
+   const char *entry;
+   dbus_int32_t tw, th, format, aspect, quality, compress;
+   float cx, cy;
+   double t;
+   const char *theme_file, *group, *swallow;
+   const char *directory, *category;
+   double video_time, video_start, video_interval;
+   dbus_int32_t video_ntimes, video_fps, document_page;
+
+   EINA_SAFETY_ON_NULL_RETURN(client);
+   EINA_SAFETY_ON_FALSE_RETURN(client->connected);
+   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);
+   t = cx;
+   dbus_message_iter_append_basic(&vaiter, DBUS_TYPE_DOUBLE, &t);
+   t = cy;
+   dbus_message_iter_append_basic(&vaiter, DBUS_TYPE_DOUBLE, &t);
+   dbus_message_iter_close_container(&viter, &vaiter);
+   _close_variant_iter(viter);
+
+   _open_variant_iter("quality", "i", viter);
+   quality = ethumb_thumb_quality_get(e);
+   dbus_message_iter_append_basic(&viter, DBUS_TYPE_INT32, &quality);
+   _close_variant_iter(viter);
+
+   _open_variant_iter("compress", "i", viter);
+   compress = ethumb_thumb_compress_get(e);
+   dbus_message_iter_append_basic(&viter, DBUS_TYPE_INT32, &compress);
+   _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("video_start", "d", viter);
+   video_start = ethumb_video_start_get(e);
+   dbus_message_iter_append_basic(&viter, DBUS_TYPE_DOUBLE, &video_start);
+   _close_variant_iter(viter);
+
+   _open_variant_iter("video_interval", "d", viter);
+   video_interval = ethumb_video_interval_get(e);
+   dbus_message_iter_append_basic(&viter, DBUS_TYPE_DOUBLE, &video_interval);
+   _close_variant_iter(viter);
+
+   _open_variant_iter("video_ntimes", "i", viter);
+   video_ntimes = ethumb_video_ntimes_get(e);
+   dbus_message_iter_append_basic(&viter, DBUS_TYPE_INT32, &video_ntimes);
+   _close_variant_iter(viter);
+
+   _open_variant_iter("video_fps", "i", viter);
+   video_fps = ethumb_video_fps_get(e);
+   dbus_message_iter_append_basic(&viter, DBUS_TYPE_INT32, &video_fps);
+   _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;
+   dbus_int32_t id = -1;
+   const char *thumb;
+   const char *thumb_key;
+   Ethumb_Client *client = data;
+   int t;
+   dbus_bool_t 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_INT32))
+     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(pending->data, client, id,
+                             pending->file, pending->key,
+                              pending->thumb, pending->thumb_key,
+                             success);
+        if (pending->free_data)
+         pending->free_data(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;
+   dbus_int32_t 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_INT32))
+     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;
+   generating->free_data = pending->free_data;
+   client->pending_gen = eina_list_append(client->pending_gen, generating);
+
+end:
+   free(pending);
+}
+
+static int
+_ethumb_client_queue_add(Ethumb_Client *client, const char *file, const char *key, const char *thumb, const char *thumb_key, Ethumb_Client_Generate_Cb generated_cb, const void *data, Eina_Free_Cb free_data)
+{
+   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 = (void *)data;
+   pending->free_data = free_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_INT32, &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;
+   dbus_bool_t 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->cancel_cb)
+     pending->cancel_cb(pending->data, success);
+   if (pending->free_data)
+     pending->free_data(pending->data);
+   free(pending);
+}
+
+/**
+ * Ask server to cancel generation of thumbnail.
+ *
+ * @param client client instance. Must @b not be @c NULL and client
+ *        must be connected (after connected_cb is called).
+ * @param id valid id returned by ethumb_client_generate()
+ * @param cancel_cb function to report cancellation results.
+ * @param data context argument to give back to @a cancel_cb. May be
+ *        @c NULL.
+ * @param data context to give back to @a cancel_cb. May be @c
+ *        NULL.
+ * @param free_data used to release @a data resources after @a
+ *        cancel_cb is called or user calls
+ *        ethumb_client_disconnect().
+ */
+EAPI void
+ethumb_client_generate_cancel(Ethumb_Client *client, int id, Ethumb_Client_Generate_Cancel_Cb cancel_cb, const void *data, Eina_Free_Cb free_data)
+{
+   DBusMessage *msg;
+   struct _ethumb_pending_remove *pending;
+   Eina_List *l;
+   int found;
+   dbus_int32_t id32 = id;
+   EINA_SAFETY_ON_NULL_RETURN(client);
+   EINA_SAFETY_ON_FALSE_RETURN(id >= 0);
+
+   pending = calloc(1, sizeof(*pending));
+   pending->id = id;
+   pending->cancel_cb = cancel_cb;
+   pending->data = (void *)data;
+   pending->free_data = free_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_INT32, &id32, 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 != id32)
+         {
+            l = l->next;
+            continue;
+         }
+       client->pending_add = eina_list_remove_list(client->pending_add, l);
+       eina_stringshare_del(pending->file);
+       eina_stringshare_del(pending->key);
+       eina_stringshare_del(pending->thumb);
+       eina_stringshare_del(pending->thumb_key);
+       dbus_pending_call_cancel(pending->pending_call);
+       dbus_pending_call_unref(pending->pending_call);
+       if (pending->free_data)
+         pending->free_data(pending->data);
+       free(pending);
+       found = 1;
+       break;
+     }
+
+   if (found)
+     goto end;
+
+   l = client->pending_gen;
+   while (l)
+     {
+       struct _ethumb_pending_gen *pending = l->data;
+       if (pending->id != id32)
+         {
+            l = l->next;
+            continue;
+         }
+       client->pending_gen = eina_list_remove_list(client->pending_gen, l);
+       eina_stringshare_del(pending->file);
+       eina_stringshare_del(pending->key);
+       eina_stringshare_del(pending->thumb);
+       eina_stringshare_del(pending->thumb_key);
+       if (pending->free_data)
+         pending->free_data(pending->data);
+       free(pending);
+       found = 1;
+       break;
+     }
+
+end:
+   dbus_message_unref(msg);
+}
+
+static void
+_ethumb_client_queue_clear_cb(void *data, DBusMessage *msg __UNUSED__, DBusError *error __UNUSED__)
+{
+   Ethumb_Client *client = data;
+
+   client->pending_clear = NULL;
+}
+
+/**
+ * Ask server to cancel generation of all thumbnails.
+ *
+ * @param client client instance. Must @b not be @c NULL and client
+ *        must be connected (after connected_cb is called).
+ *
+ * @see ethumb_client_generate_cancel()
+ */
+EAPI void
+ethumb_client_generate_cancel_all(Ethumb_Client *client)
+{
+   DBusMessage *msg;
+   void *data;
+   EINA_SAFETY_ON_NULL_RETURN(client);
+
+   if (client->pending_clear)
+     return;
+
+   EINA_LIST_FREE(client->pending_add, data)
+     {
+       struct _ethumb_pending_add *pending = data;
+       eina_stringshare_del(pending->file);
+       eina_stringshare_del(pending->key);
+       eina_stringshare_del(pending->thumb);
+       eina_stringshare_del(pending->thumb_key);
+       dbus_pending_call_cancel(pending->pending_call);
+       dbus_pending_call_unref(pending->pending_call);
+       if (pending->free_data)
+         pending->free_data(pending->data);
+       free(pending);
+     }
+
+   EINA_LIST_FREE(client->pending_gen, data)
+     {
+       struct _ethumb_pending_gen *pending = data;
+       eina_stringshare_del(pending->file);
+       eina_stringshare_del(pending->key);
+       eina_stringshare_del(pending->thumb);
+       eina_stringshare_del(pending->thumb_key);
+       if (pending->free_data)
+         pending->free_data(pending->data);
+       free(pending);
+     }
+
+   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)
+{
+   if (tw) *tw = 0;
+   if (th) *th = 0;
+   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)
+{
+   if (x) *x = 0.0;
+   if (y) *y = 0.0;
+   EINA_SAFETY_ON_NULL_RETURN(client);
+
+   ethumb_thumb_crop_align_get(client->ethumb, x, y);
+}
+
+EAPI void
+ethumb_client_quality_set(Ethumb_Client *client, int quality)
+{
+   EINA_SAFETY_ON_NULL_RETURN(client);
+
+   ethumb_thumb_quality_set(client->ethumb, quality);
+}
+
+EAPI int
+ethumb_client_quality_get(const Ethumb_Client *client)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(client, 0);
+
+   return ethumb_thumb_quality_get(client->ethumb);
+}
+
+EAPI void
+ethumb_client_compress_set(Ethumb_Client *client, int compress)
+{
+   EINA_SAFETY_ON_NULL_RETURN(client);
+
+   ethumb_thumb_compress_set(client->ethumb, compress);
+}
+
+EAPI int
+ethumb_client_compress_get(const Ethumb_Client *client)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(client, 0);
+
+   return ethumb_thumb_compress_get(client->ethumb);
+}
+
+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_video_start_set(Ethumb_Client *client, float start)
+{
+   EINA_SAFETY_ON_NULL_RETURN(client);
+
+   client->ethumb_dirty = 1;
+   ethumb_video_start_set(client->ethumb, start);
+}
+
+EAPI void
+ethumb_client_video_interval_set(Ethumb_Client *client, float interval)
+{
+   EINA_SAFETY_ON_NULL_RETURN(client);
+
+   client->ethumb_dirty = 1;
+   ethumb_video_interval_set(client->ethumb, interval);
+}
+
+EAPI void
+ethumb_client_video_ntimes_set(Ethumb_Client *client, int ntimes)
+{
+   EINA_SAFETY_ON_NULL_RETURN(client);
+
+   client->ethumb_dirty = 1;
+   ethumb_video_ntimes_set(client->ethumb, ntimes);
+}
+
+EAPI void
+ethumb_client_video_fps_set(Ethumb_Client *client, int fps)
+{
+   EINA_SAFETY_ON_NULL_RETURN(client);
+
+   client->ethumb_dirty = 1;
+   ethumb_video_fps_set(client->ethumb, fps);
+}
+
+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);
+}
+
+/**
+ * Set source file to be thumbnailed.
+ *
+ * Calling this function has the side effect of resetting values set
+ * with ethumb_client_thumb_path_set() or auto-generated with
+ * ethumb_client_thumb_exists().
+ *
+ * @param client the client instance to use. Must @b not be @c
+ *        NULL. May be pending connected (can be called before @c
+ *        connected_cb)
+ * @param path the filesystem path to use. May be @c NULL.
+ * @param key the extra argument/key inside @a path to read image
+ *        from. This is only used for formats that allow multiple
+ *        resources in one file, like EET or Edje (group name).
+ *
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ */
+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);
+}
+
+/**
+ * Get values set with ethumb_client_file_get()
+ */
+EAPI void
+ethumb_client_file_get(Ethumb_Client *client, const char **path, const char **key)
+{
+   if (path) *path = NULL;
+   if (key) *key = NULL;
+   EINA_SAFETY_ON_NULL_RETURN(client);
+
+   ethumb_file_get(client->ethumb, path, key);
+}
+
+/**
+ * Reset previously set file to @c NULL.
+ *
+ * @param client the client instance to use. Must @b not be @c
+ *        NULL. May be pending connected (can be called before @c
+ *        connected_cb)
+ */
+EAPI void
+ethumb_client_file_free(Ethumb_Client *client)
+{
+   EINA_SAFETY_ON_NULL_RETURN(client);
+
+   ethumb_file_free(client->ethumb);
+}
+
+/**
+ * Set a defined path and key to store the thumbnail.
+ *
+ * If not explicitly given, the thumbnail path will be auto-generated
+ * by ethumb_client_thumb_exists() or server using configured
+ * parameters like size, aspect and category.
+ *
+ * Set these to @c NULL to forget previously given values. After
+ * ethumb_client_file_set() these values will be reset to @c NULL.
+ */
+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);
+}
+
+/**
+ * Get the configured thumbnail path.
+ *
+ * This returns the value set with ethumb_client_thumb_path_set() or
+ * auto-generated by ethumb_client_thumb_exists() if it was not set.
+ *
+ * @param path where to return configured path. May be @c NULL.  If
+ *        there was no path configured with
+ *        ethumb_client_thumb_path_set() and
+ *        ethumb_client_thumb_exists() was not called, then it will
+ *        probably return @c NULL. If not @c NULL, then it will be a
+ *        pointer to a stringshared instance, but @b no references are
+ *        added (do it with eina_stringshare_ref())!
+ * @param key where to return configured key. May be @c NULL.  If
+ *        there was no key configured with
+ *        ethumb_client_thumb_key_set() and
+ *        ethumb_client_thumb_exists() was not called, then it will
+ *        probably return @c NULL. If not @c NULL, then it will be a
+ *        pointer to a stringshared instance, but @b no references are
+ *        added (do it with eina_stringshare_ref())!
+ */
+EAPI void
+ethumb_client_thumb_path_get(Ethumb_Client *client, const char **path, const char **key)
+{
+   if (path) *path = NULL;
+   if (key) *key = NULL;
+   EINA_SAFETY_ON_NULL_RETURN(client);
+
+   ethumb_thumb_path_get(client->ethumb, path, key);
+}
+
+/**
+ * Checks whenever file already exists (locally!)
+ *
+ * This will check locally (not calling server) if thumbnail already
+ * exists or not, also calculating the thumbnail path. See
+ * ethumb_client_thumb_path_get(). Path must be configured with
+ * ethumb_client_file_set() before using it and the last set file will
+ * be used!
+ *
+ * @param client client instance. Must @b not be @c NULL and client
+ *        must be configured with ethumb_client_file_set().
+ *
+ * @return #EINA_TRUE if it exists, #EINA_FALSE otherwise.
+ */
+EAPI Eina_Bool
+ethumb_client_thumb_exists(Ethumb_Client *client)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(client, 0);
+
+   return ethumb_exists(client->ethumb);
+}
+
+/**
+ * Ask server to generate thumbnail.
+ *
+ * This process is asynchronous and will report back from main loop
+ * using @a generated_cb. One can cancel this request by calling
+ * ethumb_client_generate_cancel() or
+ * ethumb_client_generate_cancel_all(), but not that request might be
+ * processed by server already and no generated files will be removed
+ * if that is the case.
+ *
+ * This will not check if file already exists, this should be done by
+ * explicitly calling ethumb_client_thumb_exists(). That is, this
+ * function will override any existing thumbnail.
+ *
+ * @param client client instance. Must @b not be @c NULL and client
+ *        must be connected (after connected_cb is called).
+ * @param generated_cb function to report generation results.
+ * @param data context argument to give back to @a generated_cb. May
+ *        be @c NULL.
+ * @param data context to give back to @a generate_cb. May be @c
+ *        NULL.
+ * @param free_data used to release @a data resources after @a
+ *        generated_cb is called or user calls
+ *        ethumb_client_disconnect().
+ *
+ * @return identifier or -1 on error. If -1 is returned (error) then
+ *         @a free_data is @b not called!
+ *
+ * @see ethumb_client_connect()
+ * @see ethumb_client_file_set()
+ * @see ethumb_client_thumb_exists()
+ * @see ethumb_client_generate_cancel()
+ * @see ethumb_client_generate_cancel_all()
+ */
+EAPI int
+ethumb_client_generate(Ethumb_Client *client, Ethumb_Client_Generate_Cb generated_cb, const void *data, Eina_Free_Cb free_data)
+{
+   const char *file, *key, *thumb, *thumb_key;
+   int id;
+   EINA_SAFETY_ON_NULL_RETURN_VAL(client, -1);
+   EINA_SAFETY_ON_FALSE_RETURN_VAL(client->connected, -1);
+
+   ethumb_file_get(client->ethumb, &file, &key);
+   if (!file)
+     {
+       ERR("no file set.\n");
+       return -1;
+     }
+
+   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, free_data);
+
+   return id;
+}
diff --git a/src/lib/client/Ethumb_Client.h b/src/lib/client/Ethumb_Client.h
new file mode 100644 (file)
index 0000000..2035f6b
--- /dev/null
@@ -0,0 +1,94 @@
+#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 (*Ethumb_Client_Connect_Cb)(void *data, Ethumb_Client *client, Eina_Bool success);
+typedef void (*Ethumb_Client_Die_Cb)(void *data, Ethumb_Client *client);
+typedef void (*Ethumb_Client_Generate_Cb)(void *data, Ethumb_Client *client, int id, const char *file, const char *key, const char *thumb_path, const char *thumb_key, Eina_Bool success);
+typedef void (*Ethumb_Client_Generate_Cancel_Cb)(void *data, Eina_Bool success);
+
+EAPI int ethumb_client_init(void);
+EAPI int ethumb_client_shutdown(void);
+
+EAPI Ethumb_Client * ethumb_client_connect(Ethumb_Client_Connect_Cb connect_cb, const void *data, Eina_Free_Cb free_data);
+EAPI void ethumb_client_disconnect(Ethumb_Client *client);
+EAPI void ethumb_client_on_server_die_callback_set(Ethumb_Client *client, Ethumb_Client_Die_Cb server_die_cb, const void *data, Eina_Free_Cb free_data);
+
+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 void ethumb_client_quality_set(Ethumb_Client *client, int quality);
+EAPI int ethumb_client_quality_get(const Ethumb_Client *client);
+EAPI void ethumb_client_compress_set(Ethumb_Client *client, int compress);
+EAPI int ethumb_client_compress_get(const Ethumb_Client *client);
+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_video_start_set(Ethumb_Client *client, float start);
+EAPI void ethumb_client_video_interval_set(Ethumb_Client *client, float interval);
+EAPI void ethumb_client_video_ntimes_set(Ethumb_Client *client, int ntimes);
+EAPI void ethumb_client_video_fps_set(Ethumb_Client *client, int fps);
+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 int  ethumb_client_generate(Ethumb_Client *client, Ethumb_Client_Generate_Cb generated_cb, const void *data, Eina_Free_Cb free_data);
+EAPI void ethumb_client_generate_cancel(Ethumb_Client *client, int id, Ethumb_Client_Generate_Cancel_Cb cancel_cb, const void *data, Eina_Free_Cb free_data);
+EAPI void ethumb_client_generate_cancel_all(Ethumb_Client *client);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* __ETHUMB_CLIENT_H__ */
diff --git a/src/lib/client/Makefile.am b/src/lib/client/Makefile.am
new file mode 100644 (file)
index 0000000..542d347
--- /dev/null
@@ -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/src/lib/ethumb_private.h b/src/lib/ethumb_private.h
new file mode 100644 (file)
index 0000000..ed7937b
--- /dev/null
@@ -0,0 +1,49 @@
+#ifndef __ETHUMB_PRIVATE_H__
+#define __ETHUMB_PRIVATE_H__ 1
+
+#include <Ethumb.h>
+
+struct _Ethumb_Frame
+{
+   const char *file;
+   const char *group;
+   const char *swallow;
+   Evas_Object *edje;
+};
+
+struct _Ethumb
+{
+   const char *thumb_dir;
+   const char *category;
+   int tw, th;
+   int format;
+   int aspect;
+   float crop_x, crop_y;
+   int quality;
+   int compress;
+   const char *src_path;
+   const char *src_key;
+   const char *thumb_path;
+   const char *thumb_key;
+   int rw, rh;
+   struct
+     {
+       double start, time, interval;
+       int ntimes, fps;
+     } video;
+   struct
+     {
+       int page;
+     } document;
+   Ethumb_Frame *frame;
+   Ecore_Evas *ee, *sub_ee;
+   Evas *e, *sub_e;
+   Evas_Object *o, *img;
+   Ecore_Idler *finished_idler;
+   Ethumb_Generate_Cb finished_cb;
+   void *cb_data;
+   Eina_Free_Cb cb_data_free;
+   int cb_result;
+};
+
+#endif /* __ETHUMB_PRIVATE_H__ */
diff --git a/src/lib/md5.c b/src/lib/md5.c
new file mode 100644 (file)
index 0000000..4603efd
--- /dev/null
@@ -0,0 +1,247 @@
+/*
+ * This code implements the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest.  This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD5Context structure, pass it to MD5Init, call MD5Update as
+ * needed on buffers full of bytes, and then call MD5Final, which
+ * will fill a supplied 16-byte array with the digest.
+ */
+
+#include <string.h>            /* for memcpy() */
+#include "md5.h"
+
+#if (__BYTE_ORDER == 1234)
+#define byteReverse(buf, len)  /* Nothing */
+#else
+void byteReverse(unsigned char *buf, unsigned longs);
+
+/*
+ * Note: this code is harmless on little-endian machines.
+ */
+void byteReverse(unsigned char *buf, unsigned longs)
+{
+    uint32_t t;
+    do {
+       t = (uint32_t) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
+           ((unsigned) buf[1] << 8 | buf[0]);
+       *(uint32_t *) buf = t;
+       buf += 4;
+    } while (--longs);
+}
+#endif
+
+/*
+ * Start MD5 accumulation.  Set bit count to 0 and buffer to mysterious
+ * initialization constants.
+ */
+void MD5Init(MD5_CTX *ctx)
+{
+    ctx->buf[0] = 0x67452301;
+    ctx->buf[1] = 0xefcdab89;
+    ctx->buf[2] = 0x98badcfe;
+    ctx->buf[3] = 0x10325476;
+
+    ctx->bits[0] = 0;
+    ctx->bits[1] = 0;
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+void MD5Update(MD5_CTX *ctx, unsigned char const *buf, unsigned len)
+{
+    uint32_t t;
+
+    /* Update bitcount */
+
+    t = ctx->bits[0];
+    if ((ctx->bits[0] = t + ((uint32_t) len << 3)) < t)
+       ctx->bits[1]++;         /* Carry from low to high */
+    ctx->bits[1] += len >> 29;
+
+    t = (t >> 3) & 0x3f;       /* Bytes already in shsInfo->data */
+
+    /* Handle any leading odd-sized chunks */
+
+    if (t) {
+       unsigned char *p = (unsigned char *) ctx->in + t;
+
+       t = 64 - t;
+       if (len < t) {
+           memcpy(p, buf, len);
+           return;
+       }
+       memcpy(p, buf, t);
+       byteReverse(ctx->in, 16);
+       MD5Transform(ctx->buf, (uint32_t *) ctx->in);
+       buf += t;
+       len -= t;
+    }
+    /* Process data in 64-byte chunks */
+
+    while (len >= 64) {
+       memcpy(ctx->in, buf, 64);
+       byteReverse(ctx->in, 16);
+       MD5Transform(ctx->buf, (uint32_t *) ctx->in);
+       buf += 64;
+       len -= 64;
+    }
+
+    /* Handle any remaining bytes of data. */
+
+    memcpy(ctx->in, buf, len);
+}
+
+/*
+ * Final wrapup - pad to 64-byte boundary with the bit pattern 
+ * 1 0* (64-bit count of bits processed, MSB-first)
+ */
+void MD5Final(unsigned char digest[16], MD5_CTX *ctx)
+{
+    unsigned count;
+    unsigned char *p;
+
+    /* Compute number of bytes mod 64 */
+    count = (ctx->bits[0] >> 3) & 0x3F;
+
+    /* Set the first char of padding to 0x80.  This is safe since there is
+       always at least one byte free */
+    p = ctx->in + count;
+    *p++ = 0x80;
+
+    /* Bytes of padding needed to make 64 bytes */
+    count = 64 - 1 - count;
+
+    /* Pad out to 56 mod 64 */
+    if (count < 8) {
+       /* Two lots of padding:  Pad the first block to 64 bytes */
+       memset(p, 0, count);
+       byteReverse(ctx->in, 16);
+       MD5Transform(ctx->buf, (uint32_t *) ctx->in);
+
+       /* Now fill the next block with 56 bytes */
+       memset(ctx->in, 0, 56);
+    } else {
+       /* Pad block to 56 bytes */
+       memset(p, 0, count - 8);
+    }
+    byteReverse(ctx->in, 14);
+
+    /* Append length in bits and transform */
+    ((uint32_t *) ctx->in)[14] = ctx->bits[0];
+    ((uint32_t *) ctx->in)[15] = ctx->bits[1];
+
+    MD5Transform(ctx->buf, (uint32_t *) ctx->in);
+    byteReverse((unsigned char *) ctx->buf, 4);
+    memcpy(digest, ctx->buf, 16);
+    memset((char *) ctx, 0, sizeof(ctx));      /* In case it's sensitive */
+}
+
+/* The four core functions - F1 is optimized somewhat */
+
+/* #define F1(x, y, z) (x & y | ~x & z) */
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+/* This is the central step in the MD5 algorithm. */
+#define MD5STEP(f, w, x, y, z, data, s) \
+       ( w += f(x, y, z) + data,  w = w<<s | w>>(32-s),  w += x )
+
+/*
+ * The core of the MD5 algorithm, this alters an existing MD5 hash to
+ * reflect the addition of 16 longwords of new data.  MD5Update blocks
+ * the data and converts bytes into longwords for this routine.
+ */
+void MD5Transform(uint32_t buf[4], uint32_t const in[16])
+{
+    register uint32_t a, b, c, d;
+
+    a = buf[0];
+    b = buf[1];
+    c = buf[2];
+    d = buf[3];
+
+    MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
+    MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
+    MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
+    MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
+    MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
+    MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
+    MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
+    MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
+    MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
+    MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
+    MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
+    MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
+    MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
+    MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
+    MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
+    MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
+
+    MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
+    MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
+    MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
+    MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
+    MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
+    MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
+    MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
+    MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
+    MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
+    MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
+    MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
+    MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
+    MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
+    MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
+    MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
+    MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
+
+    MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
+    MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
+    MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
+    MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
+    MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
+    MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
+    MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
+    MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
+    MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
+    MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
+    MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
+    MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
+    MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
+    MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
+    MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
+    MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
+
+    MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
+    MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
+    MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
+    MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
+    MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
+    MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
+    MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
+    MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
+    MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
+    MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
+    MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
+    MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
+    MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
+    MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
+    MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
+    MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
+
+    buf[0] += a;
+    buf[1] += b;
+    buf[2] += c;
+    buf[3] += d;
+}
diff --git a/src/lib/md5.h b/src/lib/md5.h
new file mode 100644 (file)
index 0000000..348fcd6
--- /dev/null
@@ -0,0 +1,24 @@
+#ifndef _MD5_H_
+#define _MD5_H_
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#define MD5_HASHBYTES 16
+
+typedef struct MD5Context {
+       uint32_t buf[4];
+       uint32_t bits[2];
+       unsigned char in[64];
+} MD5_CTX;
+
+extern void   MD5Init(MD5_CTX *context);
+extern void   MD5Update(MD5_CTX *context,unsigned char const *buf,unsigned len);
+extern void   MD5Final(unsigned char digest[MD5_HASHBYTES], MD5_CTX *context);
+
+extern void   MD5Transform(uint32_t buf[4], uint32_t const in[16]);
+extern char  *MD5End(MD5_CTX *, char *);
+extern char  *MD5File(const char *, char *);
+extern char  *MD5Data (const unsigned char *, unsigned int, char *);
+
+#endif
diff --git a/src/plugins/Makefile.am b/src/plugins/Makefile.am
new file mode 100644 (file)
index 0000000..2e5d034
--- /dev/null
@@ -0,0 +1,15 @@
+MAINTAINERCLEANFILES = Makefile.in
+
+SUBDIRS =
+
+if USE_MODULE_EMOTION
+SUBDIRS += emotion
+endif
+
+if USE_MODULE_EPDF
+SUBDIRS += epdf
+endif
+
+DIST_SUBDIRS = \
+       emotion \
+       epdf
diff --git a/src/plugins/emotion/Makefile.am b/src/plugins/emotion/Makefile.am
new file mode 100644 (file)
index 0000000..3b0f5bf
--- /dev/null
@@ -0,0 +1,28 @@
+MAINTAINERCLEANFILES = Makefile.in
+
+EDJE_CC = edje_cc
+EDJE_FLAGS = -v
+
+filesdir = $(pluginsdir)/data
+files_DATA = emotion_template.edj
+
+EXTRA_DIST= \
+      template.edc
+
+AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_srcdir)/src/plugins/emotion \
+       @EVAS_CFLAGS@ @EINA_CFLAGS@ @EMOTION_CFLAGS@ @ECORE_CFLAGS@ \
+       @EDJE_CFLAGS@
+
+pkgdir = $(pluginsdir)
+pkg_LTLIBRARIES = emotion.la
+emotion_la_SOURCES = emotion.c
+emotion_la_DEPENDENCIES = $(top_builddir)/config.h
+emotion_la_LIBADD = $(top_builddir)/src/lib/libethumb.la \
+       @EVAS_LIBS@ @EINA_LIBS@ @EMOTION_LIBS@ @ECORE_LIBS@ @EDJE_LIBS@
+emotion_la_LDFLAGS = -module -avoid-version
+
+
+emotion_template.edj: Makefile $(EXTRADIST)
+       $(EDJE_CC) $(EDJE_FLAGS) \
+               $(top_srcdir)/src/plugins/emotion/template.edc \
+               $(top_builddir)/src/plugins/emotion/emotion_template.edj
diff --git a/src/plugins/emotion/emotion.c b/src/plugins/emotion/emotion.c
new file mode 100644 (file)
index 0000000..227d2ca
--- /dev/null
@@ -0,0 +1,365 @@
+#include "Ethumb.h"
+#include "Ethumb_Plugin.h"
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <Eina.h>
+#include <Eet.h>
+#include <Ecore_File.h>
+#include <Evas.h>
+#include <Edje.h>
+#include <Edje_Edit.h>
+#include <Emotion.h>
+
+struct _emotion_plugin
+{
+   int fps;
+   double ptotal, len, pi;
+   double total_time, tmp_time;
+   int pcount;
+   int frnum;
+   int first;
+   Eet_File *ef;
+   Evas_Object *video;
+   Ethumb *e;
+   int w, h;
+};
+
+static void
+_resize_movie(struct _emotion_plugin *_plugin)
+{
+   Ethumb *e = _plugin->e;
+   double ratio;
+   int w, h;
+   int fx, fy, fw, fh;
+
+   ratio = emotion_object_ratio_get(_plugin->video);
+   ethumb_calculate_aspect_from_ratio(e, ratio, &w, &h);
+   ethumb_calculate_fill_from_ratio(e, ratio, &fx, &fy, &fw, &fh);
+
+   _plugin->w = w;
+   _plugin->h = h;
+
+   ethumb_plugin_image_resize(e, _plugin->w, _plugin->h);
+
+   evas_object_resize(_plugin->video, fw, fh);
+   evas_object_move(_plugin->video, fx, fy);
+   emotion_object_audio_mute_set(_plugin->video, 1);
+}
+
+static void
+_frame_resized_cb(void *data, Evas_Object *o __UNUSED__, void *event_info __UNUSED__)
+{
+   _resize_movie(data);
+}
+
+static void
+_video_stopped_cb(void *data, Evas_Object *o __UNUSED__, void *event_info __UNUSED__)
+{
+   struct _emotion_plugin *_plugin = data;
+
+   _plugin->pi = 0;
+   _plugin->ptotal = 0;
+   _plugin->first = 0;
+   _plugin->total_time = _plugin->tmp_time;
+}
+
+static void
+_video_pos_set(struct _emotion_plugin *_plugin)
+{
+   double pos;
+   double interval;
+
+   pos = ethumb_video_start_get(_plugin->e);
+   interval = ethumb_video_interval_get(_plugin->e);
+   _plugin->len = emotion_object_play_length_get(_plugin->video);
+
+   if (_plugin->len > 0)
+     _plugin->first = 1;
+
+   if (pos <=0 || pos >= 1)
+     _plugin->pi = 0.2 * _plugin->len + _plugin->pcount *
+       _plugin->len * interval;
+   else
+     _plugin->pi = pos * _plugin->len + _plugin->pcount *
+       _plugin->len * interval;
+
+   emotion_object_position_set(_plugin->video, _plugin->pi);
+}
+
+static int
+_setup_thumbnail(struct _emotion_plugin *_plugin)
+{
+   char buf[4096];
+   Evas *evas;
+   Evas_Object *edje;
+   int i;
+   const char *thumb_path;
+
+   ethumb_thumb_path_get(_plugin->e, &thumb_path, NULL);
+   evas = ethumb_evas_get(_plugin->e);
+
+   if (!edje_file_group_exists(thumb_path, "movie/thumb"))
+     {
+       fprintf(stderr, "ERROR: no group 'movie/thumb' found.\n");
+       goto exit_error;
+     }
+
+   edje = edje_object_add(evas);
+   edje_object_file_set(edje, thumb_path, "movie/thumb");
+   if (!edje_object_part_exists(edje, "image"))
+     {
+       fprintf(stderr, "ERROR: no 'image' part found.\n");
+       evas_object_del(edje);
+       goto exit_error;
+     }
+   if (!edje_edit_program_exist(edje, "animate"))
+     {
+       fprintf(stderr, "ERROR: no 'animate' program found.\n");
+       evas_object_del(edje);
+       goto exit_error;
+     }
+
+   for (i = 0; i < _plugin->frnum; i++)
+     {
+       snprintf(buf, sizeof(buf), "images/%d", i);
+       edje_edit_image_data_add(edje, buf, i);
+       if (i == 0)
+         edje_edit_state_image_set(edje, "image", "default 0.00", buf);
+       else
+         edje_edit_state_tween_add(edje, "image", "default 0.00", buf);
+     }
+
+   edje_edit_program_transition_time_set(edje, "animate",
+                                        _plugin->total_time);
+   edje_edit_program_transition_time_set(edje, "animate_loop",
+                                        _plugin->total_time);
+   edje_edit_group_min_w_set(edje, _plugin->w);
+   edje_edit_group_max_w_set(edje, _plugin->w);
+   edje_edit_group_min_h_set(edje, _plugin->h);
+   edje_edit_group_max_h_set(edje, _plugin->h);
+   edje_edit_save(edje);
+
+   evas_object_del(edje);
+
+   return 1;
+
+exit_error:
+   return 0;
+}
+
+static void
+_finish_thumb_generation(struct _emotion_plugin *_plugin, int success)
+{
+   int r = 0;
+   evas_object_smart_callback_del(_plugin->video, "frame_resize",
+                                 _frame_resized_cb);
+   emotion_object_play_set(_plugin->video, 0);
+   evas_object_del(_plugin->video);
+   if (_plugin->ef)
+     eet_close(_plugin->ef);
+
+   if (success)
+     r = _setup_thumbnail(_plugin);
+
+   free(_plugin);
+   ethumb_finished_callback_call(_plugin->e, r);
+}
+
+static int
+_frame_grab_single(void *data)
+{
+   struct _emotion_plugin *_plugin = data;
+   Ethumb *e = _plugin->e;
+   double p;
+
+   if (_plugin->len <= 0)
+     {
+       _video_pos_set(_plugin);
+       return EINA_TRUE;
+     }
+
+   p = emotion_object_position_get(_plugin->video);
+   if (p < _plugin->pi)
+     return EINA_TRUE;
+
+   ethumb_image_save(e);
+
+   evas_object_smart_callback_del(_plugin->video, "frame_resize",
+                                 _frame_resized_cb);
+   emotion_object_play_set(_plugin->video, 0);
+   evas_object_del(_plugin->video);
+   free(_plugin);
+   ethumb_finished_callback_call(e, 1);
+
+   return EINA_FALSE;
+}
+
+static int
+_frame_grab(void *data)
+{
+   struct _emotion_plugin *_plugin = data;
+   Ethumb *e = _plugin->e;
+   char buf[4096];
+   const void *pixels;
+   double p;
+
+   if (_plugin->len <= 0)
+     {
+       _video_pos_set(_plugin);
+       return EINA_TRUE;
+     }
+
+   p = emotion_object_position_get(_plugin->video);
+   if (p < _plugin->pi)
+     return EINA_TRUE;
+
+   if (_plugin->first)
+     {
+       _plugin->pi = p;
+       _plugin->first = 0;
+     }
+
+   if (p > _plugin->pi + _plugin->ptotal)
+     {
+       _plugin->total_time += _plugin->tmp_time;
+       if (_plugin->pcount >= ethumb_video_ntimes_get(e))
+         {
+            _finish_thumb_generation(_plugin, EINA_TRUE);
+            return EINA_FALSE;
+         }
+       else
+         {
+            _plugin->pcount++;
+            _video_pos_set(_plugin);
+            return EINA_TRUE;
+         }
+     }
+
+   _plugin->tmp_time = p - _plugin->pi;
+
+   if (_plugin->ef)
+     {
+       Ecore_Evas *ee = ethumb_ecore_evas_get(e);
+       int quality, compress;
+
+       quality = ethumb_thumb_quality_get(e);
+       compress = ethumb_thumb_compress_get(e);
+
+       pixels = ecore_evas_buffer_pixels_get(ee);
+       snprintf(buf, sizeof(buf), "images/%d", _plugin->frnum);
+       eet_data_image_write(_plugin->ef, buf, pixels, _plugin->w, _plugin->h,
+                            0, compress, quality, quality);
+       _plugin->frnum++;
+     }
+
+   return EINA_TRUE;
+}
+
+static void
+_generate_animated_thumb(struct _emotion_plugin *_plugin)
+{
+   const char *thumb_path;
+   char *thumb_dir;
+   char buf[4096];
+   Ethumb *e = _plugin->e;
+
+   snprintf(buf, sizeof(buf), "%s/data/emotion_template.edj", PLUGINSDIR);
+   ethumb_thumb_path_get(e, &thumb_path, NULL);
+   thumb_dir = ecore_file_dir_get(thumb_path);
+   ecore_file_mkpath(thumb_dir);
+   free(thumb_dir);
+   ecore_file_cp(buf, thumb_path);
+   _plugin->ef = eet_open(thumb_path, EET_FILE_MODE_READ_WRITE);
+   if (!_plugin->ef)
+     {
+       fprintf(stderr, "ERROR: could not open '%s'\n", thumb_path);
+       _finish_thumb_generation(_plugin, 0);
+     }
+
+   ecore_timer_add(1.0 / ethumb_video_fps_get(e), _frame_grab, _plugin);
+}
+
+static void
+_generate_thumb(Ethumb *e)
+{
+   Evas_Object *o;
+   int r;
+   const char *file;
+   float start;
+   Ethumb_Thumb_Format f;
+   struct _emotion_plugin *_plugin = calloc(sizeof(struct _emotion_plugin), 1);
+
+   o = emotion_object_add(ethumb_evas_get(e));
+   r = emotion_object_init(o, "xine");
+   if (!r)
+     {
+       fprintf(stderr, "ERROR: could not start emotion using gstreamer"
+               " plugin.\n");
+       evas_object_del(o);
+       ethumb_finished_callback_call(e, 0);
+       free(_plugin);
+       return;
+     }
+
+   _plugin->video = o;
+
+   ethumb_file_get(e, &file, NULL);
+   start = ethumb_video_start_get(e);
+   f = ethumb_thumb_format_get(e);
+
+   emotion_object_file_set(o, file);
+
+   _plugin->video = o;
+   _plugin->e = e;
+
+   _plugin->ptotal = ethumb_video_time_get(e) / ethumb_video_ntimes_get(e);
+   _plugin->pcount = 1;
+
+   _resize_movie(_plugin);
+   evas_object_smart_callback_add(o, "frame_resize",
+                                 _frame_resized_cb, _plugin);
+   evas_object_smart_callback_add(o, "decode_stop",
+                                 _video_stopped_cb, _plugin);
+
+   if (f == ETHUMB_THUMB_EET)
+     {
+       _generate_animated_thumb(_plugin);
+     }
+   else
+     {
+       ecore_timer_add(0.1, _frame_grab_single, _plugin);
+     }
+
+   _video_pos_set(_plugin);
+   emotion_object_play_set(o, 1);
+   evas_object_show(o);
+}
+
+EAPI Ethumb_Plugin *
+ethumb_plugin_get(void)
+{
+   static const char *extensions[] = { "avi", "mp4", "ogv", "mov", NULL };
+   static Ethumb_Plugin plugin =
+     {
+       extensions,
+       _generate_thumb,
+     };
+
+   return &plugin;
+}
+
+static Eina_Bool
+_module_init(void)
+{
+   return EINA_TRUE;
+}
+
+static void
+_module_shutdown(void)
+{
+}
+
+EINA_MODULE_INIT(_module_init);
+EINA_MODULE_SHUTDOWN(_module_shutdown);
diff --git a/src/plugins/emotion/template.edc b/src/plugins/emotion/template.edc
new file mode 100644 (file)
index 0000000..4a30c3d
--- /dev/null
@@ -0,0 +1,43 @@
+collections {
+
+   group {
+      name: "movie/thumb";
+
+      parts {
+         part {
+            name: "image";
+            type: IMAGE;
+            mouse_events: 0;
+            description {
+               state: "default" 0.0;
+              fill.smooth: 0;
+               image.scale_hint: DYNAMIC;
+            }
+         }
+      }
+
+      programs {
+         program {
+            name: "animate";
+            signal: "animate";
+            action: STATE_SET "default" 0.0;
+            transition: LINEAR 3.0;
+            target: "image";
+         }
+         program {
+            name: "animate_loop";
+            signal: "animate_loop";
+            action: STATE_SET "default" 0.0;
+            transition: LINEAR 3.0;
+            target: "image";
+            after: "animate_loop";
+         }
+         program {
+            name: "animate_stop";
+            signal: "animate_stop";
+            action: ACTION_STOP;
+            target: "animate_loop";
+         }
+      }
+   }
+}
diff --git a/src/plugins/epdf/Makefile.am b/src/plugins/epdf/Makefile.am
new file mode 100644 (file)
index 0000000..db28d26
--- /dev/null
@@ -0,0 +1,12 @@
+MAINTAINERCLEANFILES = Makefile.in
+
+AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_srcdir)/src/plugins/epdf \
+       @EINA_CFLAGS@ @EVAS_CFLAGS@ @ECORE_CFLAGS@ @EPDF_CFLAGS@
+
+pkgdir = $(pluginsdir)
+pkg_LTLIBRARIES = epdf.la
+epdf_la_SOURCES = epdf.c
+epdf_la_DEPENDENCIES = $(top_builddir)/config.h
+epdf_la_LIBADD = $(top_builddir)/src/lib/libethumb.la \
+       @EINA_LIBS@ @EVAS_LIBS@ @ECORE_LIBS@ @EPDF_LIBS@
+epdf_la_LDFLAGS = -module -avoid-version
diff --git a/src/plugins/epdf/epdf.c b/src/plugins/epdf/epdf.c
new file mode 100644 (file)
index 0000000..217f98d
--- /dev/null
@@ -0,0 +1,95 @@
+#include "Ethumb.h"
+#include "Ethumb_Plugin.h"
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <Eina.h>
+#include <Evas.h>
+#include <Epdf.h>
+
+static void
+_generate_thumb(Ethumb *e)
+{
+   Epdf_Document *document;
+   Epdf_Page *page;
+   Evas_Object *o;
+   const char *src_path;
+   int w, h, ww, hh;
+   int fx, fy, fw, fh;
+   int npages;
+   int pagenum;
+
+   ethumb_file_get(e, &src_path, NULL);
+   document = epdf_document_new(src_path);
+   if (!document)
+     {
+       fprintf(stderr, "ERROR: could not read document: %s\n", src_path);
+       ethumb_finished_callback_call(e, 0);
+       return;
+     }
+
+   page = epdf_page_new(document);
+   if (!page)
+     {
+       fprintf(stderr, "ERROR: could not read document: %s\n", src_path);
+       epdf_document_delete(document);
+       ethumb_finished_callback_call(e, 0);
+       return;
+     }
+
+   npages = epdf_document_page_count_get(document);
+   pagenum = ethumb_document_page_get(e);
+   if (pagenum < npages)
+     epdf_page_page_set(page, pagenum);
+   epdf_page_size_get(page, &w, &h);
+   ethumb_calculate_aspect(e, w, h, &ww, &hh);
+   ethumb_plugin_image_resize(e, ww, hh);
+
+   o = evas_object_image_add(ethumb_evas_get(e));
+   epdf_page_render(page, o);
+   evas_object_resize(o, ww, hh);
+   evas_object_move(o, 0, 0);
+
+   ethumb_calculate_fill(e, w, h, &fx, &fy, &fw, &fh);
+   evas_object_image_fill_set(o, fx, fy, fw, fh);
+
+   evas_object_show(o);
+   ethumb_image_save(e);
+
+   evas_object_del(o);
+   epdf_page_delete(page);
+   epdf_document_delete(document);
+
+   ethumb_finished_callback_call(e, 1);
+}
+
+EAPI Ethumb_Plugin *
+ethumb_plugin_get(void)
+{
+   static const char *extensions[] = { "pdf", NULL };
+   static Ethumb_Plugin plugin =
+     {
+       extensions,
+       _generate_thumb,
+     };
+
+   return &plugin;
+}
+
+static Eina_Bool
+_module_init(void)
+{
+   epdf_init();
+
+   return EINA_TRUE;
+}
+
+static void
+_module_shutdown(void)
+{
+   epdf_shutdown();
+}
+
+EINA_MODULE_INIT(_module_init);
+EINA_MODULE_SHUTDOWN(_module_shutdown);
diff --git a/src/tests/Makefile.am b/src/tests/Makefile.am
new file mode 100644 (file)
index 0000000..fa6cfb6
--- /dev/null
@@ -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/src/tests/ethumb_dbus.c b/src/tests/ethumb_dbus.c
new file mode 100644 (file)
index 0000000..3357c6f
--- /dev/null
@@ -0,0 +1,123 @@
+/**
+ * @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 <antognolli@profusion.mobi>
+ */
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <dirent.h>
+#include <Ethumb.h>
+#include <Ethumb_Client.h>
+#include <Eina.h>
+#include <Ecore_Getopt.h>
+#include <Ecore.h>
+
+static void
+_on_server_die_cb(void *data __UNUSED__, Ethumb_Client *client __UNUSED__)
+{
+   ecore_main_loop_quit();
+}
+
+static void
+_queue_add_cb(void *data __UNUSED__, Ethumb_Client *client __UNUSED__, int id, const char *file, const char *key __UNUSED__, const char *thumb_path, const char *thumb_key __UNUSED__, Eina_Bool success)
+{
+   fprintf(stderr, ">>> %hhu file ready: %s; thumb ready: %s; id = %d\n", success, file, thumb_path, id);
+}
+
+static void
+_request_thumbnails(Ethumb_Client *client, void *data)
+{
+   const char *path = data;
+   DIR *dir;
+   struct dirent *de;
+   char buf[PATH_MAX];
+
+   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, NULL);
+     }
+
+   closedir(dir);
+}
+
+static void
+_connect_cb(void *data, Ethumb_Client *client, Eina_Bool success)
+{
+   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 <images directory>\n");
+       return -2;
+     }
+
+   ethumb_client_init();
+   client = ethumb_client_connect(_connect_cb, argv[1], NULL);
+   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, NULL);
+
+   fprintf(stderr, "*** debug\n");
+   ecore_main_loop_begin();
+
+   ethumb_client_disconnect(client);
+
+   ethumb_client_shutdown();
+
+   return 0;
+}