Initial import of an arbitrary tarball... need to replace this with
authorRusty Lynch <rusty.lynch@intel.com>
Tue, 20 Nov 2012 22:33:10 +0000 (14:33 -0800)
committerRusty Lynch <rusty.lynch@intel.com>
Tue, 20 Nov 2012 22:33:10 +0000 (14:33 -0800)
a proper git tree once one is located.

62 files changed:
.gitignore [new file with mode: 0644]
AUTHORS [new file with mode: 0644]
COPYING [new file with mode: 0644]
Makefile.am [new file with mode: 0644]
README [new file with mode: 0644]
autogen.sh [new file with mode: 0755]
configure.ac [new file with mode: 0644]
doc/Doxyfile.in [new file with mode: 0644]
doc/Makefile.am [new file with mode: 0644]
doc/e.css [new file with mode: 0644]
doc/examples.dox [new file with mode: 0644]
doc/foot.html [new file with mode: 0644]
doc/head.html [new file with mode: 0644]
doc/images/e.png [new file with mode: 0644]
doc/images/edoxy.css [new file with mode: 0644]
doc/images/foot_bg.png [new file with mode: 0644]
doc/images/head_bg.png [new file with mode: 0644]
doc/images/menu_bg.png [new file with mode: 0644]
doc/images/menu_bg_current.png [new file with mode: 0644]
doc/images/menu_bg_hover.png [new file with mode: 0644]
doc/images/menu_bg_last.png [new file with mode: 0644]
doc/images/menu_bg_unsel.png [new file with mode: 0644]
edbus2.pc.in [new file with mode: 0644]
m4/ac_attribute.m4 [new file with mode: 0644]
m4/ac_valist.m4 [new file with mode: 0644]
m4/efl_compiler_flag.m4 [new file with mode: 0644]
m4/efl_doxygen.m4 [new file with mode: 0644]
m4/efl_examples.m4 [new file with mode: 0644]
packaging/edbus.spec [new file with mode: 0644]
src/examples/banshee.c [new file with mode: 0644]
src/examples/client.c [new file with mode: 0644]
src/examples/complex_types.c [new file with mode: 0644]
src/examples/complex_types_client_eina_value.c [new file with mode: 0644]
src/examples/complex_types_server.c [new file with mode: 0644]
src/examples/connman-list-services.c [new file with mode: 0644]
src/examples/ofono-dial.c [new file with mode: 0644]
src/examples/server.c [new file with mode: 0644]
src/examples/simple-signal-emit.c [new file with mode: 0644]
src/lib/EDBus.h [new file with mode: 0644]
src/lib/edbus_connection.h [new file with mode: 0644]
src/lib/edbus_core.c [new file with mode: 0644]
src/lib/edbus_freedesktop.c [new file with mode: 0644]
src/lib/edbus_freedesktop.h [new file with mode: 0644]
src/lib/edbus_message.c [new file with mode: 0644]
src/lib/edbus_message.h [new file with mode: 0644]
src/lib/edbus_message_eina_value.h [new file with mode: 0644]
src/lib/edbus_message_from_eina_value.c [new file with mode: 0644]
src/lib/edbus_message_helper.c [new file with mode: 0644]
src/lib/edbus_message_helper.h [new file with mode: 0644]
src/lib/edbus_message_to_eina_value.c [new file with mode: 0644]
src/lib/edbus_object.c [new file with mode: 0644]
src/lib/edbus_object.h [new file with mode: 0644]
src/lib/edbus_pending.c [new file with mode: 0644]
src/lib/edbus_pending.h [new file with mode: 0644]
src/lib/edbus_private.h [new file with mode: 0644]
src/lib/edbus_private_types.h [new file with mode: 0644]
src/lib/edbus_proxy.c [new file with mode: 0644]
src/lib/edbus_proxy.h [new file with mode: 0644]
src/lib/edbus_service.c [new file with mode: 0644]
src/lib/edbus_service.h [new file with mode: 0644]
src/lib/edbus_signal_handler.c [new file with mode: 0644]
src/lib/edbus_signal_handler.h [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..eaa83e9
--- /dev/null
@@ -0,0 +1,45 @@
+*.o
+*.lo
+*~
+.libs
+.deps
+.dirstamp
+aclocal.m4
+autom4te.cache/
+compile
+config.guess
+config.h
+config.h.in
+config.log
+config.status
+config.sub
+configure
+depcomp
+install-sh
+libtool
+ltmain.sh
+m4/libtool.m4
+m4/ltoptions.m4
+m4/ltsugar.m4
+m4/ltversion.m4
+m4/lt~obsolete.m4
+Makefile
+Makefile.in
+missing
+stamp-h1
+edbus-*.tar.*
+edbus2.pc
+libedbus2.la
+src/examples/connman-list-services
+src/examples/ofono-dial
+src/examples/banshee
+src/examples/complex_types
+src/examples/complex_types_server
+src/examples/server
+src/examples/simple-signal-emit
+src/examples/client
+src/examples/complex_types_client_eina_value
+doc/Doxyfile
+doc/html/
+doc/latex/
+doc/man/
diff --git a/AUTHORS b/AUTHORS
new file mode 100644 (file)
index 0000000..0306d25
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,4 @@
+Gustavo Sverzut Barbieri <barbieri@profusion.mobi>
+José Roberto de Souza <zehortigoza@profusion.mobi>
+Leandro Pereira <leandro@profusion.mobi>
+Lucas De Marchi <lucas.demarchi@profusion.mobi>
diff --git a/COPYING b/COPYING
new file mode 100644 (file)
index 0000000..d63a526
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,492 @@
+Copyright notice for EDBus:
+
+Copyright (C) 2012 ProFUSION embedded systems, Samsung Electronics and
+various contributors (see AUTHORS)
+
+This library is free software; you can redistribute it and/or modify it
+under the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; version 2.1 of the License.
+
+This library is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
+details.
+
+Below is a copy of the GNU Lesser General Public License that is distributed
+along with this library. If you do not have a copy below, write to the Free
+Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301  USA
+\f
+                 GNU LESSER GENERAL PUBLIC LICENSE
+                      Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL.  It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it.  You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+  When we speak of free software, we are referring to freedom of use,
+not price.  Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+  To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights.  These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  To protect each distributor, we want to make it very clear that
+there is no warranty for the free library.  Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+\f
+  Finally, software patents pose a constant threat to the existence of
+any free program.  We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder.  Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+  Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License.  This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License.  We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+  When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library.  The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom.  The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+  We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License.  It also provides other free software developers Less
+of an advantage over competing non-free programs.  These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries.  However, the Lesser license provides advantages in certain
+special circumstances.
+
+  For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard.  To achieve this, non-free programs must be
+allowed to use the library.  A more frequent case is that a free
+library does the same job as widely used non-free libraries.  In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+  In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software.  For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+  Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+\f
+                 GNU LESSER GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+\f
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent modules,
+and to copy and distribute the resulting executable under terms of your
+choice, provided that you also meet, for each linked independent module,
+the terms and conditions of the license of that module. An independent
+module is a module which is not derived from or based on this library.
+If you modify this library, you may extend this exception to your version
+of the library, but you are not obliged to do so. If you do not wish to
+do so, delete this exception statement from your version.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+\f
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+\f
+  6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Use a suitable shared library mechanism for linking with the
+    Library.  A suitable mechanism is one that (1) uses at run time a
+    copy of the library already present on the user's computer system,
+    rather than copying library functions into the executable, and (2)
+    will operate properly with a modified version of the library, if
+    the user installs one, as long as the modified version is
+    interface-compatible with the version that the work was made with.
+
+    c) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    d) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    e) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+\f
+  7. 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 not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+\f
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the 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
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+\f
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+                           NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
diff --git a/Makefile.am b/Makefile.am
new file mode 100644 (file)
index 0000000..1c7df4d
--- /dev/null
@@ -0,0 +1,140 @@
+ACLOCAL_AMFLAGS = -I m4
+CLEANFILES =
+MAINTAINERCLEANFILES =
+EXTRA_DIST =
+
+SUBDIRS = doc
+
+AM_MAKEFLAGS = --no-print-directory
+AM_CFLAGS = \
+       -include $(top_builddir)/config.h \
+       -I$(top_srcdir)/src/lib \
+       @ECORE_CFLAGS@ \
+       @DBUS_CFLAGS@
+
+AM_CPPFLAGS = -DEFL_EDBUS_BUILD=1
+
+includedir = @includedir@/edbus-@VMAJ@/
+
+SED_PROCESS = \
+       $(AM_V_GEN)$(MKDIR_P) $(dir $@) && $(SED) \
+       -e 's,@VERSION\@,$(VERSION),g' \
+       -e 's,@prefix\@,$(prefix),g' \
+       -e 's,@exec_prefix\@,$(exec_prefix),g' \
+       -e 's,@libdir\@,$(libdir),g' \
+       -e 's,@includedir\@,$(includedir),g' \
+       < $< > $@ || rm $@
+
+%.pc: %.pc.in Makefile
+       $(SED_PROCESS)
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = edbus2.pc
+CLEANFILES += edbus2.pc
+EXTRA_DIST += edbus2.pc.in
+
+EXTRA_DIST += \
+       README \
+       AUTHORS \
+       COPYING \
+       m4/efl_doxygen.m4 \
+       m4/efl_compiler_flag.m4
+
+
+MAINTAINERCLEANFILES += \
+       aclocal.m4 \
+       compile \
+       config.guess \
+       config.h.in \
+       config.sub \
+       configure \
+       depcomp \
+       install-sh \
+       ltmain.sh \
+       Makefile.in \
+       missing \
+       mkinstalldirs
+
+lib_LTLIBRARIES = libedbus2.la
+
+include_HEADERS = \
+       src/lib/EDBus.h \
+       src/lib/edbus_connection.h \
+       src/lib/edbus_freedesktop.h \
+       src/lib/edbus_message.h \
+       src/lib/edbus_object.h \
+       src/lib/edbus_pending.h \
+       src/lib/edbus_proxy.h \
+       src/lib/edbus_service.h \
+       src/lib/edbus_signal_handler.h \
+       src/lib/edbus_message_helper.h \
+       src/lib/edbus_message_eina_value.h
+
+libedbus2_la_LIBADD = @ECORE_LIBS@ @DBUS_LIBS@
+libedbus2_la_SOURCES = \
+       src/lib/edbus_private.h \
+       src/lib/edbus_private_types.h \
+       src/lib/edbus_proxy.c \
+       src/lib/edbus_core.c \
+       src/lib/edbus_message.c \
+       src/lib/edbus_object.c \
+       src/lib/edbus_pending.c \
+       src/lib/edbus_freedesktop.c \
+       src/lib/edbus_service.c \
+       src/lib/edbus_signal_handler.c \
+       src/lib/edbus_message_helper.c \
+       src/lib/edbus_message_to_eina_value.c \
+       src/lib/edbus_message_from_eina_value.c
+
+EXAMPLES = \
+       src/examples/connman-list-services \
+       src/examples/ofono-dial \
+       src/examples/banshee \
+       src/examples/complex_types \
+       src/examples/complex_types_server \
+       src/examples/server \
+       src/examples/client \
+       src/examples/simple-signal-emit \
+       src/examples/complex_types_client_eina_value
+
+EXAMPLES_LIBS = libedbus2.la @ECORE_LIBS@
+
+EXTRA_PROGRAMS = $(EXAMPLES)
+
+src_examples_connman_list_services_SOURCES = \
+       src/examples/connman-list-services.c
+src_examples_connman_list_services_LDADD = $(EXAMPLES_LIBS)
+
+src_examples_ofono_dial_SOURCES = src/examples/ofono-dial.c
+src_examples_ofono_dial_LDADD = $(EXAMPLES_LIBS)
+
+src_examples_banshee_SOURCES = src/examples/banshee.c
+src_examples_banshee_LDADD = $(EXAMPLES_LIBS)
+
+src_examples_complex_types_SOURCES = src/examples/complex_types.c
+src_examples_complex_types_LDADD = $(EXAMPLES_LIBS)
+
+src_examples_complex_types_server_SOURCES = src/examples/complex_types_server.c
+src_examples_complex_types_server_LDADD = $(EXAMPLES_LIBS)
+
+src_examples_server_SOURCES = src/examples/server.c
+src_examples_server_LDADD = $(EXAMPLES_LIBS)
+
+src_examples_client_SOURCES = src/examples/client.c
+src_examples_client_LDADD = $(EXAMPLES_LIBS)
+
+src_examples_simple_signal_emit_SOURCES = src/examples/simple-signal-emit.c
+src_examples_simple_signal_emit_LDADD = $(EXAMPLES_LIBS)
+
+src_examples_complex_types_client_eina_value_SOURCES = src/examples/complex_types_client_eina_value.c
+src_examples_complex_types_client_eina_value_LDADD = $(EXAMPLES_LIBS)
+
+.PHONY: doc examples
+
+examples: $(EXAMPLES)
+
+# Documentation
+
+doc:
+       @echo "entering doc/"
+       make -C doc doc
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..50d6d18
--- /dev/null
+++ b/README
@@ -0,0 +1,55 @@
+ABOUT:
+-----
+
+EDBus provides easy access to D-Bus from EFL applications.
+
+EDBus allows connecting to both system and session buses acting as
+both client and service roles.
+
+Many official D-Bus specifications and interfaces are supported, namely:
+
+        - org.freedesktop.DBus.Peer: full support (Ping and GetMachineId).
+        - org.freedesktop.DBus.Introspectable: full support.
+        - org.freedesktop.DBus.Properties: full support.
+        - org.freedesktop.DBus.ObjectManager: partial support (under dev).
+
+One can create client-side objects using the low-level methods from
+EDBus_Connection and EDBus_Object, or go high level with
+EDBus_Proxy.
+
+
+RELATION TO OLD E_DBUS:
+-----------------------
+
+This is a replacement for old library "e_dbus". Its main purpose is to
+fix some core bugs and completely encapsulating D-Bus without exposing
+libdbus to end-user. One day libdbus may be completely removed as a
+dependency.
+
+
+REQUIREMENTS:
+-------------
+
+        - libdbus-1
+        - eina >= 1.7
+        - ecore >= 1.7
+
+
+CONTACT:
+--------
+
+Bugs, questions, ideas and comments should be addressed to:
+
+        enlightenment-devel@lists.sourceforge.net
+
+
+
+COMPILING AND INSTALLING:
+-------------------------
+
+Standard autotools process:
+
+        ./autogen.sh    # if trying development
+        ./configure     # if running from release tarball
+        make
+        sudo make install
diff --git a/autogen.sh b/autogen.sh
new file mode 100755 (executable)
index 0000000..fcad521
--- /dev/null
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+autoreconf -f -i
+
+if [ -z "$NOCONFIGURE" ]; then
+    exec ./configure "$@"
+fi
diff --git a/configure.ac b/configure.ac
new file mode 100644 (file)
index 0000000..e203746
--- /dev/null
@@ -0,0 +1,114 @@
+##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
+##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
+m4_define([v_maj], [1])
+m4_define([v_min], [7])
+m4_define([v_mic], [99])
+m4_define([v_rev], m4_esyscmd([(svnversion "${SVN_REPO_PATH:-.}" | grep -v '\(export\|Unversioned directory\)' || echo 0) | awk -F : '{printf("%s\n", $1);}' | tr -d ' :MSP\n']))
+m4_if(v_rev, [0], [m4_define([v_rev], m4_esyscmd([git log 2> /dev/null | (grep -m1 git-svn-id || echo 0) | sed -e 's/.*@\([0-9]*\).*/\1/' | tr -d '\n']))])
+##--   When released, remove the dnl on the below line
+dnl m4_undefine([v_rev])
+##--   When doing snapshots - change soname. remove dnl on below line
+dnl m4_define([relname], [ver-pre-svn-07])
+dnl m4_define([v_rel], [-release relname])
+##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
+m4_ifdef([v_rev], [m4_define([v_ver], [v_maj.v_min.v_mic.v_rev])],
+[m4_define([v_ver], [v_maj.v_min.v_mic])])
+m4_define([lt_cur], m4_eval(v_maj + v_min))
+m4_define([lt_rev], v_mic)
+m4_define([lt_age], v_min)
+##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
+##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
+
+AC_INIT([edbus], [v_ver], [enlightenment-devel@lists.sourceforge.net])
+AC_PREREQ([2.60])
+
+AM_INIT_AUTOMAKE([foreign subdir-objects])
+AM_CONFIG_HEADER([config.h])
+AC_CONFIG_MACRO_DIR([m4])
+
+m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
+
+PKG_PROG_PKG_CONFIG
+
+EFL_COMPILER_FLAG([-Wall])
+EFL_COMPILER_FLAG([-Wextra])
+EFL_COMPILER_FLAG([-Wshadow])
+EFL_COMPILER_FLAG([-Wno-unused-parameter])
+EFL_COMPILER_FLAG([-Wvla])
+EFL_COMPILER_FLAG([-Wundef])
+EFL_COMPILER_FLAG([-Wformat=2])
+EFL_COMPILER_FLAG([-Wlogical-op])
+EFL_COMPILER_FLAG([-Wsign-compare])
+EFL_COMPILER_FLAG([-Wformat-security])
+EFL_COMPILER_FLAG([-Wmissing-include-dirs])
+EFL_COMPILER_FLAG([-Wformat-nonliteral])
+EFL_COMPILER_FLAG([-Wold-style-definition])
+EFL_COMPILER_FLAG([-Wpointer-arith])
+EFL_COMPILER_FLAG([-Winit-self])
+EFL_COMPILER_FLAG([-Wdeclaration-after-statement])
+EFL_COMPILER_FLAG([-Wmissing-declarations])
+EFL_COMPILER_FLAG([-Wmissing-noreturn])
+EFL_COMPILER_FLAG([-Wendif-labels])
+EFL_COMPILER_FLAG([-Wstrict-aliasing=2])
+EFL_COMPILER_FLAG([-Wwrite-strings])
+EFL_COMPILER_FLAG([-Wno-long-long])
+EFL_COMPILER_FLAG([-Wno-overlength-strings])
+EFL_COMPILER_FLAG([-Wno-missing-field-initializers])
+EFL_COMPILER_FLAG([-Wno-nested-externs])
+EFL_COMPILER_FLAG([-Wchar-subscripts])
+EFL_COMPILER_FLAG([-Wtype-limits])
+EFL_COMPILER_FLAG([-Wuninitialized])
+
+AC_LANG_C
+
+AC_PROG_CC
+AC_PROG_MKDIR_P
+AM_PROG_CC_C_O
+AC_C___ATTRIBUTE__
+AC_C_VA_LIST_AS_ARRAY
+
+AC_DISABLE_STATIC
+define([AC_LIBTOOL_LANG_CXX_CONFIG], [:])dnl
+define([AC_LIBTOOL_LANG_F77_CONFIG], [:])dnl
+AC_PROG_LIBTOOL
+
+# doxygen program for documentation building
+EFL_CHECK_DOXYGEN([build_doc="yes"], [build_doc="no"])
+
+PKG_CHECK_MODULES([EINA], [eina >= 1.7.0])
+PKG_CHECK_MODULES([ECORE], [ecore])
+PKG_CHECK_MODULES([DBUS], [dbus-1])
+
+with_max_log_level="EINA_LOG_LEVEL_DBG"
+AC_ARG_WITH(maximum-log-level,
+   [AC_HELP_STRING([--with-maximum-log-level=NUMBER],
+                   [limit log level, any call to EINA_LOG() with values greater than this will be compiled out, ignoring runtime settings, but saving function calls.])],
+   [with_max_log_level="${withval}"], [:])
+AC_DEFINE_UNQUOTED(EINA_LOG_LEVEL_MAXIMUM, ${with_max_log_level}, [if set, logging is limited to this amount.])
+
+##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
+##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
+m4_ifdef([v_rev], , [m4_define([v_rev], [0])])
+m4_ifdef([v_rel], , [m4_define([v_rel], [])])
+AC_DEFINE_UNQUOTED(VMAJ, [v_maj], [Major version])
+AC_DEFINE_UNQUOTED(VMIN, [v_min], [Minor version])
+AC_DEFINE_UNQUOTED(VMIC, [v_mic], [Micro version])
+AC_DEFINE_UNQUOTED(VREV, [v_rev], [Revison])
+version_info="lt_cur:lt_rev:lt_age"
+release_info="v_rel"
+AC_SUBST(version_info)
+AC_SUBST(release_info)
+##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
+##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##
+VMAJ=v_maj
+VMIN=v_min
+AC_SUBST(VMAJ)
+AC_SUBST(VMIN)
+
+AC_CONFIG_FILES([
+Makefile
+doc/Makefile
+doc/Doxyfile
+])
+
+AC_OUTPUT
diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in
new file mode 100644 (file)
index 0000000..12ce744
--- /dev/null
@@ -0,0 +1,224 @@
+DOXYFILE_ENCODING      = UTF-8
+PROJECT_NAME           = EDBus
+PROJECT_NUMBER         =
+OUTPUT_DIRECTORY       = .
+CREATE_SUBDIRS         = NO
+OUTPUT_LANGUAGE        = English
+BRIEF_MEMBER_DESC      = YES
+REPEAT_BRIEF           = YES
+ABBREVIATE_BRIEF       =
+ALWAYS_DETAILED_SEC    = NO
+INLINE_INHERITED_MEMB  = NO
+FULL_PATH_NAMES        = NO
+STRIP_FROM_PATH        =
+STRIP_FROM_INC_PATH    =
+SHORT_NAMES            = NO
+JAVADOC_AUTOBRIEF      = YES
+QT_AUTOBRIEF           = NO
+MULTILINE_CPP_IS_BRIEF = NO
+INHERIT_DOCS           = YES
+SEPARATE_MEMBER_PAGES  = NO
+TAB_SIZE               = 2
+ALIASES                =
+OPTIMIZE_OUTPUT_FOR_C  = YES
+OPTIMIZE_OUTPUT_JAVA   = NO
+OPTIMIZE_FOR_FORTRAN   = NO
+OPTIMIZE_OUTPUT_VHDL   = NO
+EXTENSION_MAPPING      =
+BUILTIN_STL_SUPPORT    = NO
+CPP_CLI_SUPPORT        = NO
+SIP_SUPPORT            = NO
+IDL_PROPERTY_SUPPORT   = YES
+DISTRIBUTE_GROUP_DOC   = NO
+SUBGROUPING            = YES
+TYPEDEF_HIDES_STRUCT   = NO
+SYMBOL_CACHE_SIZE      = 0
+EXTRACT_ALL            = NO
+EXTRACT_PRIVATE        = NO
+EXTRACT_STATIC         = NO
+EXTRACT_LOCAL_CLASSES  = NO
+EXTRACT_LOCAL_METHODS  = NO
+EXTRACT_ANON_NSPACES   = NO
+HIDE_UNDOC_MEMBERS     = NO
+HIDE_UNDOC_CLASSES     = YES
+HIDE_FRIEND_COMPOUNDS  = YES
+HIDE_IN_BODY_DOCS      = NO
+INTERNAL_DOCS          = NO
+CASE_SENSE_NAMES       = YES
+HIDE_SCOPE_NAMES       = NO
+SHOW_INCLUDE_FILES     = NO
+FORCE_LOCAL_INCLUDES   = NO
+INLINE_INFO            = YES
+SORT_MEMBER_DOCS       = YES
+SORT_MEMBERS_CTORS_1ST = NO
+SORT_GROUP_NAMES       = NO
+SORT_BY_SCOPE_NAME     = NO
+GENERATE_TODOLIST      = YES
+GENERATE_TESTLIST      = YES
+GENERATE_BUGLIST       = YES
+GENERATE_DEPRECATEDLIST= YES
+ENABLED_SECTIONS       =
+MAX_INITIALIZER_LINES  = 30
+SHOW_USED_FILES        = NO
+SHOW_FILES             = YES
+SHOW_NAMESPACES        = YES
+FILE_VERSION_FILTER    =
+LAYOUT_FILE            =
+QUIET                  = YES
+WARNINGS               = YES
+WARN_IF_UNDOCUMENTED   = YES
+WARN_IF_DOC_ERROR      = YES
+WARN_NO_PARAMDOC       = YES
+WARN_FORMAT            = "$file:$line: $text"
+WARN_LOGFILE           =
+INPUT                  = @top_srcdir@/src/lib \
+                         @top_srcdir@/doc/examples.dox
+INPUT_ENCODING         = UTF-8
+FILE_PATTERNS          =
+RECURSIVE              = YES
+EXCLUDE                = 
+EXCLUDE_SYMLINKS       = NO
+EXCLUDE_PATTERNS       = 
+EXCLUDE_SYMBOLS        = 
+EXAMPLE_PATH           = @top_srcdir@/src/examples/
+EXAMPLE_PATTERNS       =
+EXAMPLE_RECURSIVE      = YES
+IMAGE_PATH             = @top_srcdir@/doc/images/
+INPUT_FILTER           =
+FILTER_PATTERNS        =
+FILTER_SOURCE_FILES    = NO
+SOURCE_BROWSER         = NO
+INLINE_SOURCES         = NO
+STRIP_CODE_COMMENTS    = YES
+REFERENCED_BY_RELATION = YES
+REFERENCES_RELATION    = YES
+REFERENCES_LINK_SOURCE = YES
+USE_HTAGS              = NO
+VERBATIM_HEADERS       = NO
+ALPHABETICAL_INDEX     = YES
+COLS_IN_ALPHA_INDEX    = 2
+IGNORE_PREFIX          = EDBUS_ edbus_
+GENERATE_HTML          = YES
+HTML_OUTPUT            = html
+HTML_FILE_EXTENSION    = .html
+HTML_HEADER            = @srcdir@/head.html
+HTML_FOOTER            = @srcdir@/foot.html
+HTML_STYLESHEET        = @srcdir@/e.css
+HTML_COLORSTYLE_HUE    = 220
+HTML_COLORSTYLE_SAT    = 100
+HTML_COLORSTYLE_GAMMA  = 80
+HTML_TIMESTAMP         = YES
+HTML_DYNAMIC_SECTIONS  = NO
+GENERATE_DOCSET        = NO
+DOCSET_FEEDNAME        = "Doxygen generated docs"
+DOCSET_BUNDLE_ID       = org.doxygen.Project
+DOCSET_PUBLISHER_ID    = org.doxygen.Publisher
+DOCSET_PUBLISHER_NAME  = Publisher
+GENERATE_HTMLHELP      = NO
+CHM_FILE               =
+HHC_LOCATION           =
+GENERATE_CHI           = NO
+CHM_INDEX_ENCODING     =
+BINARY_TOC             = NO
+TOC_EXPAND             = NO
+GENERATE_QHP           = NO
+QCH_FILE               =
+QHP_NAMESPACE          = org.doxygen.Project
+QHP_VIRTUAL_FOLDER     = doc
+QHP_CUST_FILTER_NAME   =
+QHP_CUST_FILTER_ATTRS  =
+QHP_SECT_FILTER_ATTRS  =
+QHG_LOCATION           =
+GENERATE_ECLIPSEHELP   = NO
+ECLIPSE_DOC_ID         = org.doxygen.Project
+DISABLE_INDEX          = YES
+ENUM_VALUES_PER_LINE   = 1
+GENERATE_TREEVIEW      = NO
+TREEVIEW_WIDTH         = 250
+EXT_LINKS_IN_WINDOW    = NO
+FORMULA_FONTSIZE       = 10
+FORMULA_TRANSPARENT    = YES
+SEARCHENGINE           = NO
+SERVER_BASED_SEARCH    = NO
+GENERATE_LATEX         = YES
+LATEX_OUTPUT           = latex
+LATEX_CMD_NAME         = latex
+MAKEINDEX_CMD_NAME     = makeindex
+COMPACT_LATEX          = NO
+PAPER_TYPE             = a4wide
+EXTRA_PACKAGES         =
+LATEX_HEADER           =
+PDF_HYPERLINKS         = YES
+USE_PDFLATEX           = NO
+LATEX_BATCHMODE        = NO
+LATEX_HIDE_INDICES     = NO
+LATEX_SOURCE_CODE      = NO
+GENERATE_RTF           = NO
+RTF_OUTPUT             = rtf
+COMPACT_RTF            = NO
+RTF_HYPERLINKS         = NO
+RTF_STYLESHEET_FILE    =
+RTF_EXTENSIONS_FILE    =
+GENERATE_MAN           = YES
+MAN_OUTPUT             = man
+MAN_EXTENSION          = .3
+MAN_LINKS              = YES
+GENERATE_XML           = NO
+XML_OUTPUT             = xml
+XML_SCHEMA             =
+XML_DTD                =
+XML_PROGRAMLISTING     = YES
+GENERATE_AUTOGEN_DEF   = NO
+GENERATE_PERLMOD       = NO
+PERLMOD_LATEX          = NO
+PERLMOD_PRETTY         = YES
+PERLMOD_MAKEVAR_PREFIX =
+ENABLE_PREPROCESSING   = YES
+MACRO_EXPANSION        = YES
+EXPAND_ONLY_PREDEF     = YES
+SEARCH_INCLUDES        = NO
+INCLUDE_PATH           =
+INCLUDE_FILE_PATTERNS  =
+PREDEFINED             = EINA_MAGIC_DEBUG \
+                         __UNUSED__= \
+                         EINA_ARG_NONNULL()= \
+                         EINA_MALLOC= \
+                         EINA_WARN_UNUSED_RESULT= \
+                         EAPI= \
+                         EINA_PURE= \
+                         EINA_CONST=
+EXPAND_AS_DEFINED      =
+SKIP_FUNCTION_MACROS   = YES
+TAGFILES               =
+GENERATE_TAGFILE       =
+ALLEXTERNALS           = NO
+EXTERNAL_GROUPS        = YES
+PERL_PATH              = /usr/bin/perl
+CLASS_DIAGRAMS         = NO
+MSCGEN_PATH            =
+HIDE_UNDOC_RELATIONS   = YES
+HAVE_DOT               = NO
+DOT_NUM_THREADS        = 0
+DOT_FONTNAME           = FreeSans.ttf
+DOT_FONTSIZE           = 10
+DOT_FONTPATH           =
+CLASS_GRAPH            = NO
+COLLABORATION_GRAPH    = NO
+GROUP_GRAPHS           = YES
+UML_LOOK               = NO
+TEMPLATE_RELATIONS     = NO
+INCLUDE_GRAPH          = NO
+INCLUDED_BY_GRAPH      = NO
+CALL_GRAPH             = NO
+CALLER_GRAPH           = NO
+GRAPHICAL_HIERARCHY    = NO
+DIRECTORY_GRAPH        = YES
+DOT_IMAGE_FORMAT       = png
+DOT_PATH               =
+DOTFILE_DIRS           =
+DOT_GRAPH_MAX_NODES    = 50
+MAX_DOT_GRAPH_DEPTH    = 0
+DOT_TRANSPARENT        = NO
+DOT_MULTI_TARGETS      = NO
+GENERATE_LEGEND        = YES
+DOT_CLEANUP            = YES
diff --git a/doc/Makefile.am b/doc/Makefile.am
new file mode 100644 (file)
index 0000000..781bbd2
--- /dev/null
@@ -0,0 +1,36 @@
+MAINTAINERCLEANFILES = Makefile.in
+
+.PHONY: doc
+
+PACKAGE_DOCNAME = $(PACKAGE_TARNAME)-$(PACKAGE_VERSION)-doc
+
+if EFL_BUILD_DOC
+
+doc-clean:
+       rm -rf html/ latex/ $(top_builddir)/$(PACKAGE_DOCNAME).tar*
+
+doc: all
+       $(efl_doxygen)
+       cp $(srcdir)/images/* html/
+       rm -rf $(PACKAGE_DOCNAME).tar*
+       mkdir -p $(PACKAGE_DOCNAME)/doc
+       cp -R html/ latex/ $(PACKAGE_DOCNAME)/doc
+       tar cf $(PACKAGE_DOCNAME).tar $(PACKAGE_DOCNAME)/
+       bzip2 -9 $(PACKAGE_DOCNAME).tar
+       rm -rf $(PACKAGE_DOCNAME)/
+       mv $(PACKAGE_DOCNAME).tar.bz2 $(top_builddir)
+
+clean-local: doc-clean
+
+else
+
+doc:
+       @echo "Documentation not built. Run ./configure --help"
+
+endif
+
+EXTRA_DIST = $(srcdir)/Doxyfile.in \
+       $(wildcard $(srcdir)/img/*.*) \
+       $(srcdir)/e.css \
+       $(srcdir)/head.html \
+       $(srcdir)/foot.html
\ No newline at end of file
diff --git a/doc/e.css b/doc/e.css
new file mode 100644 (file)
index 0000000..8697a3a
--- /dev/null
+++ b/doc/e.css
@@ -0,0 +1,218 @@
+/*
+    Author:
+        Andres Blanc <andresblanc@gmail.com>
+       DaveMDS Andreoli <dave@gurumeditation.it>
+
+    Supported Browsers:
+        ie7, opera9, konqueror4 and firefox3
+
+        Please use a different file for ie6, ie5, etc. hacks.
+*/
+
+
+/* Necessary to place the footer at the bottom of the page */
+html, body {
+       height: 100%;
+       margin: 0px;
+       padding: 0px;
+}
+
+#container {
+       min-height: 100%;
+       height: auto !important;
+       height: 100%;
+       margin: 0 auto -53px;
+}
+
+#footer, #push {
+       height: 53px;
+}
+
+
+* html #container {
+       height: 100%;
+}
+
+/* Prevent floating elements overflowing containers */
+.clear {
+       clear: both;
+       width: 0px;
+       height: 0px;
+}
+
+/* Flexible & centered layout from 750 to 960 pixels */
+.layout {
+       max-width: 960px;
+       min-width: 760px;
+       margin-left: auto;
+       margin-right: auto;
+}
+
+body {
+       /*font-family: Lucida Grande, Helvetica, sans-serif;*/
+       font-family: "Bitstream Vera","Vera","Trebuchet MS",Trebuchet,Tahoma,sans-serif
+}
+
+/* Prevent design overflowing the viewport in small resolutions */
+#container {
+       padding-right: 17px;
+       padding-left: 17px;
+       background-image: url(head_bg.png);
+       background-repeat: repeat-x;
+}
+
+#header {
+       width: 100%;
+       height: 102px;
+}
+
+#header h1 {
+       width: 63px;
+       height: 63px;
+       background-image: url(e.png);
+       background-repeat: no-repeat;
+       position: absolute;
+       margin: 0px;
+}
+
+#header h1 span {
+       display: none;
+}
+
+#header h2 {
+       display: none;
+}
+
+/* .menu-container is used to set properties common to .menu and .submenu */
+#header .menu-container {
+}
+
+#header .menu-container ul {
+       list-style-type: none;
+       list-style-position: inside;
+       margin: 0;
+}
+
+#header .menu-container li {
+       display: block;
+       float: right;
+}
+
+#header .menu {
+       height: 63px;
+       display: block;
+       background-image: url(menu_bg.png);
+       background-repeat: repeat-x;
+}
+
+#header .menu ul {
+       height: 100%;
+       display: block;
+       background-image: url(menu_bg_last.png);
+       background-repeat: no-repeat;
+       background-position: top right;
+       padding-right: 17px;
+}
+
+#header .menu li {
+       height: 100%;
+       text-align: center;
+       background-image: url(menu_bg_unsel.png);
+       background-repeat: no-repeat;
+}
+
+#header .menu a {
+       height: 100%;
+       display: block;
+       color: #cdcdcd;
+       text-decoration: none;
+       font-size: 10pt;
+       line-height: 59px;
+       text-align: center;
+       padding: 0px 15px 0px 15px;
+}
+
+#header .menu li:hover {
+       background-image: url(menu_bg_hover.png);
+       background-repeat: no-repeat;
+}
+
+#header .menu li:hover a {
+       color: #FFFFFF;
+}
+
+#header .menu li.current {
+       background-image: url(menu_bg_current.png);
+       background-repeat: no-repeat;
+}
+
+#header .menu li.current a {
+       color: #646464;
+}
+
+
+/* Hide all the submenus but the current */
+#header .submenu ul {
+       display: none;
+}
+
+#header .submenu .current {
+       display: block;
+}
+
+#header .submenu {
+       font: bold 10px verdana,'Bitstream Vera Sans',helvetica,arial,sans-serif;
+       margin-top: 10px;
+}
+
+#header .submenu a {
+       color: #888888;
+       text-decoration: none;
+       font-size: 0.9em;
+       line-height: 15px;
+       padding:0px 5px 0px 5px;
+}
+
+#header .submenu a:hover {
+       color: #444444;
+}
+
+#header .submenu li {
+       border-left: 1px solid #DDDDDD;
+}
+
+#header .submenu li:last-child {
+       border-left: 0;
+}
+
+#header .doxytitle {
+       position: absolute;
+       font-size: 1.8em;
+       font-weight: bold;
+       color: #444444;
+       line-height: 35px;
+}
+
+#header small {
+       font-size: 0.4em;
+}
+
+#footer {
+       background-image: url(foot_bg.png);
+       width: 100%;
+}
+
+#footer table {
+       width: 100%;
+       text-align: center;
+       white-space: nowrap;
+       padding: 5px 30px 5px 30px;
+       font-size: 0.8em;
+       font-family: "Bitstream Vera","Vera","Trebuchet MS",Trebuchet,Tahoma,sans-serif;
+       color: #888888;
+}
+
+#footer td.copyright {
+       width: 100%;
+}
+
diff --git a/doc/examples.dox b/doc/examples.dox
new file mode 100644 (file)
index 0000000..14b4ba3
--- /dev/null
@@ -0,0 +1,55 @@
+/**
+ * @page Examples Examples
+ *
+ * Here is a page with some EDBus examples:
+ * 
+ * @li @ref banshee
+ * @li @ref simple_dbus_client
+ * @li @ref simple_dbus_server
+ * @li @ref complex_types
+ * @li @ref complex_types_server
+ * @li @ref connman
+ * @li @ref ofono
+ */
+
+/**
+ * @page banshee Banshee dbus client
+ * 
+ * @include banshee.c
+ */
+
+/**
+ * @page simple_dbus_client Simple dbus client
+ * 
+ * @include client.c
+ */
+
+/**
+ * @page simple_dbus_server Simple dbus server
+ * 
+ * @include server.c
+ */
+
+/**
+ * @page complex_types Handling with dbus complex types
+ * 
+ * @include complex_types.c
+ */
+
+/**
+ * @page complex_types_server Handling with dbus complex types server side
+ * 
+ * @include complex_types_server.c
+ */
+
+/**
+ * @page connman Connman
+ * 
+ * @include connman-list-services.c
+ */
+
+/**
+ * @page ofono Ofono
+ * 
+ * @include ofono-dial.c
+ */
diff --git a/doc/foot.html b/doc/foot.html
new file mode 100644 (file)
index 0000000..78ef911
--- /dev/null
@@ -0,0 +1,19 @@
+ <div id="push"></div>
+ </div> <!-- #content -->
+  </div> <!-- .layout -->
+ </div> <!-- #container -->
+  <div id="footer">
+    <table><tr>
+      <td class="poweredby"><img src="doxygen.png"></td>
+      <td class="copyright">Copyright &copy;$year Enlightenment</td>
+      <td class="generated">Docs generated $datetime</td>
+    </tr></table>
+  </div>
+
+
+</body>
+</html>
diff --git a/doc/head.html b/doc/head.html
new file mode 100644 (file)
index 0000000..2d841f1
--- /dev/null
@@ -0,0 +1,67 @@
+<html>
+<head>
+    <title>$title</title>
+    <meta http-equiv="content-type" content="text/html;charset=UTF-8">
+    <meta name="author" content="Andres Blanc" >
+    
+    <link rel="icon" href="images/favicon.png" type="image/x-icon">
+    <link rel="shortcut icon" href="images/favicon.png" type="image/x-icon">
+    <link rel="icon" href="images/favicon.png" type="image/ico">
+    <link rel="shortcut icon" href="images/favicon.png" type="image/ico">
+
+    <link rel="stylesheet" type="text/css" media="screen" href="e.css">
+    <link rel="stylesheet" type="text/css" media="screen" href="edoxy.css">
+</head>
+
+<body>
+
+<div id="container">
+
+<div id="header">
+<div class="layout">
+    
+    <h1><span>Enlightenment</span></h1>
+    <h2><span>Beauty at your fingertips</span></h2>
+
+    <div class="menu-container">
+        <div class="menu">
+            <ul>
+               <li class="current"><a href="http://web.enlightenment.org/p.php?p=docs">Docs</a></li>
+                <li><a href="http://trac.enlightenment.org/e">Tracker</a></li>
+                <li><a href="http://www.enlightenment.org/p.php?p=contact">Contact</a></li>
+                <li><a href="http://www.enlightenment.org/p.php?p=contribute">Contribute</a></li>
+                <li><a href="http://www.enlightenment.org/p.php?p=support">Support</a></li>
+                <li><a href="http://www.enlightenment.org/p.php?p=download">Download</a></li>
+                <li><a href="http://www.enlightenment.org/p.php?p=about">About</a></li>
+                <li><a href="http://www.enlightenment.org/p.php?p=news">News</a></li>
+                <li><a href="http://www.enlightenment.org/">Home</a></li>
+            </ul>
+        </div>
+    </div>
+
+    <div class="doxytitle">
+        $projectname Documentation <small>at $date</small>
+    </div>
+
+    <div class="menu-container">
+        <!--<div class="submenu">
+            <ul class="current">
+                <li><a href="group__EUkit__Group.html">EUkit</a></li>
+                <li><a href="group__EOfono__Group.html">EOfono</a></li>
+                <li><a href="group__ENotify__Group.html">ENotify</a></li>
+                <li><a href="group__EHal__Group.html">EHal</a></li>
+                <li><a href="group__EConnman__Group.html">EConnman</a></li>
+                <li><a href="group__EBluez__Group.html">EBluez</a></li>
+                <li><a href="group__EDbus__Group.html">EDbus</a></li>
+               <li class="current"><a  href="index.html">Main Page</a></li>
+            </ul>
+        </div>-->
+    </div>
+
+
+    <div class="clear"></div>
+</div>
+</div>
+
+<div id="content">
+<div class="layout">
diff --git a/doc/images/e.png b/doc/images/e.png
new file mode 100644 (file)
index 0000000..b3884a5
Binary files /dev/null and b/doc/images/e.png differ
diff --git a/doc/images/edoxy.css b/doc/images/edoxy.css
new file mode 100644 (file)
index 0000000..3caf7a9
--- /dev/null
@@ -0,0 +1,483 @@
+/*
+ * This file contain a custom doxygen style to match e.org graphics
+ */
+
+
+
+/* BODY,H1,H2,H3,H4,H5,H6,P,CENTER,TD,TH,UL,DL,DIV {
+       font-family: Geneva, Arial, Helvetica, sans-serif;
+}*/ 
+BODY, TD {
+       font-size: 12px;
+}
+H1 {
+       text-align: center;
+       font-size: 160%;
+}
+H2 {
+       font-size: 120%;
+}
+H3 {
+       font-size: 100%;
+}
+CAPTION { 
+       font-weight: bold 
+}
+DIV.qindex {
+       width: 100%;
+       background-color: #e8eef2;
+       border: 1px solid #84b0c7;
+       text-align: center;
+       margin: 2px;
+       padding: 2px;
+       line-height: 140%;
+}
+DIV.navpath {
+       width: 100%;
+       background-color: #e8eef2;
+       border: 1px solid #84b0c7;
+       text-align: center;
+       margin: 2px;
+       padding: 2px;
+       line-height: 140%;
+}
+DIV.navtab {
+       background-color: #e8eef2;
+       border: 1px solid #84b0c7;
+       text-align: center;
+       margin: 2px;
+       margin-right: 15px;
+       padding: 2px;
+}
+TD.navtab {
+       font-size: 70%;
+}
+A.qindex {
+       text-decoration: none;
+       font-weight: bold;
+       color: #1A419D;
+}
+A.qindex:visited {
+       text-decoration: none;
+       font-weight: bold;
+       color: #1A419D
+}
+A.qindex:hover {
+       text-decoration: none;
+       background-color: #ddddff;
+}
+A.qindexHL {
+       text-decoration: none;
+       font-weight: bold;
+       background-color: #6666cc;
+       color: #ffffff;
+       border: 1px double #9295C2;
+}
+A.qindexHL:hover {
+       text-decoration: none;
+       background-color: #6666cc;
+       color: #ffffff;
+}
+A.qindexHL:visited { 
+       text-decoration: none; 
+       background-color: #6666cc; 
+       color: #ffffff 
+}
+A.el { 
+       text-decoration: none; 
+       font-weight: bold 
+}
+A.elRef { 
+       font-weight: bold 
+}
+A.code:link { 
+       text-decoration: none; 
+       font-weight: normal; 
+       color: #0000FF
+}
+A.code:visited { 
+       text-decoration: none; 
+       font-weight: normal; 
+       color: #0000FF
+}
+A.codeRef:link { 
+       font-weight: normal; 
+       color: #0000FF
+}
+A.codeRef:visited { 
+       font-weight: normal; 
+       color: #0000FF
+}
+A:hover, A:visited:hover { 
+       text-decoration: none;  
+       /* background-color: #f2f2ff; */
+       color: #000055;
+}
+A.anchor {
+       color: #000;
+}
+DL.el { 
+       margin-left: -1cm 
+}
+.fragment {
+       font-family: monospace, fixed;
+       font-size: 95%;
+}
+PRE.fragment {
+       border: 1px solid #CCCCCC;
+       background-color: #f5f5f5;
+       margin-top: 4px;
+       margin-bottom: 4px;
+       margin-left: 2px;
+       margin-right: 8px;
+       padding-left: 6px;
+       padding-right: 6px;
+       padding-top: 4px;
+       padding-bottom: 4px;
+}
+DIV.ah { 
+       background-color: black; 
+       font-weight: bold; 
+       color: #ffffff; 
+       margin-bottom: 3px; 
+       margin-top: 3px 
+}
+
+DIV.groupHeader {
+       margin-left: 16px;
+       margin-top: 12px;
+       margin-bottom: 6px;
+       font-weight: bold;
+}
+DIV.groupText { 
+       margin-left: 16px; 
+       font-style: italic; 
+       font-size: 90% 
+}
+/*BODY {
+       background: white;
+       color: black;
+       margin-right: 20px;
+       margin-left: 20px;
+}*/
+TD.indexkey {
+       background-color: #e8eef2;
+       font-weight: bold;
+       padding-right  : 10px;
+       padding-top    : 2px;
+       padding-left   : 10px;
+       padding-bottom : 2px;
+       margin-left    : 0px;
+       margin-right   : 0px;
+       margin-top     : 2px;
+       margin-bottom  : 2px;
+       border: 1px solid #CCCCCC;
+}
+TD.indexvalue {
+       background-color: #e8eef2;
+       font-style: italic;
+       padding-right  : 10px;
+       padding-top    : 2px;
+       padding-left   : 10px;
+       padding-bottom : 2px;
+       margin-left    : 0px;
+       margin-right   : 0px;
+       margin-top     : 2px;
+       margin-bottom  : 2px;
+       border: 1px solid #CCCCCC;
+}
+TR.memlist {
+       background-color: #f0f0f0; 
+}
+P.formulaDsp { 
+       text-align: center; 
+}
+IMG.formulaDsp {
+}
+IMG.formulaInl { 
+       vertical-align: middle; 
+}
+SPAN.keyword       { color: #008000 }
+SPAN.keywordtype   { color: #604020 }
+SPAN.keywordflow   { color: #e08000 }
+SPAN.comment       { color: #800000 }
+SPAN.preprocessor  { color: #806020 }
+SPAN.stringliteral { color: #002080 }
+SPAN.charliteral   { color: #008080 }
+SPAN.vhdldigit     { color: #ff00ff }
+SPAN.vhdlchar      { color: #000000 }
+SPAN.vhdlkeyword   { color: #700070 }
+SPAN.vhdllogic     { color: #ff0000 }
+
+.mdescLeft {
+       padding: 0px 8px 4px 8px;
+       font-size: 80%;
+       font-style: italic;
+       background-color: #FAFAFA;
+       border-top: 1px none #E0E0E0;
+       border-right: 1px none #E0E0E0;
+       border-bottom: 1px none #E0E0E0;
+       border-left: 1px none #E0E0E0;
+       margin: 0px;
+}
+.mdescRight {
+        padding: 0px 8px 4px 8px;
+       font-size: 80%;
+       font-style: italic;
+       background-color: #FAFAFA;
+       border-top: 1px none #E0E0E0;
+       border-right: 1px none #E0E0E0;
+       border-bottom: 1px none #E0E0E0;
+       border-left: 1px none #E0E0E0;
+       margin: 0px;
+}
+.memItemLeft {
+       padding: 1px 0px 0px 8px;
+       margin: 4px;
+       border-top-width: 1px;
+       border-right-width: 1px;
+       border-bottom-width: 1px;
+       border-left-width: 1px;
+       border-top-color: #E0E0E0;
+       border-right-color: #E0E0E0;
+       border-bottom-color: #E0E0E0;
+       border-left-color: #E0E0E0;
+       border-top-style: solid;
+       border-right-style: none;
+       border-bottom-style: none;
+       border-left-style: none;
+       background-color: #FAFAFA;
+       font-size: 80%;
+}
+.memItemRight {
+       padding: 1px 8px 0px 8px;
+       margin: 4px;
+       border-top-width: 1px;
+       border-right-width: 1px;
+       border-bottom-width: 1px;
+       border-left-width: 1px;
+       border-top-color: #E0E0E0;
+       border-right-color: #E0E0E0;
+       border-bottom-color: #E0E0E0;
+       border-left-color: #E0E0E0;
+       border-top-style: solid;
+       border-right-style: none;
+       border-bottom-style: none;
+       border-left-style: none;
+       background-color: #FAFAFA;
+       font-size: 80%;
+}
+.memTemplItemLeft {
+       padding: 1px 0px 0px 8px;
+       margin: 4px;
+       border-top-width: 1px;
+       border-right-width: 1px;
+       border-bottom-width: 1px;
+       border-left-width: 1px;
+       border-top-color: #E0E0E0;
+       border-right-color: #E0E0E0;
+       border-bottom-color: #E0E0E0;
+       border-left-color: #E0E0E0;
+       border-top-style: none;
+       border-right-style: none;
+       border-bottom-style: none;
+       border-left-style: none;
+       background-color: #FAFAFA;
+       font-size: 80%;
+}
+.memTemplItemRight {
+       padding: 1px 8px 0px 8px;
+       margin: 4px;
+       border-top-width: 1px;
+       border-right-width: 1px;
+       border-bottom-width: 1px;
+       border-left-width: 1px;
+       border-top-color: #E0E0E0;
+       border-right-color: #E0E0E0;
+       border-bottom-color: #E0E0E0;
+       border-left-color: #E0E0E0;
+       border-top-style: none;
+       border-right-style: none;
+       border-bottom-style: none;
+       border-left-style: none;
+       background-color: #FAFAFA;
+       font-size: 80%;
+}
+.memTemplParams {
+       padding: 1px 0px 0px 8px;
+       margin: 4px;
+       border-top-width: 1px;
+       border-right-width: 1px;
+       border-bottom-width: 1px;
+       border-left-width: 1px;
+       border-top-color: #E0E0E0;
+       border-right-color: #E0E0E0;
+       border-bottom-color: #E0E0E0;
+       border-left-color: #E0E0E0;
+       border-top-style: solid;
+       border-right-style: none;
+       border-bottom-style: none;
+       border-left-style: none;
+       color: #606060;
+       background-color: #FAFAFA;
+       font-size: 80%;
+}
+.search { 
+       color: #003399;
+       font-weight: bold;
+}
+FORM.search {
+       margin-bottom: 0px;
+       margin-top: 0px;
+}
+INPUT.search { 
+       font-size: 75%;
+       color: #000080;
+       font-weight: normal;
+       background-color: #e8eef2;
+}
+TD.tiny { 
+       font-size: 75%;
+}
+a {
+       color: #1A41A8;
+}
+a:visited {
+       color: #2A3798;
+}
+.dirtab { 
+       padding: 4px;
+       border-collapse: collapse;
+       border: 1px solid #84b0c7;
+}
+TH.dirtab { 
+       background: #e8eef2;
+       font-weight: bold;
+}
+HR { 
+       height: 1px;
+       border: none;
+       border-top: 1px solid black;
+}
+
+/* Style for detailed member documentation */
+.memtemplate {
+       font-size: 80%;
+       color: #606060;
+       font-weight: normal;
+       margin-left: 3px;
+} 
+.memnav { 
+       background-color: #e8eef2;
+       border: 1px solid #84b0c7;
+       text-align: center;
+       margin: 2px;
+       margin-right: 15px;
+       padding: 2px;
+}
+.memitem {
+       padding: 4px;
+       background-color: #eef3f5;
+       border-width: 1px;
+       border-style: solid;
+       border-color: #dedeee;
+       -moz-border-radius: 8px 8px 8px 8px;
+}
+.memname {
+       white-space: nowrap;
+       font-weight: bold;
+}
+.memdoc{
+       padding-left: 10px;
+}
+.memproto {
+       background-color: #d5e1e8;
+       width: 100%;
+       border-width: 1px;
+       border-style: solid;
+       border-color: #84b0c7;
+       font-weight: bold;
+       -moz-border-radius: 8px 8px 8px 8px;
+}
+.paramkey {
+       text-align: right;
+}
+.paramtype {
+       white-space: nowrap;
+}
+.paramname {
+       color: #602020;
+       font-style: italic;
+       white-space: nowrap;
+}
+/* End Styling for detailed member documentation */
+
+/* for the tree view */
+.ftvtree {
+       font-family: sans-serif;
+       margin:0.5em;
+}
+/* these are for tree view when used as main index */
+.directory { 
+       font-size: 9pt; 
+       font-weight: bold; 
+}
+.directory h3 { 
+       margin: 0px; 
+       margin-top: 1em; 
+       font-size: 11pt; 
+}
+
+/* The following two styles can be used to replace the root node title */
+/* with an image of your choice.  Simply uncomment the next two styles, */
+/* specify the name of your image and be sure to set 'height' to the */
+/* proper pixel height of your image. */
+
+/* .directory h3.swap { */
+/*     height: 61px; */
+/*     background-repeat: no-repeat; */
+/*     background-image: url("yourimage.gif"); */
+/* } */
+/* .directory h3.swap span { */
+/*     display: none; */
+/* } */
+
+.directory > h3 { 
+       margin-top: 0; 
+}
+.directory p { 
+       margin: 0px; 
+       white-space: nowrap; 
+}
+.directory div { 
+       display: none; 
+       margin: 0px; 
+}
+.directory img { 
+       vertical-align: -30%; 
+}
+/* these are for tree view when not used as main index */
+.directory-alt { 
+       font-size: 100%; 
+       font-weight: bold; 
+}
+.directory-alt h3 { 
+       margin: 0px; 
+       margin-top: 1em; 
+       font-size: 11pt; 
+}
+.directory-alt > h3 { 
+       margin-top: 0; 
+}
+.directory-alt p { 
+       margin: 0px; 
+       white-space: nowrap; 
+}
+.directory-alt div { 
+       display: none; 
+       margin: 0px; 
+}
+.directory-alt img { 
+       vertical-align: -30%; 
+}
+
diff --git a/doc/images/foot_bg.png b/doc/images/foot_bg.png
new file mode 100644 (file)
index 0000000..b24f3a4
Binary files /dev/null and b/doc/images/foot_bg.png differ
diff --git a/doc/images/head_bg.png b/doc/images/head_bg.png
new file mode 100644 (file)
index 0000000..081dc13
Binary files /dev/null and b/doc/images/head_bg.png differ
diff --git a/doc/images/menu_bg.png b/doc/images/menu_bg.png
new file mode 100644 (file)
index 0000000..e978743
Binary files /dev/null and b/doc/images/menu_bg.png differ
diff --git a/doc/images/menu_bg_current.png b/doc/images/menu_bg_current.png
new file mode 100644 (file)
index 0000000..de97c92
Binary files /dev/null and b/doc/images/menu_bg_current.png differ
diff --git a/doc/images/menu_bg_hover.png b/doc/images/menu_bg_hover.png
new file mode 100644 (file)
index 0000000..3fd851d
Binary files /dev/null and b/doc/images/menu_bg_hover.png differ
diff --git a/doc/images/menu_bg_last.png b/doc/images/menu_bg_last.png
new file mode 100644 (file)
index 0000000..88c116c
Binary files /dev/null and b/doc/images/menu_bg_last.png differ
diff --git a/doc/images/menu_bg_unsel.png b/doc/images/menu_bg_unsel.png
new file mode 100644 (file)
index 0000000..50e5fd8
Binary files /dev/null and b/doc/images/menu_bg_unsel.png differ
diff --git a/edbus2.pc.in b/edbus2.pc.in
new file mode 100644 (file)
index 0000000..713e1f8
--- /dev/null
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: edbus
+Description: D-Bus access from Ecore
+Requires.private: ecore dbus-1
+Version: @VERSION@
+Libs: -L${libdir} -ledbus2
+Cflags: -I${includedir}
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/ac_valist.m4 b/m4/ac_valist.m4
new file mode 100644 (file)
index 0000000..a4d6a24
--- /dev/null
@@ -0,0 +1,48 @@
+dnl That code is public domain and can be freely used or copied.
+dnl Originally snatched from somewhere...
+
+dnl Macro for checking if va_list is an array
+
+dnl Usage: AC_C_VA_LIST_AS_ARRAY
+dnl call AC_DEFINE for HAVE_VA_LIST_AS_ARRAY
+dnl if for this architecture va_list is defined as an array
+
+AC_DEFUN([AC_C_VA_LIST_AS_ARRAY],
+[
+
+AC_MSG_CHECKING([whether va_list is defined as an array])
+
+AC_CACHE_VAL([ac_cv_valistasarray],
+   [AC_TRY_RUN(
+       [
+#include <stdlib.h>
+#include <stdarg.h>
+void foo(int i, ...)
+{
+       va_list ap1, ap2;
+       va_start(ap1, i);
+       ap2 = ap1;
+       if (va_arg(ap2, int) != 123 || va_arg(ap1, int) != 123)
+               exit(1);
+       va_end(ap1);
+}
+int main(void)
+{
+       foo(0, 123);
+       return(0);
+}
+       ],
+       [ac_cv_valistasarray="no"],
+       [ac_cv_valistasarray="yes"],
+       [ac_cv_valistasarray="no"]
+    )])
+
+AC_MSG_RESULT($ac_cv_valistasarray)
+
+if test "x${ac_cv_valistasarray}" = "xyes" ; then
+   AC_DEFINE([HAVE_VA_LIST_AS_ARRAY], [1], [Define to 1 if va_list is an array])
+fi
+
+])
+
+dnl End of ac_valist.m4
diff --git a/m4/efl_compiler_flag.m4 b/m4/efl_compiler_flag.m4
new file mode 100644 (file)
index 0000000..e3fc821
--- /dev/null
@@ -0,0 +1,24 @@
+dnl Checks if a given compiler switch is supported.
+dnl If so, this macro adds the flag to the CFLAGS
+
+AC_DEFUN([EFL_COMPILER_FLAG],
+[
+
+CFLAGS_save="${CFLAGS}"
+CFLAGS="${CFLAGS} $1"
+  
+AC_LANG_PUSH([C])
+AC_MSG_CHECKING([whether the compiler supports $1])
+
+AC_COMPILE_IFELSE(
+   [AC_LANG_PROGRAM([[]])],
+   [have_flag="yes"],
+   [have_flag="no"])
+AC_MSG_RESULT([${have_flag}])
+
+if test "x${have_flag}" = "xno" ; then
+   CFLAGS="${CFLAGS_save}"
+fi
+AC_LANG_POP([C])
+
+])
diff --git a/m4/efl_doxygen.m4 b/m4/efl_doxygen.m4
new file mode 100644 (file)
index 0000000..7324af3
--- /dev/null
@@ -0,0 +1,94 @@
+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 Macro that check if doxygen is available or not.
+
+dnl EFL_CHECK_DOXYGEN([ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]])
+dnl Test for the doxygen program
+dnl Defines efl_doxygen
+dnl Defines the automake conditionnal EFL_BUILD_DOC
+dnl
+AC_DEFUN([EFL_CHECK_DOXYGEN],
+[
+
+dnl
+dnl Disable the build of the documentation
+dnl
+AC_ARG_ENABLE([doc],
+   [AC_HELP_STRING(
+       [--disable-doc],
+       [Disable documentation build @<:@default=enabled@:>@])],
+   [
+    if test "x${enableval}" = "xyes" ; then
+       efl_enable_doc="yes"
+    else
+       efl_enable_doc="no"
+    fi
+   ],
+   [efl_enable_doc="yes"])
+
+AC_MSG_CHECKING([whether to build documentation])
+AC_MSG_RESULT([${efl_enable_doc}])
+
+if test "x${efl_enable_doc}" = "xyes" ; then
+
+dnl Specify the file name, without path
+
+   efl_doxygen="doxygen"
+
+   AC_ARG_WITH([doxygen],
+      [AC_HELP_STRING(
+          [--with-doxygen=FILE],
+          [doxygen program to use @<:@default=doxygen@:>@])],
+
+dnl Check the given doxygen program.
+
+      [efl_doxygen=${withval}
+       AC_CHECK_PROG([efl_have_doxygen],
+          [${efl_doxygen}],
+          [yes],
+          [no])
+       if test "x${efl_have_doxygen}" = "xno" ; then
+          echo "WARNING:"
+          echo "The doxygen program you specified:"
+          echo "${efl_doxygen}"
+          echo "was not found.  Please check the path and make sure "
+          echo "the program exists and is executable."
+          AC_MSG_WARN([no doxygen detected. Documentation will not be built])
+       fi
+      ],
+      [AC_CHECK_PROG([efl_have_doxygen],
+          [${efl_doxygen}],
+          [yes],
+          [no])
+       if test "x${efl_have_doxygen}" = "xno" ; then
+          echo "WARNING:"
+          echo "The doxygen program was not found in your execute path."
+          echo "You may have doxygen installed somewhere not covered by your path."
+          echo ""
+          echo "If this is the case make sure you have the packages installed, AND"
+          echo "that the doxygen program is in your execute path (see your"
+          echo "shell manual page on setting the \$PATH environment variable), OR"
+          echo "alternatively, specify the program to use with --with-doxygen."
+          AC_MSG_WARN([no doxygen detected. Documentation will not be built])
+       fi
+      ])
+else
+   efl_have_doxygen="no"
+fi
+
+dnl
+dnl Substitution
+dnl
+AC_SUBST([efl_doxygen])
+
+if ! test "x${efl_have_doxygen}" = "xyes" ; then
+   efl_enable_doc="no"
+fi
+
+AM_CONDITIONAL(EFL_BUILD_DOC, test "x${efl_have_doxygen}" = "xyes")
+
+AS_IF([test "x$efl_have_doxygen" = "xyes"], [$1], [$2])
+])
+
+dnl End of efl_doxygen.m4
diff --git a/m4/efl_examples.m4 b/m4/efl_examples.m4
new file mode 100644 (file)
index 0000000..2a809ad
--- /dev/null
@@ -0,0 +1,63 @@
+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 Macro that check if building examples is wanted.
+
+dnl Usage: EFL_CHECK_BUILD_EXAMPLES([ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]])
+dnl Defines the automake conditionnal EFL_ENABLE_BUILD_EXAMPLES
+
+AC_DEFUN([EFL_CHECK_BUILD_EXAMPLES],
+[
+
+dnl configure option
+
+AC_ARG_ENABLE([build-examples],
+   [AC_HELP_STRING([--enable-build-examples], [enable building examples @<:@default=disabled@:>@])],
+   [
+    if test "x${enableval}" = "xyes" ; then
+       _efl_enable_build_examples="yes"
+    else
+       _efl_enable_build_examples="no"
+    fi
+   ],
+   [_efl_enable_build_examples="no"])
+
+AC_MSG_CHECKING([whether examples are built])
+AC_MSG_RESULT([${_efl_enable_build_examples}])
+
+AM_CONDITIONAL(EFL_BUILD_EXAMPLES, test "x${_efl_enable_build_examples}" = "xyes")
+
+AS_IF([test "x$_efl_enable_build_examples" = "xyes"], [$1], [$2])
+])
+
+
+dnl Macro that check if installing examples is wanted.
+
+dnl Usage: EFL_CHECK_INSTALL_EXAMPLES([ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]])
+dnl Defines the automake conditionnal EFL_ENABLE_INSTALL_EXAMPLES
+
+AC_DEFUN([EFL_CHECK_INSTALL_EXAMPLES],
+[
+
+dnl configure option
+
+AC_ARG_ENABLE([install-examples],
+   [AC_HELP_STRING([--enable-install-examples], [enable installing example source files @<:@default=disabled@:>@])],
+   [
+    if test "x${enableval}" = "xyes" ; then
+       _efl_enable_install_examples="yes"
+    else
+       _efl_enable_install_examples="no"
+    fi
+   ],
+   [_efl_enable_install_examples="no"])
+
+AC_MSG_CHECKING([whether examples are installed])
+AC_MSG_RESULT([${_efl_enable_install_examples}])
+
+AM_CONDITIONAL(EFL_INSTALL_EXAMPLES, test "x${_efl_enable_install_examples}" = "xyes")
+
+AS_IF([test "x$_efl_enable_install_examples" = "xyes"], [$1], [$2])
+])
+
+dnl End of efl_examples.m4
diff --git a/packaging/edbus.spec b/packaging/edbus.spec
new file mode 100644 (file)
index 0000000..899a719
--- /dev/null
@@ -0,0 +1,73 @@
+#sbs-git:slp/pkgs/e/edbus edbus 1.0.0.001+svn.69045slp2+build01 706f4acfdaf1b818e2387701a993eca929051358
+Name:       edbus
+Summary:    D-Bus and HAL wrapper libraries for EFL
+Version:    1.7.0
+Release:    1
+Group:      System/Libraries
+License:    BSD
+Source0:    %{name}-%{version}.tar.gz
+Requires(post): /sbin/ldconfig
+Requires(postun): /sbin/ldconfig
+BuildRequires:  pkgconfig(ecore)
+BuildRequires:  pkgconfig(eina)
+BuildRequires:  pkgconfig(evas)
+BuildRequires:  pkgconfig(dbus-1)
+
+
+%description
+D-Bus and HAL wrapper libraries for use with the EFL
+
+
+
+%package devel
+Summary:    D-Bus and HAL wrapper libraries for EFL (devel)
+Group:      Development/Libraries
+Requires:   %{name} = %{version}-%{release}
+
+%description devel
+D-Bus and HAL wrapper libraries for use with the EFL (devel)
+
+
+%prep
+%setup -q
+
+
+%build
+export CFLAGS+=" -fvisibility=hidden -fPIC"
+export LDFLAGS+=" -fvisibility=hidden -Wl,--hash-style=both -Wl,--as-needed"
+
+%autogen --disable-static
+%configure --disable-static
+
+make %{?jobs:-j%jobs}
+
+%install
+rm -rf %{buildroot}
+%make_install
+
+
+%post -p /sbin/ldconfig
+
+%postun -p /sbin/ldconfig
+
+%files
+%defattr(-,root,root,-)
+%{_libdir}/libe*.so
+%{_libdir}/libe*.so.*
+
+%files devel
+%defattr(-,root,root,-)
+%{_libdir}/libe*.so
+%{_libdir}/libe*.so.*
+%{_libdir}/pkgconfig/edbus2.pc
+%{_includedir}/edbus-1/EDBus.h
+%{_includedir}/edbus-1/edbus_connection.h
+%{_includedir}/edbus-1/edbus_freedesktop.h
+%{_includedir}/edbus-1/edbus_message.h
+%{_includedir}/edbus-1/edbus_message_eina_value.h
+%{_includedir}/edbus-1/edbus_message_helper.h
+%{_includedir}/edbus-1/edbus_object.h
+%{_includedir}/edbus-1/edbus_pending.h
+%{_includedir}/edbus-1/edbus_proxy.h
+%{_includedir}/edbus-1/edbus_service.h
+%{_includedir}/edbus-1/edbus_signal_handler.h
diff --git a/src/examples/banshee.c b/src/examples/banshee.c
new file mode 100644 (file)
index 0000000..b750239
--- /dev/null
@@ -0,0 +1,329 @@
+#include "EDBus.h"
+#include <Ecore.h>
+
+static Eina_Bool
+_timer1_cb(void *data)
+{
+   printf("\n## ecore_main_loop_quit()\n");
+   ecore_main_loop_quit();
+   return EINA_TRUE;
+}
+
+EDBus_Connection *conn;
+EDBus_Signal_Handler *sh, *sh2, *sh3, *sh4;
+
+static void
+on_get_playlists(void *data, const EDBus_Message *msg, EDBus_Pending *pending)
+{
+   const char *errname, *errmsg;
+   EDBus_Message_Iter *array, *struct_entry;
+   char *path, *name, *image;
+   int i = 0;
+
+   if (edbus_message_error_get(msg, &errname, &errmsg))
+     {
+        fprintf(stderr, "Error: %s %s\n", errname, errmsg);
+        return;
+     }
+
+   if (!edbus_message_arguments_get(msg, "a(oss)", &array))
+     {
+        fprintf(stderr, "Error: could not get entry contents\n");
+        return;
+     }
+   printf("on_get_playlists() \n\n");
+   while (edbus_message_iter_get_and_next(array, 'r', &struct_entry))
+     {
+        if (! edbus_message_iter_arguments_get(struct_entry, "oss", &path, &name, &image))
+          {
+             printf("error on edbus_massage_iterator_arguments_get()");
+             return;
+          }
+        i++;
+        printf("%d - %s | %s | %s\n", i, path, name, image);
+     }
+   printf("end of on_get_playlists()\n\n");
+}
+
+static void
+iterate_dict(void *data, const void *key, EDBus_Message_Iter *var)
+{
+   const char *skey = key;
+
+   if (!strcmp(skey, "PlaylistCount"))
+     {
+        unsigned count;
+        if (!edbus_message_iter_arguments_get(var, "u", &count))
+          printf("error2\n");
+        printf("PlaylistCount=%d\n", count);
+     }
+   else if (!strcmp(skey, "Orderings"))
+     {
+        EDBus_Message_Iter *as;
+        const char *txt;
+        printf("- Orderings\n");
+        if (!edbus_message_iter_arguments_get(var, "as", &as))
+          printf("error1\n");
+        while (edbus_message_iter_get_and_next(as, 's', &txt))
+          printf("\t%s\n", txt);
+     }
+}
+
+static void
+playlist_get_all_cb(void *data, const EDBus_Message *msg, EDBus_Pending *pending)
+{
+   const char *errname, *errmsg;
+   EDBus_Message_Iter *array;
+
+   if (edbus_message_error_get(msg, &errname, &errmsg))
+     {
+        fprintf(stderr, "Error: %s %s\n", errname, errmsg);
+        return;
+     }
+   if (edbus_message_arguments_get(msg, "a{sv}", &array))
+     edbus_message_iter_dict_iterate(array, "sv", iterate_dict, NULL);
+}
+
+static void
+on_introspect(void *data, const EDBus_Message *msg, EDBus_Pending *pending)
+{
+   const char *errname, *errmsg, *string;
+
+   if (edbus_message_error_get(msg, &errname, &errmsg))
+     {
+        fprintf(stderr, "Error: %s %s\n", errname, errmsg);
+        return;
+     }
+
+   if (!edbus_message_arguments_get(msg, "s", &string))
+     {
+        fprintf(stderr, "Error: could not get entry contents\n");
+        return;
+     }
+
+   printf("on_introspect() data=\n%s\n\n", string);
+}
+
+static void
+on_next(void *data, const EDBus_Message *msg, EDBus_Pending *pending)
+{
+   const char *errname, *errmsg;
+
+   printf("on_next()\n");
+
+   if (edbus_message_error_get(msg, &errname, &errmsg))
+     {
+        fprintf(stderr, "Error: %s %s\n", errname, errmsg);
+     }
+}
+
+static void
+on_pause(void *data, const EDBus_Message *msg, EDBus_Pending *pending)
+{
+   const char *errname, *errmsg;
+
+   printf("on_pause()\n");
+
+   if (edbus_message_error_get(msg, &errname, &errmsg))
+     {
+        fprintf(stderr, "Error: %s %s\n", errname, errmsg);
+     }
+}
+
+static void
+on_state_changed(void *data, const EDBus_Message *msg)
+{
+   char *status;
+   if (edbus_message_error_get(msg, NULL, NULL))
+     {
+        fprintf(stderr, "on_state_changed error\n");
+        return;
+     }
+
+   if (!edbus_message_arguments_get(msg, "s", &status))
+     {
+        fprintf(stderr, "Error: could not get entry contents\n");
+        return;
+     }
+
+   printf("on_state_changed = %s\n", status);
+}
+
+static void
+on_state_changed2(void *data, const EDBus_Message *msg)
+{
+   char *status;
+   if (edbus_message_error_get(msg, NULL, NULL))
+     {
+        fprintf(stderr, "on_state_changed error\n");
+        return;
+     }
+
+   if (!edbus_message_arguments_get(msg, "s", &status))
+     {
+        fprintf(stderr, "Error: could not get entry contents\n");
+        return;
+     }
+
+   printf("on_state_changed2 = %s\n", status);
+   edbus_signal_handler_unref(sh2);
+   sh2 = NULL;
+}
+
+static void
+on_name_owner_changed_by_id(void *data, const EDBus_Message *msg)
+{
+   char *bus, *older_id, *new_id;
+
+   if (edbus_message_error_get(msg, NULL, NULL))
+     return;
+   if (!edbus_message_arguments_get(msg, "sss", &bus, &older_id, &new_id))
+     printf("Error getting arguments from NameOwnerChanged");
+
+   printf("banshee started on id=%s\n", new_id);
+}
+
+static void
+on_name_owner_changed(void *data, const EDBus_Message *msg)
+{
+   char *bus, *older_id, *new_id;
+   const char *name, *text;
+
+   if (edbus_message_error_get(msg, &name, &text))
+     printf("NameOwnerChanged name=%s text=%s", name, text);
+   if (!edbus_message_arguments_get(msg, "sss", &bus, &older_id, &new_id))
+     printf("Error getting arguments from NameOwnerChanged");
+
+   printf("bus = %s older=%s new=%s\n\n", bus, older_id, new_id);
+}
+
+int
+main(void)
+{
+   EDBus_Object *player_engine_obj, *playback_controller_obj, *mediaplayer2_obj;
+   EDBus_Proxy *player_engine, *playback_controler, *introspectable, *playlists;
+   EDBus_Pending *pending;
+   unsigned int bool2 = 1;
+   unsigned int playlist_index = 0;
+   unsigned int playlist_max_count = 30;
+   unsigned int playlist_reverse_order = 0;
+   const char *playlist_order = "asc";
+
+   ecore_init();
+   edbus_init();
+
+   conn = edbus_connection_get(EDBUS_CONNECTION_TYPE_SESSION);
+
+   player_engine_obj = edbus_object_get(conn, "org.bansheeproject.Banshee",
+                                        "/org/bansheeproject/Banshee/PlayerEngine");
+   if (!player_engine_obj)
+     {
+        fprintf(stderr, "Error: could not get object\n");
+        return EXIT_FAILURE;
+     }
+
+   playback_controller_obj = edbus_object_get(conn, "org.bansheeproject.Banshee",
+                                              "/org/bansheeproject/Banshee/PlaybackController");
+
+   mediaplayer2_obj = edbus_object_get(conn, "org.bansheeproject.Banshee",
+                                       "/org/mpris/MediaPlayer2");
+
+   player_engine = edbus_proxy_get(player_engine_obj,
+                                   "org.bansheeproject.Banshee.PlayerEngine");
+   if (!player_engine)
+     {
+        fprintf(stderr, "Error: could not get binding\n");
+        return EXIT_FAILURE;
+     }
+
+   introspectable = edbus_proxy_get(player_engine_obj,
+                                    "org.freedesktop.DBus.Introspectable");
+   if (!introspectable)
+     {
+        fprintf(stderr, "Error: could not get binding\n");
+        return EXIT_FAILURE;
+     }
+
+   playback_controler = edbus_proxy_get(playback_controller_obj,
+                             "org.bansheeproject.Banshee.PlaybackController");
+   if (!playback_controler)
+     {
+        fprintf(stderr, "Error: could not get binding\n");
+        return EXIT_FAILURE;
+     }
+   edbus_proxy_signal_handler_add(player_engine, "StateChanged", on_state_changed, NULL);
+
+   playlists = edbus_proxy_get(mediaplayer2_obj, "org.mpris.MediaPlayer2.Playlists");
+
+   edbus_proxy_property_get_all(playlists, playlist_get_all_cb, NULL);
+
+   pending = edbus_proxy_call(introspectable, "Introspect", on_introspect, NULL, -1, "");
+   if (!pending)
+     {
+        fprintf(stderr, "Error: could not call\n");
+        return EXIT_FAILURE;
+     }
+
+   pending = edbus_proxy_call(player_engine, "Pause", on_pause, NULL, -1, "");
+   if (!pending)
+     {
+        fprintf(stderr, "Error: could not call\n");
+        return EXIT_FAILURE;
+     }
+
+   pending = edbus_proxy_call(playback_controler, "Next", on_next, NULL, -1, "b", bool2);
+   if (!pending)
+     {
+        fprintf(stderr, "Error: could not call\n");
+        return EXIT_FAILURE;
+     }
+
+   edbus_proxy_call(playlists, "GetPlaylists", on_get_playlists, NULL, -1,
+                    "uusb", playlist_index, playlist_max_count,
+                    playlist_order, playlist_reverse_order);
+
+   sh = edbus_signal_handler_add(conn, "org.bansheeproject.Banshee",
+                            "/org/bansheeproject/Banshee/PlayerEngine",
+                            "org.bansheeproject.Banshee.PlayerEngine",
+                            "StateChanged", on_state_changed, NULL);
+
+   sh2 = edbus_signal_handler_add(conn, "org.bansheeproject.Banshee",
+                               "/org/bansheeproject/Banshee/PlayerEngine",
+                               "org.bansheeproject.Banshee.PlayerEngine",
+                               "StateChanged", on_state_changed2, NULL);
+
+   sh3 = edbus_signal_handler_add(conn,
+                                  EDBUS_FDO_BUS,
+                                  EDBUS_FDO_PATH,
+                                  EDBUS_FDO_INTERFACE,
+                                  "NameOwnerChanged",
+                                  on_name_owner_changed,
+                                  NULL);
+   edbus_signal_handler_match_extra_set(sh3, "arg0", "org.bansheeproject.Banshee", NULL);
+
+   sh4 = edbus_signal_handler_add(conn,
+                                  EDBUS_FDO_BUS,
+                                  EDBUS_FDO_PATH,
+                                  EDBUS_FDO_INTERFACE,
+                                  "NameOwnerChanged",
+                                  on_name_owner_changed_by_id,
+                                  NULL);
+   edbus_signal_handler_match_extra_set(sh4,
+                                        "arg0", "org.bansheeproject.Banshee",
+                                        "arg1", "", NULL);
+
+   ecore_timer_add(50, _timer1_cb, NULL);
+
+   ecore_main_loop_begin();
+
+   edbus_signal_handler_unref(sh);
+   edbus_proxy_unref(playback_controler);
+   edbus_proxy_unref(introspectable);
+   edbus_object_unref(player_engine_obj);
+   edbus_connection_unref(conn);
+
+   edbus_shutdown();
+   ecore_shutdown();
+   return 0;
+}
+
diff --git a/src/examples/client.c b/src/examples/client.c
new file mode 100644 (file)
index 0000000..58a8c95
--- /dev/null
@@ -0,0 +1,283 @@
+#include "EDBus.h"
+#include <Ecore.h>
+
+#define BUS "org.Enlightenment"
+#define PATH "/org/enlightenment"
+#define INTERFACE "org.enlightenment.Test"
+#define NTESTS 7
+
+static int i = 0;
+static EDBus_Signal_Handler *sh;
+
+static void
+_on_alive(void *context, const EDBus_Message *msg)
+{
+   printf("Alive\n\n");
+}
+
+static void
+_on_alive2(void *context, const EDBus_Message *msg)
+{
+   printf("Alive2\n\n");
+   i++;
+   if (i == 2)
+     edbus_signal_handler_unref(sh);
+}
+
+static void
+_on_hello(void *context, const EDBus_Message *msg)
+{
+   char *txt;
+
+   if (edbus_message_arguments_get(msg, "s", &txt))
+     printf("%s\n", txt);
+}
+
+#define bool_value EINA_TRUE
+#define byte_value 0xAA
+#define uint32_value 0xFFFFFFFF
+#define int32_value 0xFFFFFFFF
+#define int16_value 0x0000FFFF
+#define double_value 3.1415926
+#define string_value "test"
+
+static void
+test(void)
+{
+   static int n = 0;
+
+   n++;
+   if (n == NTESTS)
+    printf("Passed in all tests\n");
+}
+
+static void
+_on_send_bool(void *data, const EDBus_Message *msg, EDBus_Pending *pending)
+{
+   const char *errname, *errmsg;
+   Eina_Bool bool;
+   if (edbus_message_error_get(msg, &errname, &errmsg))
+     {
+        fprintf(stderr, "Error: %s %s\n", errname, errmsg);
+        return;
+     }
+
+   if (!edbus_message_arguments_get(msg, "b", &bool))
+     {
+        fprintf(stderr, "Error: could not get entry contents\n");
+        return;
+     }
+
+   if (bool != bool_value) printf("Error on bool\n");
+   else test();
+}
+
+static void
+_on_send_byte(void *data, const EDBus_Message *msg, EDBus_Pending *pending)
+{
+   const char *errname, *errmsg;
+   unsigned char byte;
+   if (edbus_message_error_get(msg, &errname, &errmsg))
+     {
+        fprintf(stderr, "Error: %s %s\n", errname, errmsg);
+        return;
+     }
+
+   if (!edbus_message_arguments_get(msg, "y", &byte))
+     {
+        fprintf(stderr, "Error: could not get entry contents\n");
+        return;
+     }
+
+   if (byte != byte_value) printf("Error on byte\n");
+   else test();
+}
+
+static void
+_on_send_uint32(void *data, const EDBus_Message *msg, EDBus_Pending *pending)
+{
+   const char *errname, *errmsg;
+   unsigned int uint32;
+   if (edbus_message_error_get(msg, &errname, &errmsg))
+     {
+        fprintf(stderr, "Error: %s %s\n", errname, errmsg);
+        return;
+     }
+
+   if (!edbus_message_arguments_get(msg, "u", &uint32))
+     {
+        fprintf(stderr, "Error: could not get entry contents\n");
+        return;
+     }
+
+   if (uint32 != uint32_value) printf("Error on uint32\n");
+   else test();
+}
+
+static void
+_on_send_int32(void *data, const EDBus_Message *msg, EDBus_Pending *pending)
+{
+   const char *errname, *errmsg;
+   int int32;
+   if (edbus_message_error_get(msg, &errname, &errmsg))
+     {
+        fprintf(stderr, "Error: %s %s\n", errname, errmsg);
+        return;
+     }
+
+   if (!edbus_message_arguments_get(msg, "i", &int32))
+     {
+        fprintf(stderr, "Error: could not get entry contents\n");
+        return;
+     }
+
+   if (int32 != (int)int32_value) printf("Error on int32\n");
+   else test();
+}
+
+static void
+_on_send_int16(void *data, const EDBus_Message *msg, EDBus_Pending *pending)
+{
+   const char *errname, *errmsg;
+   short int int16;
+   if (edbus_message_error_get(msg, &errname, &errmsg))
+     {
+        fprintf(stderr, "Error: %s %s\n", errname, errmsg);
+        return;
+     }
+
+   if (!edbus_message_arguments_get(msg, "n", &int16))
+     {
+        fprintf(stderr, "Error: could not get entry contents\n");
+        return;
+     }
+
+   if (int16 != (short int)int16_value) printf("Error on int16\n");
+   else test();
+}
+
+static void
+_on_send_double(void *data, const EDBus_Message *msg, EDBus_Pending *pending)
+{
+   const char *errname, *errmsg;
+   double d;
+   if (edbus_message_error_get(msg, &errname, &errmsg))
+     {
+        fprintf(stderr, "Error: %s %s\n", errname, errmsg);
+        return;
+     }
+
+   if (!edbus_message_arguments_get(msg, "d", &d))
+     {
+        fprintf(stderr, "Error: could not get entry contents\n");
+        return;
+     }
+
+   if (d != double_value) printf("Error on double\n");
+   else test();
+}
+
+static void
+_on_send_string(void *data, const EDBus_Message *msg, EDBus_Pending *pending)
+{
+   const char *errname, *errmsg;
+   char *str;
+   if (edbus_message_error_get(msg, &errname, &errmsg))
+     {
+        fprintf(stderr, "Error: %s %s\n", errname, errmsg);
+        return;
+     }
+
+   if (!edbus_message_arguments_get(msg, "s", &str))
+     {
+        fprintf(stderr, "Error: could not get entry contents\n");
+        return;
+     }
+
+   if (strcmp(str, string_value)) printf("Error on string\n");
+   else test();
+}
+
+static void
+_on_async_test(void *data, const EDBus_Message *msg, EDBus_Pending *pending)
+{
+   const char *errname, *errmsg;
+   char *str;
+   if (edbus_message_error_get(msg, &errname, &errmsg))
+     {
+        fprintf(stderr, "Error: %s %s\n", errname, errmsg);
+        return;
+     }
+
+   if (!edbus_message_arguments_get(msg, "s", &str))
+     {
+        fprintf(stderr, "Error: could not get entry contents\n");
+        return;
+     }
+
+   printf("%s\n", str);
+}
+
+static void
+on_name_owner_changed2(void *data, const char *bus, const char *old_id, const char *new_id)
+{
+   printf("2 - Bus=%s | old=%s | new=%s\n", bus, old_id, new_id);
+}
+
+static void
+on_name_owner_changed(void *data, const char *bus, const char *old_id, const char *new_id)
+{
+   printf("Bus=%s | old=%s | new=%s\n", bus, old_id, new_id);
+}
+
+static Eina_Bool
+add_name_owner2(void *data)
+{
+   EDBus_Connection *conn = data;
+   edbus_name_owner_changed_callback_add(conn, BUS, on_name_owner_changed2,
+                                        NULL, EINA_TRUE);
+   return EINA_FALSE;
+}
+
+int
+main(void)
+{
+   EDBus_Connection *conn;
+   EDBus_Object *obj;
+   EDBus_Proxy *proxy;
+
+   ecore_init();
+   edbus_init();
+
+   conn = edbus_connection_get(EDBUS_CONNECTION_TYPE_SESSION);
+
+   obj = edbus_object_get(conn, BUS, PATH);
+   proxy = edbus_proxy_get(obj, INTERFACE);
+   edbus_proxy_signal_handler_add(proxy, "Alive", _on_alive, NULL);
+   sh = edbus_proxy_signal_handler_add(proxy, "Alive", _on_alive2, NULL);
+   edbus_proxy_signal_handler_add(proxy, "Hello", _on_hello, NULL);
+
+   edbus_proxy_call(proxy, "SendBool", _on_send_bool, NULL, -1, "b", bool_value);
+   edbus_proxy_call(proxy, "SendByte", _on_send_byte, NULL, -1, "y", byte_value);
+   edbus_proxy_call(proxy, "SendUint32", _on_send_uint32, NULL, -1, "u", uint32_value);
+   edbus_proxy_call(proxy, "SendInt32", _on_send_int32, NULL, -1, "i", int32_value);
+   edbus_proxy_call(proxy, "SendInt16", _on_send_int16, NULL, -1, "n", int16_value);
+   edbus_proxy_call(proxy, "SendDouble", _on_send_double, NULL, -1, "d", double_value);
+   edbus_proxy_call(proxy, "SendString", _on_send_string, NULL, -1, "s", string_value);
+   edbus_proxy_call(proxy, "AsyncTest", _on_async_test, NULL, -1, "");
+
+   edbus_name_owner_changed_callback_add(conn, BUS, on_name_owner_changed,
+                                         conn, EINA_TRUE);
+   ecore_timer_add(3, add_name_owner2, conn);
+
+   ecore_main_loop_begin();
+
+   edbus_name_owner_changed_callback_del(conn, BUS, on_name_owner_changed, conn);
+   edbus_name_owner_changed_callback_del(conn, BUS, on_name_owner_changed2,
+                                         NULL);
+   edbus_connection_unref(conn);
+
+   edbus_shutdown();
+   ecore_shutdown();
+   return 0;
+}
diff --git a/src/examples/complex_types.c b/src/examples/complex_types.c
new file mode 100644 (file)
index 0000000..9b8c164
--- /dev/null
@@ -0,0 +1,284 @@
+#include "EDBus.h"
+#include <Ecore.h>
+
+#define BUS "com.profusion"
+#define PATH "/com/profusion/Test"
+#define IFACE "com.profusion.Test"
+
+EDBus_Connection *conn;
+
+static Eina_Bool
+_timer1_cb(void *data)
+{
+   printf("\n## ecore_main_loop_quit()\n");
+   ecore_main_loop_quit();
+   return EINA_TRUE;
+}
+
+static void
+on_plus_one(void *data, const EDBus_Message *msg, EDBus_Pending *pending)
+{
+   int num2 = 0;
+
+   if (edbus_message_error_get(msg, NULL, NULL))
+     {
+        printf("Message error\n\n");
+        return;
+     }
+   if (!edbus_message_arguments_get(msg, "i", &num2))
+     {
+        printf("Error getting arguments.");
+        return;
+     }
+
+   printf("on_plus_one() %d\n", num2);
+}
+
+static void
+set_property_resp2(void *data, const EDBus_Message *msg, EDBus_Pending *pending)
+{
+   const char *errname;
+   const char *errmsg;
+
+   printf("set_property_resp2()\n");
+   if (edbus_message_error_get(msg, &errname, &errmsg))
+     {
+        printf("Message error %s - %s\n\n", errname, errmsg);
+        return;
+     }
+}
+
+static void
+get_property_resp2(void *data, const EDBus_Message *msg, EDBus_Pending *pending)
+{
+   EDBus_Proxy *proxy = data;
+   EDBus_Message_Iter *variant = NULL;
+   char *type;
+   char *resp2;
+   const char *errname;
+   const char *errmsg;
+
+   printf("get_property_resp2()\n");
+   if (edbus_message_error_get(msg, &errname, &errmsg))
+     {
+        printf("Message error %s - %s\n\n", errname, errmsg);
+        return;
+     }
+   if (!edbus_message_arguments_get(msg, "v", &variant))
+     {
+        printf("Error getting arguments.");
+        return;
+     }
+
+   type = edbus_message_iter_signature_get(variant);
+   if (type[1])
+     {
+        printf("It is a complex type, not handle yet.\n\n");
+        return;
+     }
+   if (type[0] != 's')
+     {
+        printf("Expected type is string.\n\n");
+        return;
+     }
+   if (!edbus_message_iter_arguments_get(variant, "s", &resp2))
+     {
+        printf("error in edbus_message_iter_arguments_get()\n\n");
+        return;
+     }
+   printf("resp2=%s\n", resp2);
+   free(type);
+
+   edbus_proxy_property_set(proxy, "Resp2", 's', "lalala", set_property_resp2, NULL);
+}
+
+static void
+on_send_array_int(void *data, const EDBus_Message *msg, EDBus_Pending *pending)
+{
+   EDBus_Message_Iter *array = NULL;
+   int num;
+
+   printf("on_send_array_int()\n");
+   if (edbus_message_error_get(msg, NULL, NULL))
+     {
+        printf("Message error\n\n");
+        return;
+     }
+   if (!edbus_message_arguments_get(msg, "ai", &array))
+     {
+        printf("Error getting arguments.");
+        return;
+     }
+
+   while (edbus_message_iter_get_and_next(array, 'i', &num))
+     {
+        printf("%d\n", num);
+     }
+}
+
+static void
+on_send_array(void *data, const EDBus_Message *msg, EDBus_Pending *pending)
+{
+   EDBus_Message_Iter *array = NULL;
+   char *txt = NULL;
+   char *string[10];
+   int i = 0;
+   int z;
+
+   printf("on_send_array()\n");
+   if (edbus_message_error_get(msg, NULL, NULL))
+     {
+        printf("Message error\n\n");
+        return;
+     }
+   if (!edbus_message_arguments_get(msg, "as", &array))
+     {
+        printf("Error getting arguments.");
+        return;
+     }
+
+   while (edbus_message_iter_get_and_next(array, 's', &txt))
+     {
+        string[i] = txt;
+        i++;
+     }
+
+   for (z = 0; z < i; z++)
+     printf("string = %s\n", string[z]);
+}
+
+static void
+on_receive_array_with_size(void *data, const EDBus_Message *msg, EDBus_Pending *pending)
+{
+   const char *errname;
+   const char *errmsg;
+
+   printf("on_receive_array_with_size()\n");
+   if (edbus_message_error_get(msg, &errname, &errmsg))
+     {
+        fprintf(stderr, "Error: %s %s\n", errname, errmsg);
+     }
+}
+
+static void
+on_send_variant(void *data, const EDBus_Message *msg, EDBus_Pending *pending)
+{
+   printf("on_send_variant()\n\n");
+}
+
+static void
+on_receive_array(void *data, const EDBus_Message *msg, EDBus_Pending *pending)
+{
+   const char *errname;
+   const char *errmsg;
+
+   printf("on_receive_array()\n");
+   if (edbus_message_error_get(msg, &errname, &errmsg))
+     {
+        fprintf(stderr, "Error: %s %s\n", errname, errmsg);
+     }
+}
+
+int
+main(void)
+{
+   EDBus_Object *test2_obj;
+   EDBus_Proxy *test2_proxy;
+   EDBus_Pending *pending;
+   EDBus_Message_Iter *iter, *array_of_string, *variant;
+   EDBus_Message_Iter *array_itr, *structure;
+   EDBus_Message *msg;
+   int size_of_array = 5;
+   const char *array[5] = { "aaaa", "bbbb", "cccc", "dddd", "eeee" };
+   int i;
+   int plus_one = 24;
+
+   ecore_init();
+   edbus_init();
+
+   conn = edbus_connection_get(EDBUS_CONNECTION_TYPE_SESSION);
+
+   test2_obj = edbus_object_get(conn, BUS, PATH);
+   test2_proxy = edbus_proxy_get(test2_obj, IFACE);
+
+   msg = edbus_proxy_method_call_new(test2_proxy, "ReceiveArray");
+   iter = edbus_message_iter_get(msg);
+   array_of_string = edbus_message_iter_container_new(iter, 'a',"s");
+   if (!array_of_string) printf("array_of_string == NULL\n\n");
+   for (i = 0; i < 5; i++)
+     edbus_message_iter_basic_append(array_of_string, 's', array[i]);
+   edbus_message_iter_container_close(iter, array_of_string);
+   pending = edbus_proxy_send(test2_proxy, msg, on_receive_array, NULL, -1);
+   if (!pending) printf("Error in edbus_proxy_send()\n\n");
+   edbus_message_unref(msg);
+
+   msg = edbus_proxy_method_call_new(test2_proxy, "ReceiveArrayOfStringIntWithSize");
+   iter = edbus_message_iter_get(msg);
+   if (!edbus_message_iter_arguments_set(iter, "ia(si)", size_of_array, &array_of_string))
+     printf("error on edbus_massage_iterator_arguments_set()\n\n");
+   for (i = 0; i < size_of_array; i++)
+     {
+         EDBus_Message_Iter *struct_of_si;
+         edbus_message_iter_arguments_set(array_of_string, "(si)", &struct_of_si);
+         edbus_message_iter_arguments_set(struct_of_si, "si", array[i], i);
+         edbus_message_iter_container_close(array_of_string, struct_of_si);
+     }
+   edbus_message_iter_container_close(iter, array_of_string);
+   pending = edbus_proxy_send(test2_proxy, msg, on_receive_array_with_size, NULL, -1);
+   edbus_message_unref(msg);
+
+   msg = edbus_proxy_method_call_new(test2_proxy, "SendVariantData");
+   iter = edbus_message_iter_get(msg);
+   variant = edbus_message_iter_container_new(iter, 'v', "s");
+   edbus_message_iter_basic_append(variant, 's', "test");
+   edbus_message_iter_container_close(iter, variant);
+   pending = edbus_proxy_send(test2_proxy, msg, on_send_variant, NULL, -1);
+   edbus_message_unref(msg);
+
+   msg = edbus_proxy_method_call_new(test2_proxy, "DoubleContainner");
+   iter = edbus_message_iter_get(msg);
+   /**
+    * edbus_message_iterator_arguments_set(itr, "a(ii)a(ii)", &array_itr, &array_itr2);
+    * this will cause a error, we could not open another container until
+    * we close the first one
+    */
+   edbus_message_iter_arguments_set(iter, "a(ii)", &array_itr);
+   for (i = 0; i < 5; i++)
+     {
+        edbus_message_iter_arguments_set(array_itr, "(ii)", &structure);
+        edbus_message_iter_arguments_set(structure, "ii", i, i*i);
+        edbus_message_iter_container_close(array_itr, structure);
+     }
+   edbus_message_iter_container_close(iter, array_itr);
+   edbus_message_iter_arguments_set(iter, "a(ii)", &array_itr);
+   for (i = 0; i < 7; i++)
+     {
+        edbus_message_iter_arguments_set(array_itr, "(ii)", &structure);
+        edbus_message_iter_arguments_set(structure, "ii", i, i*i*i);
+        edbus_message_iter_container_close(array_itr, structure);
+     }
+   edbus_message_iter_container_close(iter, array_itr);
+   edbus_proxy_send(test2_proxy, msg, NULL, NULL, -1);
+   edbus_message_unref(msg);
+
+   pending = edbus_proxy_call(test2_proxy, "SendArrayInt", on_send_array_int, NULL,
+                                 -1 , "");
+
+   pending = edbus_proxy_call(test2_proxy, "SendArray", on_send_array, NULL,
+                              -1 , "");
+
+   pending = edbus_proxy_call(test2_proxy, "PlusOne", on_plus_one, NULL,
+                              -1 , "i", plus_one);
+
+   pending = edbus_proxy_property_get(test2_proxy, "Resp2", get_property_resp2, test2_proxy);
+
+   ecore_timer_add(10, _timer1_cb, NULL);
+
+   ecore_main_loop_begin();
+
+   edbus_connection_unref(conn);
+
+   edbus_shutdown();
+   ecore_shutdown();
+   return 0;
+}
diff --git a/src/examples/complex_types_client_eina_value.c b/src/examples/complex_types_client_eina_value.c
new file mode 100644 (file)
index 0000000..f5dcfb4
--- /dev/null
@@ -0,0 +1,272 @@
+#include "EDBus.h"
+#include <Ecore.h>
+
+#define BUS "com.profusion"
+#define PATH "/com/profusion/Test"
+#define IFACE "com.profusion.Test"
+
+#define size_of_array 5
+static const char *array_string[] = {
+   "aaaa", "bbbb", "cccc", "dddd", "eeee"
+};
+
+typedef struct _sub_struct
+{
+   char *txt;
+   int num;
+} sub_struct;
+
+typedef struct _main_struct
+{
+   int size;
+   sub_struct array[];
+} main_struct;
+
+static unsigned int
+_type_offset(unsigned base, unsigned size)
+{
+   unsigned padding;
+   if (!(base % size))
+     return base;
+   padding = abs(base - size);
+   return base + padding;
+}
+
+static void
+_fill_receive_array_of_string_int_with_size(EDBus_Message *msg, int size, const char *array[])
+{
+   Eina_Value *value_struct, *value_array;
+   int i;
+   unsigned offset;
+   Eina_Value_Struct_Member main_members[2];
+   Eina_Value_Struct_Member sub_members[] = {
+      EINA_VALUE_STRUCT_MEMBER(EINA_VALUE_TYPE_STRING, sub_struct, txt),
+      EINA_VALUE_STRUCT_MEMBER(EINA_VALUE_TYPE_INT, sub_struct, num)
+   };
+   Eina_Value_Struct_Desc desc_sub_struct = {
+      EINA_VALUE_STRUCT_DESC_VERSION,
+      NULL, // no special operations
+      sub_members,
+      2,
+      sizeof(sub_struct)
+   };
+   Eina_Value_Struct_Desc desc_struct = {
+      EINA_VALUE_STRUCT_DESC_VERSION,
+      NULL, // no special operations
+      main_members,
+      2,
+      0//will be set below
+   };
+
+   offset = _type_offset(sizeof(int), sizeof(Eina_Value_Array));
+   main_members[0].name = "size";
+   main_members[0].type = EINA_VALUE_TYPE_INT, 0;
+   main_members[0].offset = 0;
+   main_members[1].name = "array";
+   main_members[1].type = EINA_VALUE_TYPE_ARRAY;
+   main_members[1].offset = offset;
+   desc_struct.size = offset + sizeof(Eina_Value_Array);
+
+   value_struct = eina_value_struct_new(&desc_struct);
+   eina_value_struct_set(value_struct, "size", size);
+
+   value_array = eina_value_array_new(EINA_VALUE_TYPE_STRUCT, size);
+   for (i = 0; i < size; i++)
+     {
+        Eina_Value *value_sub_struct = eina_value_struct_new(&desc_sub_struct);
+        Eina_Value_Struct st;
+        eina_value_struct_set(value_sub_struct, "txt", array[i]);
+        eina_value_struct_set(value_sub_struct, "num", i);
+        eina_value_get(value_sub_struct, &st);
+        eina_value_array_append(value_array, st);
+        eina_value_free(value_sub_struct);
+     }
+   eina_value_struct_value_set(value_struct, "array", value_array);
+
+   edbus_message_from_eina_value("ia(si)", msg, value_struct);
+
+   eina_value_free(value_struct);
+   eina_value_free(value_array);
+}
+
+static void
+on_send_array(void *data, const EDBus_Message *msg, EDBus_Pending *pending)
+{
+   Eina_Value *v, array;
+   const char *txt;
+   unsigned i;
+   printf("2 - on_send_array()\n");
+
+   if (edbus_message_error_get(msg, NULL, NULL))
+     {
+        printf("Message error\n\n");
+        return;
+     }
+
+   v = edbus_message_to_eina_value(msg);
+   eina_value_struct_value_get(v, "arg0", &array);
+   for (i = 0; i < eina_value_array_count(&array); i++)
+     {
+        eina_value_array_get(&array, i, &txt);
+        printf("\t%s\n", txt);
+     }
+
+   eina_value_free(v);
+   eina_value_flush(&array);
+}
+
+static void
+on_receive_array_with_size(void *data, const EDBus_Message *msg, EDBus_Pending *pending)
+{
+   const char *errname;
+   const char *errmsg;
+
+   printf("1 - on_receive_array_with_size()\n");
+   if (edbus_message_error_get(msg, &errname, &errmsg))
+     {
+        fprintf(stderr, "Error: %s %s\n", errname, errmsg);
+     }
+}
+
+static void
+on_plus_one(void *data, const EDBus_Message *msg, EDBus_Pending *pending)
+{
+   Eina_Value *v;
+   int num2;
+
+   if (edbus_message_error_get(msg, NULL, NULL))
+     {
+        printf("Message error\n\n");
+        return;
+     }
+
+   v = edbus_message_to_eina_value(msg);
+   eina_value_struct_get(v, "arg0", &num2);
+
+   printf("3 - on_plus_one() %d\n", num2);
+   eina_value_free(v);
+}
+
+static void
+_property_changed(void *data, EDBus_Proxy *proxy, void *event_info)
+{
+   EDBus_Proxy_Event_Property_Changed *event = event_info;
+   const char *name;
+   const Eina_Value *value;
+   printf("\nproperty changed\n");
+
+   name = event->name;
+   value = event->value;
+
+   if (!strcmp(name, "text"))
+     {
+        const char *txt;
+        eina_value_get(value, &txt);
+        printf("[%s] = %s\n", name, txt);
+     }
+   else if (!strcmp(name, "int32"))
+     {
+        int num;
+        eina_value_get(value, &num);
+        printf("[%s] = %d\n", name, num);
+     }
+   else if (!strcmp(name, "st"))
+     {
+        const char *txt;
+        eina_value_struct_get(value, "arg0", &txt);
+        printf("[%s] %s | ", name, txt);
+        eina_value_struct_get(value, "arg1", &txt);
+        printf("%s\n", txt);
+     }
+}
+
+static Eina_Bool
+_read_cache(void *data)
+{
+   EDBus_Proxy *proxy = data;
+   const char *txt;
+   int num;
+   Eina_Value *v;
+
+   v = edbus_proxy_property_local_get(proxy, "text");
+   eina_value_get(v, &txt);
+   printf("Read cache: [txt] = %s\n", txt);
+
+   v = edbus_proxy_property_local_get(proxy, "int32");
+   eina_value_get(v, &num);
+   printf("Read cache: [int32] = %d\n", num);
+
+   v = edbus_proxy_property_local_get(proxy, "st");
+   eina_value_struct_get(v, "arg0", &txt);
+   printf("Read cache: [st] %s | ", txt);
+   eina_value_struct_get(v, "arg1", &txt);
+   printf("%s\n", txt);
+
+   return EINA_FALSE;
+}
+
+static void
+_fill_plus_one(EDBus_Message *msg, int num)
+{
+   Eina_Value *v;
+   Eina_Value_Struct_Member main_members[] = {
+      {"num", EINA_VALUE_TYPE_INT, 0}
+   };
+   Eina_Value_Struct_Desc desc_struct = {
+         EINA_VALUE_STRUCT_DESC_VERSION,
+         NULL, // no special operations
+         main_members,
+         1,
+         sizeof(int)
+   };
+   v = eina_value_struct_new(&desc_struct);
+   eina_value_struct_set(v, "num", num);
+
+   edbus_message_from_eina_value("i", msg, v);
+
+   eina_value_free(v);
+}
+
+int
+main(void)
+{
+   EDBus_Connection *conn;
+   EDBus_Object *obj;
+   EDBus_Proxy *proxy;
+   EDBus_Message *msg;
+
+   ecore_init();
+   edbus_init();
+
+   conn = edbus_connection_get(EDBUS_CONNECTION_TYPE_SESSION);
+   obj = edbus_object_get(conn, BUS, PATH);
+   proxy = edbus_proxy_get(obj, IFACE);
+
+   msg = edbus_proxy_method_call_new(proxy, "ReceiveArrayOfStringIntWithSize");
+   _fill_receive_array_of_string_int_with_size(msg, size_of_array, array_string);
+   edbus_proxy_send(proxy, msg, on_receive_array_with_size, NULL, -1);
+   edbus_message_unref(msg);
+
+   edbus_proxy_call(proxy, "SendArray", on_send_array, NULL, -1 , "");
+
+   msg = edbus_proxy_method_call_new(proxy, "PlusOne");
+   _fill_plus_one(msg, 14);
+   edbus_proxy_send(proxy, msg, on_plus_one, NULL, -1);
+   edbus_message_unref(msg);
+
+   edbus_proxy_event_callback_add(proxy,
+                                  EDBUS_PROXY_EVENT_PROPERTY_CHANGED,
+                                  _property_changed, NULL);
+
+   ecore_timer_add(10, _read_cache, proxy);
+
+   ecore_main_loop_begin();
+
+   edbus_proxy_event_callback_del(proxy, EDBUS_PROXY_EVENT_PROPERTY_CHANGED,
+                                  _property_changed, NULL);
+   edbus_connection_unref(conn);
+
+   edbus_shutdown();
+   ecore_shutdown();
+   return 0;
+}
diff --git a/src/examples/complex_types_server.c b/src/examples/complex_types_server.c
new file mode 100644 (file)
index 0000000..b958a4e
--- /dev/null
@@ -0,0 +1,398 @@
+#include "EDBus.h"
+#include <Ecore.h>
+
+#define BUS "com.profusion"
+#define PATH "/com/profusion/Test"
+#define IFACE "com.profusion.Test"
+
+static char *resp2;
+
+static EDBus_Message *
+_receive_array(const EDBus_Service_Interface *iface, const EDBus_Message *msg)
+{
+   EDBus_Message *reply = edbus_message_method_return_new(msg);
+   EDBus_Message_Iter *array;
+   char *txt;
+
+   printf("receiveArray\n");
+   if (!edbus_message_arguments_get(msg, "as", &array))
+     {
+        printf("Error on edbus_message_arguments_get()\n");
+        return reply;
+     }
+
+   while (edbus_message_iter_get_and_next(array, 's', &txt))
+     printf("%s\n", txt);
+
+   printf("\n");
+
+   return reply;
+}
+
+static EDBus_Message *
+_receive_array_of_string_int_with_size(const EDBus_Service_Interface *iface, const EDBus_Message *msg)
+{
+   EDBus_Message *reply = edbus_message_method_return_new(msg);
+   EDBus_Message_Iter *array;
+   EDBus_Message_Iter *struct_si;
+   int size, i = 0;
+
+   printf("receiveArrayOfStringIntWithSize\n");
+   if (!edbus_message_arguments_get(msg, "ia(si)", &size, &array))
+     {
+        printf("Error on edbus_message_arguments_get()\n");
+        return reply;
+     }
+
+   while (edbus_message_iter_get_and_next(array, 'r', &struct_si))
+     {
+        char *txt;
+        int num;
+
+        if (!edbus_message_iter_arguments_get(struct_si, "si", &txt, &num))
+          {
+             printf("Error on edbus_message_arguments_get()\n");
+             return reply;
+          }
+        printf("%s | %d\n", txt, num);
+        i++;
+     }
+   printf("size in msg %d | size read %d\n", size, i);
+   printf("\n");
+
+   return reply;
+}
+
+static EDBus_Message *
+_send_variant(const EDBus_Service_Interface *iface, const EDBus_Message *msg)
+{
+   EDBus_Message *reply = edbus_message_method_return_new(msg);
+   EDBus_Message_Iter *variant;
+   char *type;
+
+   printf("sendVariantData\n");
+   if (!edbus_message_arguments_get(msg, "v", &variant))
+     {
+        printf("Error on edbus_message_arguments_get()\n");
+        return reply;
+     }
+
+   type = edbus_message_iter_signature_get(variant);
+   if (type[1] || type[0] == 'v')
+     {
+        printf("It is a complex type, not handle yet.\n");
+        free(type);
+        return reply;
+     }
+
+   switch (type[0])
+     {
+      case 's':
+      case 'o':
+        {
+           char *txt;
+           edbus_message_iter_arguments_get(variant, type, &txt);
+           printf("type = %c value = %s\n", type[0], txt);
+           break;
+        }
+      case 'i':
+        {
+           int num;
+           edbus_message_iter_arguments_get(variant, type, &num);
+           printf("type = %c value = %d\n", type[0], num);
+           break;
+        }
+      default:
+        {
+           printf("Unhandled type\n");
+        }
+     }
+
+   printf("\n");
+
+   free(type);
+   return reply;
+}
+
+static EDBus_Message *
+_send_array_int(const EDBus_Service_Interface *iface, const EDBus_Message *msg)
+{
+   EDBus_Message *reply = edbus_message_method_return_new(msg);
+   EDBus_Message_Iter *iter, *array;
+   int i;
+
+   printf("sendArrayInt\n\n");
+
+   iter = edbus_message_iter_get(reply);
+   array = edbus_message_iter_container_new(iter, 'a', "i");
+   for (i = 0; i < 5; i++)
+     edbus_message_iter_arguments_set(array, "i", i);
+   edbus_message_iter_container_close(iter, array);
+
+   return reply;
+}
+
+static EDBus_Message *
+_send_array(const EDBus_Service_Interface *iface, const EDBus_Message *msg)
+{
+   EDBus_Message *reply = edbus_message_method_return_new(msg);
+   EDBus_Message_Iter *iter, *array;
+   const char *array_string[5] = {"qqqq", "wwwww", "eeeeee", "rrrrr", "ttttt"};
+   int i;
+
+   printf("sendArray\n\n");
+
+   iter = edbus_message_iter_get(reply);
+   array = edbus_message_iter_container_new(iter, 'a', "s");
+   for (i = 0; i < 5; i++)
+     edbus_message_iter_arguments_set(array, "s", array_string[i]);
+   edbus_message_iter_container_close(iter, array);
+
+   return reply;
+}
+
+static EDBus_Message *
+_plus_one(const EDBus_Service_Interface *iface, const EDBus_Message *msg)
+{
+   EDBus_Message *reply = edbus_message_method_return_new(msg);
+   int num;
+
+   printf("plusOne\n\n");
+   if (!edbus_message_arguments_get(msg, "i", &num))
+     {
+        printf("Error on edbus_message_arguments_get()\n");
+        return reply;
+     }
+   num++;
+   edbus_message_arguments_set(reply, "i", num);
+
+   return reply;
+}
+
+static EDBus_Message *
+_double_container(const EDBus_Service_Interface *iface, const EDBus_Message *msg)
+{
+   EDBus_Message_Iter *array1, *array2, *structure;
+   int num1, num2;
+   EDBus_Message *reply = edbus_message_method_return_new(msg);
+
+   if (!edbus_message_arguments_get(msg, "a(ii)a(ii)", &array1, &array2))
+     {
+        printf("Error on edbus_message_arguments_get()\n");
+        return NULL;
+     }
+
+   printf("DoubleCountainer\nArray1:\n");
+   while (edbus_message_iter_get_and_next(array1, 'r', &structure))
+     {
+        edbus_message_iter_arguments_get(structure, "ii", &num1, &num2);
+        printf("1 %d - 2 %d\n", num1, num2);
+     }
+
+   printf("Array2:\n");
+   while (edbus_message_iter_get_and_next(array2, 'r', &structure))
+     {
+         edbus_message_iter_arguments_get(structure, "ii", &num1, &num2);
+         printf("1 %d - 2 %d\n", num1, num2);
+     }
+   printf("\n");
+   return reply;
+}
+
+static EDBus_Message *
+_properties_get(const EDBus_Service_Interface *iface, const EDBus_Message *msg)
+{
+   EDBus_Message *reply;
+   char *interface, *property;
+   EDBus_Message_Iter *variant, *iter;
+
+   if (!edbus_message_arguments_get(msg, "ss", &interface, &property))
+     {
+        printf("Error on edbus_message_arguments_get()\n");
+        return NULL;
+     }
+
+   if (strcmp(interface, IFACE))
+     {
+        reply = edbus_message_error_new(msg,
+                                        "org.freedesktop.DBus.Error.UnknownInterface",
+                                        "Interface not found.");
+        return reply;
+     }
+
+   if (strcmp(property, "Resp2"))
+     {
+        reply = edbus_message_error_new(msg,
+                                        "org.freedesktop.DBus.Error.UnknownProperty",
+                                        "Property not found.");
+        return reply;
+     }
+
+   reply = edbus_message_method_return_new(msg);
+   iter = edbus_message_iter_get(reply);
+   variant = edbus_message_iter_container_new(iter, 'v', "s");
+   edbus_message_iter_basic_append(variant, 's', resp2);
+   printf("get %s\n", resp2);
+   edbus_message_iter_container_close(iter, variant);
+
+   return reply;
+}
+
+static EDBus_Message *
+_properties_set(const EDBus_Service_Interface *iface, const EDBus_Message *msg)
+{
+   EDBus_Message *reply;
+   char *interface, *property, *type, *txt;
+   EDBus_Message_Iter *variant;
+
+   if (!edbus_message_arguments_get(msg, "ssv", &interface, &property, &variant))
+     {
+        printf("Error on edbus_message_arguments_get()\n");
+        return NULL;
+     }
+
+   if (strcmp(interface, IFACE))
+     {
+        reply = edbus_message_error_new(msg,
+                                        "org.freedesktop.DBus.Error.UnknownInterface",
+                                        "Interface not found.");
+        return reply;
+     }
+
+   if (strcmp(property, "Resp2"))
+     {
+        reply = edbus_message_error_new(msg,
+                                        "org.freedesktop.DBus.Error.UnknownProperty",
+                                        "Property not found.");
+        return reply;
+     }
+
+   type = edbus_message_iter_signature_get(variant);
+
+   if (type[0] != 's')
+     {
+        reply = edbus_message_error_new(msg, "org.freedesktop.DBus.Error.InvalidSignature",
+                                         "Invalid type.");
+        free(type);
+        return reply;
+     }
+
+   reply = edbus_message_method_return_new(msg);
+   edbus_message_iter_arguments_get(variant, "s", &txt);
+   free(type);
+   free(resp2);
+   resp2 = strdup(txt);
+
+   return reply;
+}
+
+static const EDBus_Method methods[] = {
+      {
+        "ReceiveArray", EDBUS_ARGS({"as", "array_of_strings"}),
+        NULL, _receive_array, 0
+      },
+      {
+        "ReceiveArrayOfStringIntWithSize",
+        EDBUS_ARGS({"i", "size_of_array"}, {"a(si)", "array"}),
+        NULL, _receive_array_of_string_int_with_size, 0
+      },
+      {
+        "SendVariantData", EDBUS_ARGS({"v", "variant_data"}),
+        NULL, _send_variant, 0
+      },
+      {
+        "SendArrayInt", NULL,
+        EDBUS_ARGS({"ai", "array_of_int"}), _send_array_int, 0
+      },
+      {
+        "SendArray", NULL, EDBUS_ARGS({"as", "array_string"}),
+        _send_array, 0
+      },
+      {
+        "PlusOne", EDBUS_ARGS({"i", "integer"}),
+        EDBUS_ARGS({"i", "integer_plus_one"}), _plus_one, 0
+      },
+      {
+        "DoubleContainner", EDBUS_ARGS({"a(ii)", "array1"}, {"a(ii)", "array2"}),
+        NULL, _double_container, 0
+      },
+      { }
+};
+
+static const EDBus_Method properties_methods[] = {
+      {
+        "Get", EDBUS_ARGS({"s", "interface"}, {"s", "property"}),
+        EDBUS_ARGS({"v", "value"}), _properties_get, 0
+      },
+      {
+        "Set", EDBUS_ARGS({"s", "interface"}, {"s", "property"}, {"v", "value"}),
+        NULL, _properties_set, 0
+      },
+      { }
+};
+
+
+/*
+ * Temporary way to test the PropertiesChanged signal in FDO Properties
+ * interface. TODO: Remove me when service part is done.
+ */
+static const EDBus_Signal properties_signals[] = {
+   { "PropertiesChanged",
+     EDBUS_ARGS({"s", "interface"}, {"a{sv}", "data"}, {"as", "invalidate"}), 0
+   },
+   { }
+};
+
+static const EDBus_Service_Interface_Desc iface_desc = {
+   IFACE, methods
+};
+
+static void
+on_name_request(void *data, const EDBus_Message *msg, EDBus_Pending *pending)
+{
+   unsigned int flag;
+
+   resp2 = malloc(sizeof(char) * 5);
+   strcpy(resp2, "test");
+
+   if (edbus_message_error_get(msg, NULL, NULL))
+     {
+        printf("error on on_name_request\n");
+        return;
+     }
+
+   if (!edbus_message_arguments_get(msg, "u", &flag))
+     {
+        printf("error geting arguments on on_name_request\n");
+        return;
+     }
+
+   if (!(flag & EDBUS_NAME_REQUEST_REPLY_PRIMARY_OWNER))
+     {
+        printf("error name already in use\n");
+        return;
+     }
+}
+
+int
+main(void)
+{
+   EDBus_Connection *conn;
+
+   ecore_init();
+   edbus_init();
+
+   conn = edbus_connection_get(EDBUS_CONNECTION_TYPE_SESSION);
+
+   edbus_service_interface_register(conn, PATH, &iface_desc);
+   edbus_name_request(conn, BUS, EDBUS_NAME_REQUEST_FLAG_DO_NOT_QUEUE, on_name_request, NULL);
+
+   ecore_main_loop_begin();
+
+   free(resp2);
+   edbus_connection_unref(conn);
+
+   edbus_shutdown();
+   ecore_shutdown();
+   return 0;
+}
diff --git a/src/examples/connman-list-services.c b/src/examples/connman-list-services.c
new file mode 100644 (file)
index 0000000..a192d8b
--- /dev/null
@@ -0,0 +1,107 @@
+#include "EDBus.h"
+#include <Ecore.h>
+
+static void
+on_services_get(void *data, const EDBus_Message *msg, EDBus_Pending *pending)
+{
+   EDBus_Message_Iter *array, *entry;
+   const char *errname, *errmsg;
+
+   if (edbus_message_error_get(msg, &errname, &errmsg))
+     {
+        fprintf(stderr, "Error: %s %s\n", errname, errmsg);
+        return;
+     }
+
+   if (!edbus_message_arguments_get(msg, "a(oa{sv})", &array))
+     {
+        fprintf(stderr, "Error: could not get array\n");
+        return;
+     }
+
+   while (edbus_message_iter_get_and_next(array, 'r', &entry))
+     {
+        EDBus_Message_Iter *properties, *dict_entry;
+        const char *path;
+
+        if (!edbus_message_iter_arguments_get(entry, "oa{sv}", &path, &properties))
+          {
+             fprintf(stderr, "Error: could not get entry contents\n");
+             return;
+          }
+
+        printf("service: %s\n", path);
+
+        while (edbus_message_iter_get_and_next(properties, 'e', &dict_entry))
+          {
+             EDBus_Message_Iter *variant;
+             const char *key;
+
+             if (!edbus_message_iter_arguments_get(dict_entry, "sv", &key,
+                                                      &variant))
+               {
+                  fprintf(stderr,
+                          "Error: could not get property contents\n");
+                  return;
+               }
+
+             printf("\t%s: type %s\n", key,
+                    edbus_message_iter_signature_get(variant));
+
+             /* TODO: get the value from variant */
+          }
+     }
+}
+
+int
+main(void)
+{
+   EDBus_Connection *conn;
+   EDBus_Object *obj;
+   EDBus_Proxy *manager;
+   EDBus_Pending *pending;
+
+   ecore_init();
+   edbus_init();
+
+   conn = edbus_connection_get(EDBUS_CONNECTION_TYPE_SYSTEM);
+   if (!conn)
+     {
+        fprintf(stderr, "Error: could not get system bus\n");
+        return EXIT_FAILURE;
+     }
+
+   obj = edbus_object_get(conn, "net.connman", "/");
+   if (!obj)
+     {
+        fprintf(stderr, "Error: could not get object\n");
+        return EXIT_FAILURE;
+     }
+
+   manager = edbus_proxy_get(obj, "net.connman.Manager");
+   if (!manager)
+     {
+        fprintf(stderr, "Error: could not get proxy\n");
+        return EXIT_FAILURE;
+     }
+
+   pending = edbus_proxy_call(manager, "GetServices", on_services_get, NULL,
+                              -1, "");
+
+   if (!pending)
+     {
+        fprintf(stderr, "Error: could not call\n");
+        return EXIT_FAILURE;
+     }
+
+   ecore_main_loop_begin();
+
+   edbus_proxy_unref(manager);
+   edbus_object_unref(obj);
+   edbus_connection_unref(conn);
+
+   edbus_shutdown();
+   ecore_shutdown();
+   return 0;
+}
+
diff --git a/src/examples/ofono-dial.c b/src/examples/ofono-dial.c
new file mode 100644 (file)
index 0000000..5e833dd
--- /dev/null
@@ -0,0 +1,85 @@
+#include "EDBus.h"
+#include <Ecore.h>
+
+static void
+on_dial(void *data, const EDBus_Message *msg, EDBus_Pending *pending)
+{
+   const char *errname, *errmsg;
+   const char *call_path;
+
+   if (edbus_message_error_get(msg, &errname, &errmsg))
+     {
+        fprintf(stderr, "Error: %s %s\n", errname, errmsg);
+        return;
+     }
+
+   if (!edbus_message_arguments_get(msg, "o", &call_path))
+     {
+        fprintf(stderr, "Error: could not get call path\n");
+        return;
+     }
+
+   printf("dialed! call path: %s\n", call_path);
+}
+
+int
+main(int argc, char *argv[])
+{
+   EDBus_Connection *conn;
+   EDBus_Object *obj;
+   EDBus_Proxy *manager;
+   EDBus_Pending *pending;
+   const char *number, *hide_callerid;
+
+   if (argc < 2)
+     {
+        fprintf(stderr, "Usage:\n\t%s <number> [hide_callerid]\n", argv[0]);
+        return EXIT_FAILURE;
+     }
+
+   number = argv[1];
+   hide_callerid = (argc > 2) ? argv[2] : "";
+
+   ecore_init();
+   edbus_init();
+
+   conn = edbus_connection_get(EDBUS_CONNECTION_TYPE_SYSTEM);
+   if (!conn)
+     {
+        fprintf(stderr, "Error: could not get system bus\n");
+        return EXIT_FAILURE;
+     }
+
+   obj = edbus_object_get(conn, "org.ofono", "/");
+   if (!obj)
+     {
+        fprintf(stderr, "Error: could not get object\n");
+        return EXIT_FAILURE;
+     }
+
+   manager = edbus_proxy_get(obj, "org.ofono.Manager");
+   if (!manager)
+     {
+        fprintf(stderr, "Error: could not get proxy\n");
+        return EXIT_FAILURE;
+     }
+
+   pending = edbus_proxy_call(manager, "Dial", on_dial, NULL,
+                              -1, "ss", number, hide_callerid);
+   if (!pending)
+     {
+        fprintf(stderr, "Error: could not call\n");
+        return EXIT_FAILURE;
+     }
+
+   ecore_main_loop_begin();
+
+   edbus_proxy_unref(manager);
+   edbus_object_unref(obj);
+   edbus_connection_unref(conn);
+
+   edbus_shutdown();
+   ecore_shutdown();
+   return 0;
+}
+
diff --git a/src/examples/server.c b/src/examples/server.c
new file mode 100644 (file)
index 0000000..d2e733d
--- /dev/null
@@ -0,0 +1,242 @@
+#include "EDBus.h"
+#include <Ecore.h>
+
+#define BUS "org.Enlightenment"
+#define PATH "/org/enlightenment"
+#define INTERFACE "org.enlightenment.Test"
+
+EDBus_Connection *conn;
+
+static EDBus_Message *
+_hello(const EDBus_Service_Interface *iface, const EDBus_Message *message)
+{
+   EDBus_Message *reply = edbus_message_method_return_new(message);
+   edbus_message_arguments_set(reply, "s", "Hello World");
+   printf("Hello\n");
+   return reply;
+}
+
+static EDBus_Message *
+_quit(const EDBus_Service_Interface *iface, const EDBus_Message *message)
+{
+   printf("Quit\n");
+   ecore_main_loop_quit();
+   return edbus_message_method_return_new(message);
+}
+
+enum
+{
+   TEST_SIGNAL_ALIVE = 0,
+   TEST_SIGNAL_HELLO
+};
+
+static Eina_Bool
+send_signal_alive(void *data)
+{
+   EDBus_Service_Interface *iface = data;
+   edbus_service_signal_emit(iface, TEST_SIGNAL_ALIVE);
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+send_signal_hello(void *data)
+{
+   EDBus_Service_Interface *iface = data;
+   edbus_service_signal_emit(iface, TEST_SIGNAL_HELLO, "Hello World");
+   return ECORE_CALLBACK_RENEW;
+}
+
+static EDBus_Message *
+_send_bool(const EDBus_Service_Interface *iface, const EDBus_Message *msg)
+{
+   EDBus_Message *reply = edbus_message_method_return_new(msg);
+   Eina_Bool bool;
+   if (!edbus_message_arguments_get(msg, "b", &bool))
+     printf("edbus_message_arguments_get() error\n");
+   edbus_message_arguments_set(reply, "b", bool);
+   return reply;
+}
+
+static EDBus_Message *
+_send_byte(const EDBus_Service_Interface *iface, const EDBus_Message *msg)
+{
+   EDBus_Message *reply = edbus_message_method_return_new(msg);
+   unsigned char byte;
+   if (!edbus_message_arguments_get(msg, "y", &byte))
+     printf("edbus_message_arguments_get() error\n");
+   edbus_message_arguments_set(reply, "y", byte);
+   return reply;
+}
+
+static EDBus_Message *
+_send_uint32(const EDBus_Service_Interface *iface, const EDBus_Message *msg)
+{
+   EDBus_Message *reply = edbus_message_method_return_new(msg);
+   unsigned int uint32;
+   if (!edbus_message_arguments_get(msg, "u", &uint32))
+     printf("edbus_message_arguments_get() error\n");
+   edbus_message_arguments_set(reply, "u", uint32);
+   return reply;
+}
+
+static EDBus_Message *
+_send_int32(const EDBus_Service_Interface *iface, const EDBus_Message *msg)
+{
+   EDBus_Message *reply = edbus_message_method_return_new(msg);
+   int int32;
+   if (!edbus_message_arguments_get(msg, "i", &int32))
+     printf("edbus_message_arguments_get() error\n");
+   edbus_message_arguments_set(reply, "i", int32);
+   return reply;
+}
+
+static EDBus_Message *
+_send_int16(const EDBus_Service_Interface *iface, const EDBus_Message *msg)
+{
+   EDBus_Message *reply = edbus_message_method_return_new(msg);
+   short int int16;
+   if (!edbus_message_arguments_get(msg, "n", &int16))
+     printf("edbus_message_arguments_get() error\n");
+   edbus_message_arguments_set(reply, "n", int16);
+   return reply;
+}
+
+static EDBus_Message *
+_send_double(const EDBus_Service_Interface *iface, const EDBus_Message *msg)
+{
+   EDBus_Message *reply = edbus_message_method_return_new(msg);
+   double d;
+   if (!edbus_message_arguments_get(msg, "d", &d))
+     printf("edbus_message_arguments_get() error\n");
+   edbus_message_arguments_set(reply, "d", d);
+   return reply;
+}
+
+static EDBus_Message *
+_send_string(const EDBus_Service_Interface *iface, const EDBus_Message *msg)
+{
+   EDBus_Message *reply = edbus_message_method_return_new(msg);
+   char *txt;
+   if (!edbus_message_arguments_get(msg, "s", &txt))
+     printf("edbus_message_arguments_get() error\n");
+   edbus_message_arguments_set(reply, "s", txt);
+   return reply;
+}
+
+static Eina_Bool
+_resp_async(void *data)
+{
+   EDBus_Message *msg = data;
+   edbus_message_arguments_set(msg, "s", "Async test ok");
+   edbus_connection_send(conn, msg, NULL, NULL, -1);
+   edbus_message_unref(msg);
+   return ECORE_CALLBACK_CANCEL;
+}
+
+static EDBus_Message *
+_async_test(const EDBus_Service_Interface *iface, const EDBus_Message *msg)
+{
+   EDBus_Message *reply = edbus_message_method_return_new(msg);
+   printf("Received a call to AsyncTest.\n");
+   printf("Response will be send in 5 seconds.\n");
+   ecore_timer_add (5, _resp_async, reply);
+   return NULL;
+}
+
+static const EDBus_Signal signals[] = {
+   [TEST_SIGNAL_ALIVE] = {"Alive", NULL, 0},
+   [TEST_SIGNAL_HELLO] = {"Hello", EDBUS_ARGS({ "s", "message" }), 0},
+   { }
+};
+
+static const EDBus_Method methods[] = {
+      {
+        "Hello", NULL, EDBUS_ARGS({"s", "message"}),
+        _hello, 0
+      },
+      {
+        "Quit", NULL, NULL,
+        _quit, EDBUS_METHOD_FLAG_DEPRECATED
+      },
+      { "SendBool", EDBUS_ARGS({"b", "bool"}), EDBUS_ARGS({"b", "bool"}),
+        _send_bool, 0
+      },
+      { "SendByte", EDBUS_ARGS({"y", "byte"}), EDBUS_ARGS({"y", "byte"}),
+        _send_byte, 0
+      },
+      { "SendUint32", EDBUS_ARGS({"u", "uint32"}), EDBUS_ARGS({"u", "uint32"}),
+        _send_uint32, 0
+      },
+      { "SendInt32", EDBUS_ARGS({"i", "int32"}), EDBUS_ARGS({"i", "int32"}),
+        _send_int32, 0
+      },
+      { "SendInt16", EDBUS_ARGS({"n", "int16"}), EDBUS_ARGS({"n", "int16"}),
+        _send_int16, 0
+      },
+      { "SendDouble", EDBUS_ARGS({"d", "double"}), EDBUS_ARGS({"d", "double"}),
+        _send_double, 0
+      },
+      { "SendString", EDBUS_ARGS({"s", "string"}), EDBUS_ARGS({"s", "string"}),
+        _send_string, 0
+      },
+      { "AsyncTest", NULL, EDBUS_ARGS({"s", "text"}),
+        _async_test, 0
+      },
+      { }
+};
+
+static const EDBus_Service_Interface_Desc iface_desc = {
+   INTERFACE, methods, signals
+};
+
+static void
+on_name_request(void *data, const EDBus_Message *msg, EDBus_Pending *pending)
+{
+   EDBus_Service_Interface *iface;
+   unsigned int flag;
+
+   iface = data;
+   if (edbus_message_error_get(msg, NULL, NULL))
+     {
+        printf("error on on_name_request\n");
+        return;
+     }
+
+   if (!edbus_message_arguments_get(msg, "u", &flag))
+    {
+       printf("error geting arguments on on_name_request\n");
+       return;
+    }
+
+   if (!(flag & EDBUS_NAME_REQUEST_REPLY_PRIMARY_OWNER))
+     {
+        printf("error name already in use\n");
+        return;
+     }
+
+   ecore_timer_add(5, send_signal_alive, iface);
+   ecore_timer_add(6, send_signal_hello, iface);
+}
+
+int
+main(void)
+{
+   EDBus_Service_Interface *iface;
+
+   ecore_init();
+   edbus_init();
+
+   conn = edbus_connection_get(EDBUS_CONNECTION_TYPE_SESSION);
+
+   iface = edbus_service_interface_register(conn, PATH, &iface_desc);
+   edbus_name_request(conn, BUS, EDBUS_NAME_REQUEST_FLAG_DO_NOT_QUEUE,
+                      on_name_request, iface);
+
+   ecore_main_loop_begin();
+
+   edbus_connection_unref(conn);
+
+   edbus_shutdown();
+   ecore_shutdown();
+   return 0;
+}
diff --git a/src/examples/simple-signal-emit.c b/src/examples/simple-signal-emit.c
new file mode 100644 (file)
index 0000000..e1e4816
--- /dev/null
@@ -0,0 +1,83 @@
+#include <EDBus.h>
+
+enum {
+   TEST_SIGNAL_ALIVE,
+   TEST_SIGNAL_PROP,
+   TEST_SIGNAL_NAME,
+};
+
+static const EDBus_Signal test_signals[] = {
+   [TEST_SIGNAL_ALIVE] = { "Alive" },
+   [TEST_SIGNAL_PROP] = { "Properties", EDBUS_ARGS({ "a{ss}", "properties"}) },
+   [TEST_SIGNAL_NAME] = { "Name", EDBUS_ARGS({ "s", "name"}) },
+   { }
+};
+
+/* signal with complex arguments (a dict) */
+static void emit_properties(EDBus_Service_Interface *iface)
+{
+   EDBus_Message *alive2;
+   EDBus_Message_Iter *iter, *dict;
+   struct keyval {
+      const char *key;
+      const char *val;
+   } keyval[] = {
+      { "key1", "val1" },
+      { "key2", "val2" },
+      { }
+   };
+   struct keyval *k;
+
+   alive2 = edbus_service_signal_new(iface, TEST_SIGNAL_PROP);
+   iter = edbus_message_iter_get(alive2);
+   dict = edbus_message_iter_container_new(iter, 'a', "{ss}");
+
+   for (k = keyval; k && k->key; k++)
+     {
+        EDBus_Message_Iter *entry = edbus_message_iter_container_new(dict, 'e',
+                                                                     NULL);
+        edbus_message_iter_arguments_set(entry, "ss", k->key, k->val);
+        edbus_message_iter_container_close(dict, entry);
+     }
+
+   edbus_message_iter_container_close(iter, dict);
+   edbus_service_signal_send(iface, alive2);
+}
+
+/* signal with basic args */
+static void emit_name(EDBus_Service_Interface *iface)
+{
+   edbus_service_signal_emit(iface, TEST_SIGNAL_NAME, "TEST");
+}
+
+/* simple signal example */
+static void emit_alive(EDBus_Service_Interface *iface)
+{
+   edbus_service_signal_emit(iface, TEST_SIGNAL_ALIVE);
+}
+
+static const EDBus_Service_Interface_Desc iface_desc = {
+   "org.enlightenment.Test", NULL, test_signals
+};
+
+int main(void)
+{
+   EDBus_Connection *conn;
+   EDBus_Service_Interface *iface;
+
+   edbus_init();
+
+   conn = edbus_connection_get(EDBUS_CONNECTION_TYPE_SESSION);
+   iface = edbus_service_interface_register(conn, "/org/enlightenment",
+                                            &iface_desc);
+
+   emit_alive(iface);
+   emit_name(iface);
+   emit_properties(iface);
+
+   edbus_connection_unref(conn);
+
+   edbus_shutdown();
+
+   return 0;
+}
diff --git a/src/lib/EDBus.h b/src/lib/EDBus.h
new file mode 100644 (file)
index 0000000..784139c
--- /dev/null
@@ -0,0 +1,141 @@
+#ifndef EDBUS_H
+#define EDBUS_H
+
+#include <Eina.h>
+#include <stdarg.h>
+
+#ifdef EAPI
+# undef EAPI
+#endif
+
+#ifdef _WIN32
+# ifdef EFL_EDBUS_BUILD
+#  ifdef DLL_EXPORT
+#   define EAPI __declspec(dllexport)
+#  else
+#   define EAPI
+#  endif /* ! DLL_EXPORT */
+# else
+#  define EAPI __declspec(dllimport)
+# endif /* ! EFL_EDBUS_BUILD */
+#else
+# ifdef __GNUC__
+#  if __GNUC__ >= 4
+#   define EAPI __attribute__ ((visibility("default")))
+#  else
+#   define EAPI
+#  endif
+# else
+#  define EAPI
+# endif
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @defgroup EDBus_Core Core
+ *
+ * @{
+ */
+#define EDBUS_VERSION_MAJOR 1
+#define EDBUS_VERSION_MINOR 6
+
+#define EDBUS_FDO_BUS "org.freedesktop.DBus"
+#define EDBUS_FDO_PATH "/org/freedesktop/DBus"
+#define EDBUS_FDO_INTERFACE EDBUS_FDO_BUS
+#define EDBUS_FDO_INTERFACE_PROPERTIES "org.freedesktop.DBus.Properties"
+
+typedef struct _EDBus_Version
+{
+   int major;
+   int minor;
+   int micro;
+   int revision;
+} EDBus_Version;
+
+EAPI extern const EDBus_Version * edbus_version;
+
+/**
+ * @brief Initialize edbus.
+ *
+ * @return 1 or greater on success, 0 otherwise
+ */
+EAPI int edbus_init(void);
+/**
+ * @brief Shutdown edbus.
+ *
+ * @return 0 if e_dbus shuts down, greater than 0 otherwise.
+ */
+EAPI int edbus_shutdown(void);
+
+typedef void                       (*EDBus_Free_Cb)(void *data, const void *deadptr);
+
+/**
+ * @typedef EDBus_Connection
+ *
+ * Represents a connection of one the type of connection with the DBus daemon.
+ */
+typedef struct _EDBus_Connection     EDBus_Connection;
+/**
+ * @typedef EDBus_Object
+ *
+ * Represents an object path already attached with bus name or unique id.
+ */
+typedef struct _EDBus_Object         EDBus_Object;
+/**
+ * @typedef EDBus_Proxy
+ *
+ * Represents an interface of an object path.
+ */
+typedef struct _EDBus_Proxy          EDBus_Proxy;
+/**
+ * @typedef EDBus_Message
+ *
+ * Represents the way data is sent and received in DBus.
+ */
+typedef struct _EDBus_Message        EDBus_Message;
+/**
+ * @typedef EDBus_Message_Iter
+ *
+ * Represents an iterator over a complex message type (array, dict, struct,
+ * or variant). Its life is bound to the message that contains
+ * it. The same applies to the returned data.
+ */
+typedef struct _EDBus_Message_Iter EDBus_Message_Iter;
+/**
+ * @typedef EDBus_Pending
+ *
+ * Represents a message that has been sent but has not yet reached its
+ * destination.
+ */
+typedef struct _EDBus_Pending        EDBus_Pending;
+/**
+ * @typedef EDBus_Signal_Handler
+ *
+ * Represents a listener that will listen for signals emitted by other
+ * applications.
+ */
+typedef struct _EDBus_Signal_Handler EDBus_Signal_Handler;
+
+typedef void (*EDBus_Message_Cb)(void *data, const EDBus_Message *msg, EDBus_Pending *pending);
+typedef void (*EDBus_Signal_Cb)(void *data, const EDBus_Message *msg);
+/**
+ * @}
+ */
+
+#include "edbus_connection.h"
+#include "edbus_message.h"
+#include "edbus_signal_handler.h"
+#include "edbus_pending.h"
+#include "edbus_object.h"
+#include "edbus_proxy.h"
+#include "edbus_freedesktop.h"
+#include "edbus_service.h"
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/lib/edbus_connection.h b/src/lib/edbus_connection.h
new file mode 100644 (file)
index 0000000..811854d
--- /dev/null
@@ -0,0 +1,144 @@
+#ifndef EDBUS_CONNECTION_H
+#define EDBUS_CONNECTION_H 1
+
+/**
+ * @defgroup EDBus_Conneciton Connection
+ *
+ * @{
+ */
+typedef enum
+{
+   EDBUS_CONNECTION_TYPE_UNKNOWN = 0,       /**< sentinel, not a real type */
+   EDBUS_CONNECTION_TYPE_SESSION,
+   EDBUS_CONNECTION_TYPE_SYSTEM,
+   EDBUS_CONNECTION_TYPE_STARTER,
+   EDBUS_CONNECTION_TYPE_LAST       /**< sentinel, not a real type */
+} EDBus_Connection_Type;
+
+#define EDBUS_TIMEOUT_INFINITE ((int) 0x7fffffff)
+
+/**
+ * @brief Establish a connection to bus and integrate it with the ecore main
+ * loop.
+ *
+ * @param type type of connection e.g EDBUS_CONNECTION_TYPE_SESSION,
+ * EDBUS_CONNECTION_TYPE_SYSTEM or EDBUS_CONNECTION_TYPE_STARTER
+ *
+ * @return connection with bus
+ */
+EAPI EDBus_Connection *edbus_connection_get(EDBus_Connection_Type type);
+
+/**
+ * @brief Increment connection reference count.
+ *
+ * @param conn The given EDBus_Connection object to reference
+ */
+EAPI EDBus_Connection *edbus_connection_ref(EDBus_Connection *conn) EINA_ARG_NONNULL(1);
+
+/**
+ * @brief Decrement connection reference count.
+ *
+ * If reference count reaches 0, the connection to bus will be dropped and all
+ * its children will be invalidated.
+ */
+EAPI void              edbus_connection_unref(EDBus_Connection *conn) EINA_ARG_NONNULL(1);
+
+/**
+ * @brief Add a callback function to be called when connection is freed
+ *
+ * @param conn The connection object to add the callback to.
+ * @param cb callback to be called
+ * @param data data passed to callback
+ */
+EAPI void              edbus_connection_cb_free_add(EDBus_Connection *conn, EDBus_Free_Cb cb, const void *data) EINA_ARG_NONNULL(1, 2);
+
+/**
+ * @brief Remove callback registered in edbus_connection_cb_free_add().
+ */
+EAPI void              edbus_connection_cb_free_del(EDBus_Connection *conn, EDBus_Free_Cb cb, const void *data) EINA_ARG_NONNULL(1, 2);
+
+/**
+ * @brief Set an attached data pointer to an object with a given string key.
+ *
+ * @param conn The connection object to store data to
+ * @param key to identify data
+ * @param data data that will be stored
+ */
+EAPI void              edbus_connection_data_set(EDBus_Connection *conn, const char *key, const void *data) EINA_ARG_NONNULL(1, 2, 3);
+
+/**
+ * @brief Get data stored in connection.
+ *
+ * @param conn connection where data is stored
+ * @param key key that identifies data
+ *
+ * @return pointer to data if found otherwise NULL
+ */
+EAPI void             *edbus_connection_data_get(const EDBus_Connection *conn, const char *key) EINA_ARG_NONNULL(1, 2);
+
+/**
+ * @brief Del data stored in connection.
+ *
+ * @param conn connection where data is stored
+ * @param key that identifies data
+ *
+ * @return pointer to data if found otherwise NULL
+ */
+EAPI void             *edbus_connection_data_del(EDBus_Connection *conn, const char *key) EINA_ARG_NONNULL(1, 2);
+
+typedef enum
+{
+   EDBUS_CONNECTION_EVENT_OBJECT_ADDED = 0,
+   EDBUS_CONNECTION_EVENT_OBJECT_REMOVED,
+   //EDBUS_CONNECTION_EVENT_NAME_OWNER_CHANGED,
+   EDBUS_CONNECTION_EVENT_DEL,
+   EDBUS_CONNECTION_EVENT_LAST    /**< sentinel, not a real event type */
+} EDBus_Connection_Event_Type;
+
+typedef struct _EDBus_Connection_Event_Object_Added
+{
+   const char   *path;
+   EDBus_Object *object;
+} EDBus_Connection_Event_Object_Added;
+
+typedef struct _EDBus_Connection_Event_Object_Removed
+{
+   const char *path;
+} EDBus_Connection_Event_Object_Removed;
+
+typedef struct _EDBus_Connection_Event_Name_Owner_Changed
+{
+   const char *name;
+   const char *old_id;
+   const char *new_id;
+} EDBus_Connection_Event_Name_Owner_Changed;
+
+typedef void (*EDBus_Connection_Event_Cb)(void *data, EDBus_Connection *conn, void *event_info);
+
+/**
+ * @brief Add a callback function to be called when an event occurs of the
+ * type passed.
+ */
+EAPI void                  edbus_connection_event_callback_add(EDBus_Connection *conn, EDBus_Connection_Event_Type type, EDBus_Connection_Event_Cb cb, const void *cb_data) EINA_ARG_NONNULL(1, 3);
+
+/**
+ * @brief Remove callback registered in edbus_connection_event_callback_add().
+ */
+EAPI void                  edbus_connection_event_callback_del(EDBus_Connection *conn, EDBus_Connection_Event_Type type, EDBus_Connection_Event_Cb cb, const void *cb_data) EINA_ARG_NONNULL(1, 3);
+
+/**
+ * @brief Send a message.
+ *
+ * @param conn the connection where the message will be sent
+ * @param msg message that will be sent
+ * @param cb if msg is a method call a callback should be passed
+ * to be executed when a response arrives
+ * @param cb_data data passed to callback
+ * @param timeout timeout in milliseconds, -1 to use default internal value or
+ * EDBUS_TIMEOUT_INFINITE for no timeout
+ */
+EAPI EDBus_Pending *edbus_connection_send(EDBus_Connection *conn, EDBus_Message *msg, EDBus_Message_Cb cb, const void *cb_data, double timeout) EINA_ARG_NONNULL(1, 2);
+/**
+ * @}
+ */
+#endif
diff --git a/src/lib/edbus_core.c b/src/lib/edbus_core.c
new file mode 100644 (file)
index 0000000..4e8fdf8
--- /dev/null
@@ -0,0 +1,1405 @@
+#include "edbus_private.h"
+#include "edbus_private_types.h"
+#include <dbus/dbus.h>
+
+#include <Ecore.h>
+
+#define EDBUS_CONNECTION_CHECK(conn)                        \
+  do                                                        \
+    {                                                       \
+       EINA_SAFETY_ON_NULL_RETURN(conn);                    \
+       if (!EINA_MAGIC_CHECK(conn, EDBUS_CONNECTION_MAGIC)) \
+         {                                                  \
+            EINA_MAGIC_FAIL(conn, EDBUS_CONNECTION_MAGIC);  \
+            return;                                         \
+         }                                                  \
+       EINA_SAFETY_ON_TRUE_RETURN(conn->refcount <= 0);     \
+    }                                                       \
+  while (0)
+
+#define EDBUS_CONNECTION_CHECK_RETVAL(conn, retval)                 \
+  do                                                                \
+    {                                                               \
+       EINA_SAFETY_ON_NULL_RETURN_VAL(conn, retval);                \
+       if (!EINA_MAGIC_CHECK(conn, EDBUS_CONNECTION_MAGIC))         \
+         {                                                          \
+            EINA_MAGIC_FAIL(conn, EDBUS_CONNECTION_MAGIC);          \
+            return retval;                                          \
+         }                                                          \
+       EINA_SAFETY_ON_TRUE_RETURN_VAL(conn->refcount <= 0, retval); \
+    }                                                               \
+  while (0)
+
+typedef struct _EDBus_Connection_Context_Event_Cb
+{
+   EINA_INLIST;
+   EDBus_Connection_Event_Cb cb;
+   const void               *cb_data;
+   Eina_Bool                 deleted : 1;
+} EDBus_Connection_Context_Event_Cb;
+
+typedef struct _EDBus_Connection_Context_NOC_Cb
+{
+   EINA_INLIST;
+   EDBus_Name_Owner_Changed_Cb cb;
+   const void                 *cb_data;
+   Eina_Bool                   deleted : 1;
+   Ecore_Idler                *idler;
+   Eina_Bool                   allow_initial : 1;
+} EDBus_Connection_Context_NOC_Cb;
+
+typedef struct _EDBus_Handler_Data
+{
+   EINA_INLIST;
+   int               fd;
+   Ecore_Fd_Handler *fd_handler;
+   EDBus_Connection *conn;
+   DBusWatch        *watch;
+   int               enabled;
+} EDBus_Handler_Data;
+
+typedef struct _EDBus_Timeout_Data
+{
+   EINA_INLIST;
+   Ecore_Timer      *handler;
+   DBusTimeout      *timeout;
+   EDBus_Connection *conn;
+   int               interval;
+} EDBus_Timeout_Data;
+
+static const EDBus_Version _version = {VMAJ, VMIN, VMIC, VREV};
+EAPI const EDBus_Version * edbus_version = &_version;
+
+static int _edbus_init_count = 0;
+int _edbus_log_dom = -1;
+
+static EDBus_Connection *shared_connections[3];
+
+static void _edbus_connection_event_callback_call(EDBus_Connection *conn, EDBus_Connection_Event_Type type, const void *event_info);
+static void _edbus_connection_context_event_cb_del(EDBus_Connection_Context_Event *ce, EDBus_Connection_Context_Event_Cb *ctx);
+static void edbus_dispatch_name_owner_change(EDBus_Connection_Name *cn, const char *old_id);
+
+EAPI int
+edbus_init(void)
+{
+   if (_edbus_init_count > 0)
+     return ++_edbus_init_count;
+
+   if (!eina_init())
+     {
+        fputs("EDBus: Enable to initialize eina\n", stderr);
+        return 0;
+     }
+
+   _edbus_log_dom = eina_log_domain_register("edbus", EINA_COLOR_BLUE);
+   if (_edbus_log_dom < 0)
+     {
+        EINA_LOG_ERR("Unable to create an 'edbus' log domain");
+        eina_shutdown();
+        return 0;
+     }
+
+   if (!ecore_init())
+     {
+        ERR("Unable to initialize ecore");
+        eina_log_domain_unregister(_edbus_log_dom);
+        _edbus_log_dom = -1;
+        eina_shutdown();
+        return 0;
+     }
+
+   eina_magic_string_set(EDBUS_CONNECTION_MAGIC, "EDBus_Connection");
+   eina_magic_string_set(EDBUS_MESSAGE_MAGIC, "EDBus_Message");
+   eina_magic_string_set(EDBUS_SIGNAL_HANDLER_MAGIC, "EDBus_Signal_Handler");
+   eina_magic_string_set(EDBUS_PENDING_MAGIC, "EDBus_Pending");
+   eina_magic_string_set(EDBUS_OBJECT_MAGIC, "EDBus_Object");
+   eina_magic_string_set(EDBUS_PROXY_MAGIC, "EDBus_Proxy");
+   eina_magic_string_set(EDBUS_MESSAGE_ITERATOR_MAGIC, "EDBus_Message_Iterator");
+   eina_magic_string_set(EDBUS_SERVICE_INTERFACE_MAGIC, "EDBus_Service_Interface");
+
+
+   if (!edbus_message_init()) goto message_failed;
+   if (!edbus_signal_handler_init()) goto signal_handler_failed;
+   if (!edbus_pending_init()) goto pending_failed;
+   if (!edbus_object_init()) goto object_failed;
+   if (!edbus_proxy_init()) goto proxy_failed;
+   if (!edbus_service_init()) goto service_failed;
+
+   return ++_edbus_init_count;
+
+service_failed:
+   edbus_proxy_shutdown();
+proxy_failed:
+   edbus_object_shutdown();
+object_failed:
+   edbus_pending_shutdown();
+pending_failed:
+   edbus_signal_handler_shutdown();
+signal_handler_failed:
+   edbus_message_shutdown();
+message_failed:
+   ecore_shutdown();
+   eina_log_domain_unregister(_edbus_log_dom);
+   _edbus_log_dom = -1;
+   eina_shutdown();
+
+   return 0;
+}
+
+static void
+print_live_connection(EDBus_Connection *conn)
+{
+   if (!conn->names)
+     ERR("conn=%p has no alive objects", conn);
+   else
+     {
+        Eina_Iterator *iter = eina_hash_iterator_data_new(conn->names);
+        EDBus_Connection_Name *name;
+        EINA_ITERATOR_FOREACH(iter, name)
+          {
+             EDBus_Object *obj;
+             Eina_Iterator *inner_itr;
+             if (!name->objects) continue;
+
+             inner_itr = eina_hash_iterator_data_new(name->objects);
+             EINA_ITERATOR_FOREACH(inner_itr, obj)
+                ERR("conn=%p alive object=%p %s of bus=%s", conn, obj,
+                    obj->name, name->name);
+             eina_iterator_free(inner_itr);
+          }
+        eina_iterator_free(iter);
+     }
+
+   if (!conn->pendings)
+     ERR("conn=%p has no alive pending calls", conn);
+   else
+     {
+        EDBus_Pending *p;
+        EINA_INLIST_FOREACH(conn->pendings, p)
+          ERR("conn=%p alive pending call=%p dest=%s path=%s %s.%s()",
+              conn, p,
+              edbus_pending_destination_get(p),
+              edbus_pending_path_get(p),
+              edbus_pending_interface_get(p),
+              edbus_pending_method_get(p));
+     }
+}
+
+EAPI int
+edbus_shutdown(void)
+{
+   if (_edbus_init_count <= 0)
+     {
+        ERR("Init count not greater than 0 in shutdown.");
+        _edbus_init_count = 0;
+        return 0;
+     }
+   if (--_edbus_init_count)
+     return _edbus_init_count;
+
+   if (shared_connections[EDBUS_CONNECTION_TYPE_SESSION - 1])
+     {
+        CRITICAL("Alive TYPE_SESSION connection");
+        print_live_connection(shared_connections[EDBUS_CONNECTION_TYPE_SESSION - 1]);
+     }
+   if (shared_connections[EDBUS_CONNECTION_TYPE_SYSTEM - 1])
+     {
+        CRITICAL("Alive TYPE_SYSTEM connection");
+        print_live_connection(shared_connections[EDBUS_CONNECTION_TYPE_SYSTEM - 1]);
+     }
+   if (shared_connections[EDBUS_CONNECTION_TYPE_STARTER - 1])
+     {
+        CRITICAL("Alive TYPE_STARTER connection");
+        print_live_connection(shared_connections[EDBUS_CONNECTION_TYPE_STARTER - 1]);
+     }
+
+   edbus_service_shutdown();
+   edbus_proxy_shutdown();
+   edbus_object_shutdown();
+   edbus_pending_shutdown();
+   edbus_signal_handler_shutdown();
+   edbus_message_shutdown();
+
+   ecore_shutdown();
+   eina_log_domain_unregister(_edbus_log_dom);
+   _edbus_log_dom = -1;
+   eina_shutdown();
+
+   return 0;
+}
+
+/* TODO: mempool of EDBus_Context_Free_Cb */
+typedef struct _EDBus_Context_Free_Cb
+{
+   EINA_INLIST;
+   EDBus_Free_Cb cb;
+   const void   *data;
+} EDBus_Context_Free_Cb;
+
+void
+edbus_cbs_free_dispatch(Eina_Inlist **p_lst, const void *dead_pointer)
+{
+   Eina_Inlist *lst = *p_lst;
+   *p_lst = NULL;
+   while (lst)
+     {
+        Eina_Inlist *next = lst->next;
+        EDBus_Context_Free_Cb *ctx;
+
+        ctx = EINA_INLIST_CONTAINER_GET(lst, EDBus_Context_Free_Cb);
+        ctx->cb((void *)ctx->data, dead_pointer);
+        free(ctx);
+
+        lst = next;
+     }
+}
+
+Eina_Inlist *
+edbus_cbs_free_add(Eina_Inlist *lst, EDBus_Free_Cb cb, const void *data)
+{
+   EDBus_Context_Free_Cb *ctx = malloc(sizeof(EDBus_Context_Free_Cb));
+   EINA_SAFETY_ON_NULL_RETURN_VAL(ctx, lst);
+
+   ctx->cb = cb;
+   ctx->data = data;
+
+   return eina_inlist_append(lst, EINA_INLIST_GET(ctx));
+}
+
+Eina_Inlist *
+edbus_cbs_free_del(Eina_Inlist *lst, EDBus_Free_Cb cb, const void *data)
+{
+   EDBus_Context_Free_Cb *ctx;
+
+   EINA_INLIST_FOREACH(lst, ctx)
+     {
+        if (ctx->cb != cb) continue;
+        if ((data) && (ctx->data != data)) continue;
+
+        lst = eina_inlist_remove(lst, EINA_INLIST_GET(ctx));
+        free(ctx);
+        return lst;
+     }
+
+   ERR("Couldn't find cb_free=%p data=%p", cb, data);
+   return lst;
+}
+
+typedef struct _EDBus_Data
+{
+   EINA_INLIST;
+   const void  *data;
+   unsigned int keylen;
+   char         key[];
+} EDBus_Data;
+
+static inline EDBus_Data *
+edbus_data_find(Eina_Inlist **p_lst, const char *key)
+{
+   unsigned int keylen = strlen(key);
+   EDBus_Data *d;
+
+   EINA_INLIST_FOREACH(*p_lst, d)
+     {
+        if ((keylen == d->keylen) && (memcmp(key, d->key, keylen) == 0))
+          {
+             *p_lst = eina_inlist_promote(*p_lst, EINA_INLIST_GET(d));
+             return d;
+          }
+     }
+
+   return NULL;
+}
+
+void
+edbus_data_set(Eina_Inlist **p_lst, const char *key, const void *data)
+{
+   EDBus_Data *d = edbus_data_find(p_lst, key);
+   unsigned int keylen = strlen(key);
+
+   if (d)
+     {
+        *p_lst = eina_inlist_remove(*p_lst, EINA_INLIST_GET(d));
+        free(d);
+     }
+
+   d = malloc(sizeof(EDBus_Data) + keylen + 1);
+   EINA_SAFETY_ON_NULL_RETURN(d);
+
+   d->data = data;
+   d->keylen = keylen;
+   memcpy(d->key, key, keylen + 1);
+
+   *p_lst = eina_inlist_prepend(*p_lst, EINA_INLIST_GET(d));
+}
+
+void *
+edbus_data_get(Eina_Inlist **p_lst, const char *key)
+{
+   EDBus_Data *d = edbus_data_find(p_lst, key);
+   return d ? (void *)d->data : NULL;
+}
+
+void *
+edbus_data_del(Eina_Inlist **p_lst, const char *key)
+{
+   EDBus_Data *d = edbus_data_find(p_lst, key);
+   void *ret;
+   if (!d) return NULL;
+
+   ret = (void *)d->data;
+   *p_lst = eina_inlist_remove(*p_lst, EINA_INLIST_GET(d));
+   free(d);
+
+   return ret;
+}
+
+void
+edbus_data_del_all(Eina_Inlist **p_list)
+{
+   Eina_Inlist *n = *p_list;
+   *p_list = NULL;
+
+   while (n)
+     {
+        EDBus_Data *d = EINA_INLIST_CONTAINER_GET(n, EDBus_Data);
+        n = eina_inlist_remove(n, n);
+        DBG("key=%s, data=%p", d->key, d->data);
+        free(d);
+     }
+}
+
+static EDBus_Connection_Name *
+edbus_connection_name_new(const char *name)
+{
+   EDBus_Connection_Name *cn = calloc(1, sizeof(EDBus_Connection_Name));
+   EINA_SAFETY_ON_NULL_RETURN_VAL(cn, NULL);
+   cn->name = eina_stringshare_add(name);
+   return cn;
+}
+
+static void
+edbus_connection_name_free(void *data)
+{
+   EDBus_Connection_Name *cn = data;
+
+   eina_stringshare_del(cn->name);
+   eina_stringshare_del(cn->unique_id);
+
+   if (cn->objects) eina_hash_free(cn->objects);
+
+   while (cn->event_handlers.list)
+     {
+        EDBus_Connection_Context_NOC_Cb *ctx;
+        ctx = EINA_INLIST_CONTAINER_GET(cn->event_handlers.list,
+                                        EDBus_Connection_Context_NOC_Cb);
+        cn->event_handlers.list = eina_inlist_remove(cn->event_handlers.list,
+                                                     cn->event_handlers.list);
+        free(ctx);
+     }
+   eina_list_free(cn->event_handlers.to_delete);
+
+   free(cn);
+}
+
+static void
+edbus_connection_name_gc(EDBus_Connection *conn, EDBus_Connection_Name *cn)
+{
+   Eina_Bool no_objs;
+   Eina_Bool no_event_handlers;
+
+   no_objs = ((!cn->objects) || (eina_hash_population(cn->objects) == 0));
+   no_event_handlers = !!cn->event_handlers.list;
+
+   if (no_objs && no_event_handlers && cn->refcount < 1)
+     eina_hash_del(conn->names, cn->name, cn);
+}
+
+void
+edbus_connection_name_object_del(EDBus_Connection *conn, const EDBus_Object *obj)
+{
+   EDBus_Connection_Name *cn = eina_hash_find(conn->names, obj->name);
+   const EDBus_Connection_Event_Object_Removed ev = {
+      obj->path
+   };
+
+   if (!cn) return;
+   if (!cn->objects) return;
+   eina_hash_del(cn->objects, obj->path, obj);
+
+   _edbus_connection_event_callback_call
+     (conn, EDBUS_CONNECTION_EVENT_OBJECT_REMOVED, &ev);
+
+   edbus_connection_name_gc(conn, cn);
+}
+
+void
+edbus_connection_name_object_set(EDBus_Connection *conn, EDBus_Object *obj)
+{
+   EDBus_Connection_Name *cn = eina_hash_find(conn->names, obj->name);
+   Eina_Bool had_connection_name = !!cn;
+   const EDBus_Connection_Event_Object_Added ev = {
+      obj->path,
+      obj
+   };
+
+   if (!cn)
+     {
+        cn = edbus_connection_name_new(obj->name);
+        EINA_SAFETY_ON_NULL_RETURN(cn);
+        eina_hash_direct_add(conn->names, cn->name, cn);
+     }
+   if (!cn->objects)
+     {
+        cn->objects = eina_hash_string_superfast_new(NULL);
+        EINA_SAFETY_ON_NULL_GOTO(cn->objects, cleanup);
+     }
+   eina_hash_add(cn->objects, obj->path, obj);
+
+   _edbus_connection_event_callback_call
+     (conn, EDBUS_CONNECTION_EVENT_OBJECT_ADDED, &ev);
+
+   return;
+
+cleanup:
+   if (!had_connection_name)
+     {
+        eina_hash_del(conn->names, cn->name, cn);
+        edbus_connection_name_free(cn);
+     }
+}
+
+static void
+on_name_owner_changed(void *data, const EDBus_Message *msg)
+{
+   const char *bus, *older_id, *new_id;
+   EDBus_Connection_Name *cn = data;
+
+   if (!edbus_message_arguments_get(msg, "sss", &bus, &older_id, &new_id))
+     {
+        ERR("Error getting arguments from NameOwnerChanged cn=%s", cn->name);
+        return;
+     }
+
+   eina_stringshare_del(cn->unique_id);
+   cn->unique_id = eina_stringshare_add(new_id);
+   edbus_dispatch_name_owner_change(cn, older_id);
+}
+
+static void
+on_get_name_owner(void *data, const EDBus_Message *msg, EDBus_Pending *pending)
+{
+   const char *unique_id = "";
+   EDBus_Connection_Name *cn = data;
+
+   if (edbus_message_error_get(msg, NULL, NULL))
+     DBG("GetNameOwner returned an error");
+   else if (!edbus_message_arguments_get(msg, "s", &unique_id))
+     ERR("Error getting arguments from GetNameOwner");
+
+   cn->unique_id = eina_stringshare_add(unique_id);
+   edbus_dispatch_name_owner_change(cn, NULL);
+}
+
+static void
+_edbus_connection_name_ref(EDBus_Connection *conn, EDBus_Connection_Name *cn)
+{
+   cn->refcount++;
+}
+
+static void
+_edbus_connection_name_unref(EDBus_Connection *conn, EDBus_Connection_Name *cn)
+{
+   EDBUS_CONNECTION_CHECK(conn);
+   EINA_SAFETY_ON_NULL_RETURN(cn);
+
+   cn->refcount--;
+
+   if (cn->refcount > 0) return;
+   if (cn->name_owner_changed)
+     edbus_signal_handler_del(cn->name_owner_changed);
+   cn->name_owner_changed = NULL;
+   edbus_connection_name_gc(conn, cn);
+}
+
+void
+edbus_connection_name_owner_monitor(EDBus_Connection *conn, EDBus_Connection_Name *cn, Eina_Bool enable)
+{
+   EDBUS_CONNECTION_CHECK(conn);
+   EINA_SAFETY_ON_NULL_RETURN(cn);
+
+   if (!enable)
+     {
+        _edbus_connection_name_unref(conn, cn);
+        return;
+     }
+   if (cn->name_owner_changed)
+     {
+        _edbus_connection_name_ref(conn, cn);
+        return;
+     }
+
+   edbus_name_owner_get(conn, cn->name, on_get_name_owner, cn);
+   _edbus_connection_name_ref(conn, cn);
+   cn->name_owner_changed = edbus_signal_handler_add(conn,
+                                              EDBUS_FDO_BUS,
+                                              EDBUS_FDO_PATH,
+                                              EDBUS_FDO_INTERFACE,
+                                              "NameOwnerChanged",
+                                              on_name_owner_changed, cn);
+   edbus_signal_handler_match_extra_set(cn->name_owner_changed, "arg0",
+                                        cn->name, NULL);
+}
+
+EDBus_Connection_Name *
+edbus_connection_name_get(EDBus_Connection *conn, const char *name)
+{
+   EDBus_Connection_Name *cn;
+   EDBUS_CONNECTION_CHECK_RETVAL(conn, NULL);
+
+   cn = eina_hash_find(conn->names, name);
+   if (cn) return cn;
+
+   cn = edbus_connection_name_new(name);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(cn, NULL);
+   eina_hash_direct_add(conn->names, cn->name, cn);
+   return cn;
+}
+
+EDBus_Object *
+edbus_connection_name_object_get(EDBus_Connection *conn, const char *name, const char *path)
+{
+   EDBus_Connection_Name *cn;
+
+   EDBUS_CONNECTION_CHECK_RETVAL(conn, NULL);
+   cn = eina_hash_find(conn->names, name);
+   if (!cn) return NULL;
+   if (!cn->objects) return NULL;
+   return eina_hash_find(cn->objects, path);
+}
+
+
+static void
+edbus_fd_handler_del(EDBus_Handler_Data *hd)
+{
+   if (!hd->fd_handler) return;
+
+   DBG("free EDBus_Handler_Data %d", hd->fd);
+   hd->conn->fd_handlers = eina_inlist_remove(hd->conn->fd_handlers,
+                                              EINA_INLIST_GET(hd));
+   if (hd->fd_handler)
+     ecore_main_fd_handler_del(hd->fd_handler);
+
+   free(hd);
+}
+
+static Eina_Bool
+edbus_fd_handler(void *data, Ecore_Fd_Handler *fd_handler)
+{
+   EDBus_Handler_Data *hd = data;
+   unsigned int condition = 0;
+
+   DBG("Got Ecore_Fd_Handle@%p", fd_handler);
+
+   if (ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_READ)) condition |= DBUS_WATCH_READABLE;
+   if (ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_WRITE)) condition |= DBUS_WATCH_WRITABLE;
+   if (ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_ERROR)) condition |= DBUS_WATCH_ERROR;
+
+   DBG("dbus connection@%p fdh=%d flags: [%s%s%s]", hd->conn, hd->fd,
+       (condition & DBUS_WATCH_READABLE) ? "read " : "",
+       (condition & DBUS_WATCH_WRITABLE) ? "write " : "",
+       (condition & DBUS_WATCH_ERROR) ? "error" : "");
+
+   dbus_watch_handle(hd->watch, condition);
+
+   return ECORE_CALLBACK_RENEW;
+}
+
+static void
+edbus_fd_handler_add(EDBus_Handler_Data *hd)
+{
+   unsigned int dflags;
+   Ecore_Fd_Handler_Flags eflags;
+
+   if (hd->fd_handler) return;
+   dflags = dbus_watch_get_flags(hd->watch);
+   eflags = ECORE_FD_ERROR;
+   if (dflags & DBUS_WATCH_READABLE) eflags |= ECORE_FD_READ;
+   if (dflags & DBUS_WATCH_WRITABLE) eflags |= ECORE_FD_WRITE;
+
+   DBG("Watching fd %d with flags: [%s%serror]", hd->fd,
+      (eflags & ECORE_FD_READ) ? "read " : "",
+      (eflags & ECORE_FD_WRITE) ? "write " : "");
+
+   hd->fd_handler = ecore_main_fd_handler_add(hd->fd,
+                                              eflags,
+                                              edbus_fd_handler,
+                                              hd,
+                                              NULL,
+                                              NULL);
+}
+
+static void
+edbus_handler_data_free(void *data)
+{
+   EDBus_Handler_Data *hd = data;
+   edbus_fd_handler_del(hd);
+}
+
+static dbus_bool_t
+cb_watch_add(DBusWatch *watch, void *data)
+{
+   EDBus_Connection *conn = data;
+   EDBus_Handler_Data *hd;
+
+   if (!dbus_watch_get_enabled(watch)) return EINA_TRUE;
+
+   DBG("cb_watch_add (enabled: %d)", dbus_watch_get_unix_fd(watch));
+
+   hd = calloc(1, sizeof(EDBus_Handler_Data));
+   EINA_SAFETY_ON_NULL_RETURN_VAL(hd, EINA_FALSE);
+   dbus_watch_set_data(watch, hd, edbus_handler_data_free);
+   hd->conn = conn;
+   hd->watch = watch;
+   hd->enabled = dbus_watch_get_enabled(watch);
+   hd->fd = dbus_watch_get_unix_fd(hd->watch);
+
+   conn->fd_handlers = eina_inlist_append(hd->conn->fd_handlers,
+                                          EINA_INLIST_GET(hd));
+   edbus_fd_handler_add(hd);
+
+   return EINA_TRUE;
+}
+
+static void
+cb_watch_del(DBusWatch *watch, void *data)
+{
+   DBG("cb_watch_del");
+   /* will trigger edbus_handler_data_free() */
+   dbus_watch_set_data(watch, NULL, NULL);
+}
+
+static void
+cb_watch_toggle(DBusWatch *watch, void *data)
+{
+   EDBus_Handler_Data *hd;
+   hd = dbus_watch_get_data(watch);
+   if (!hd) return;
+   DBG("cb_watch_toggle %d", hd->fd);
+
+   hd->enabled = dbus_watch_get_enabled(watch);
+
+   DBG("watch %p is %sabled", hd, hd->enabled ? "en" : "dis");
+   if (hd->enabled) edbus_fd_handler_add(hd);
+   else ecore_main_fd_handler_del(hd->fd_handler);
+}
+
+static void
+edbus_timeout_data_free(void *timeout_data)
+{
+   EDBus_Timeout_Data *td = timeout_data;
+   td->conn->timeouts = eina_inlist_remove(td->conn->timeouts,
+                                           EINA_INLIST_GET(td));
+   DBG("Timeout -- freeing timeout_data %p", td);
+   if (td->handler) ecore_timer_del(td->handler);
+   free(td);
+}
+
+static Eina_Bool
+edbus_timeout_handler(void *data)
+{
+   EDBus_Timeout_Data *td = data;
+   td->handler = NULL;
+
+   if (!dbus_timeout_get_enabled(td->timeout))
+     {
+        DBG("timeout_handler (not enabled, ending)");
+        return ECORE_CALLBACK_CANCEL;
+     }
+
+   DBG("Telling dbus to handle timeout with data %p", data);
+   dbus_timeout_handle(td->timeout);
+   return ECORE_CALLBACK_CANCEL;
+}
+
+static dbus_bool_t
+cb_timeout_add(DBusTimeout *timeout, void *data)
+{
+   EDBus_Connection *conn = data;
+   EDBus_Timeout_Data *td;
+
+   if (!dbus_timeout_get_enabled(timeout))
+     return EINA_TRUE;
+
+   DBG("Adding timeout for connection@%p", conn);
+   td = calloc(1, sizeof(EDBus_Timeout_Data));
+   EINA_SAFETY_ON_NULL_RETURN_VAL(td, EINA_FALSE);
+   td->conn = conn;
+   dbus_timeout_set_data(timeout, (void *)td, edbus_timeout_data_free);
+   td->interval = dbus_timeout_get_interval(timeout);
+   td->timeout = timeout;
+
+   td->handler = ecore_timer_add(td->interval, edbus_timeout_handler, td);
+   conn->timeouts = eina_inlist_append(conn->timeouts,
+                                       EINA_INLIST_GET(td));
+
+   return EINA_TRUE;
+}
+
+static void
+cb_timeout_del(DBusTimeout *timeout, void *data)
+{
+   DBG("timeout del!");
+   /* will trigger edbus_timeout_data_free() */
+   dbus_timeout_set_data(timeout, NULL, NULL);
+}
+
+static void
+cb_timeout_toggle(DBusTimeout *timeout, void *data)
+{
+   EDBus_Timeout_Data *td;
+
+   td = dbus_timeout_get_data(timeout);
+
+   DBG("Timeout toggle; data@%p", td);
+   if (dbus_timeout_get_enabled(td->timeout))
+     {
+        td->interval = dbus_timeout_get_interval(timeout);
+        td->handler
+          = ecore_timer_add(td->interval, edbus_timeout_handler, td);
+
+        DBG("Timeout is enabled with interval %d, timer@%p",
+           td->interval, td->handler);
+     }
+   else
+     {
+        DBG("Timeout is disabled, destroying timer@%p", td->handler);
+        ecore_timer_del(td->handler);
+        td->handler = NULL;
+     }
+}
+
+static Eina_Bool
+edbus_idler(void *data)
+{
+   EDBus_Connection *conn = data;
+
+   DBG("Connection@%p: Dispatch status: %d", conn,
+      dbus_connection_get_dispatch_status(conn->dbus_conn));
+
+   if (DBUS_DISPATCH_COMPLETE ==
+       dbus_connection_get_dispatch_status(conn->dbus_conn))
+     {
+        DBG("Connection@%p: Dispatch complete, idler@%p finishing",
+           conn, conn->idler);
+        conn->idler = NULL;
+        return ECORE_CALLBACK_CANCEL;
+     }
+
+   dbus_connection_ref(conn->dbus_conn);
+   DBG("Connection@%p: Dispatching", conn);
+   dbus_connection_dispatch(conn->dbus_conn);
+   dbus_connection_unref(conn->dbus_conn);
+   return ECORE_CALLBACK_RENEW;
+}
+
+static void
+cb_dispatch_status(DBusConnection *dbus_conn, DBusDispatchStatus new_status, void *data)
+{
+   EDBus_Connection *conn = data;
+
+   DBG("Connection@%p: Dispatch status: %d", conn, new_status);
+
+   if ((new_status == DBUS_DISPATCH_DATA_REMAINS) && (!conn->idler))
+     {
+        conn->idler = ecore_idler_add(edbus_idler, conn);
+        DBG("Connection@%p: Adding idler@%p to handle remaining dispatch data",
+           conn, conn->idler);
+     }
+   else if ((new_status != DBUS_DISPATCH_DATA_REMAINS) && (conn->idler))
+     {
+        DBG("Connection@%p: No remaining dispatch data, clearing idler@%p",
+           conn, conn->idler);
+
+        ecore_idler_del(conn->idler);
+        conn->idler = NULL;
+     }
+}
+
+static void
+cb_signal_dispatcher(EDBus_Connection *conn, DBusMessage *msg)
+{
+   EDBus_Signal_Handler *sh;
+   DBusMessageIter iter;
+   int type, counter;
+   char *arg_msg;
+   EDBus_Message *edbus_msg;
+   Signal_Argument *arg;
+
+   edbus_msg = edbus_message_new(EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN(edbus_msg);
+
+   edbus_msg->dbus_msg = dbus_message_ref(msg);
+   dbus_message_iter_init(edbus_msg->dbus_msg,
+                          &edbus_msg->iterator->dbus_iterator);
+   conn->running_signal = EINA_TRUE;
+
+   EINA_INLIST_FOREACH(conn->signal_handlers, sh)
+     {
+        if (sh->sender)
+          {
+             if (sh->bus)
+               {
+                  if ((sh->bus->unique_id == NULL) ||
+                      (!sh->bus->unique_id[0]) ||
+                      (!dbus_message_has_sender(msg, sh->bus->unique_id)))
+                    continue;
+               }
+             else
+                if (!dbus_message_has_sender(msg, sh->sender)) continue;
+          }
+        if (sh->path && !dbus_message_has_path(msg, sh->path)) continue;
+        if (sh->member && !dbus_message_has_member(msg, sh->member)) continue;
+
+        dbus_message_iter_init(msg, &iter);
+        counter = 0;
+        EINA_INLIST_FOREACH(sh->args, arg)
+          {
+             type = dbus_message_iter_get_arg_type(&iter);
+             if (counter != arg->index || !(type == 's' || type == 'o'))
+               goto next_sh;
+
+             dbus_message_iter_get_basic(&iter, &arg_msg);
+             if (strcmp(arg_msg, arg->value))
+               goto next_sh;
+
+             dbus_message_iter_next(&iter);
+             counter++;
+          }
+        sh->cb((void *)sh->cb_data, edbus_msg);
+        /*
+         * Rewind iterator so another signal handler matching the same signal
+         * can iterate over it.
+         */
+        dbus_message_iter_init(edbus_msg->dbus_msg,
+                               &edbus_msg->iterator->dbus_iterator);
+
+next_sh:
+        type = 0;
+     }
+
+   edbus_message_unref(edbus_msg);
+   conn->running_signal = EINA_FALSE;
+}
+
+static DBusHandlerResult
+edbus_filter(DBusConnection *conn_dbus, DBusMessage *message, void *user_data)
+{
+   EDBus_Connection *conn = user_data;
+
+   DBG("Connection@%p Got message:\n"
+       "  Type: %s\n"
+       "  Path: %s\n"
+       "  Interface: %s\n"
+       "  Member: %s\n"
+       "  Sender: %s", conn,
+       dbus_message_type_to_string(dbus_message_get_type(message)),
+       dbus_message_get_path(message),
+       dbus_message_get_interface(message),
+       dbus_message_get_member(message),
+       dbus_message_get_sender(message));
+
+   switch (dbus_message_get_type(message))
+     {
+      case DBUS_MESSAGE_TYPE_METHOD_CALL:
+        DBG("  Signature: %s", dbus_message_get_signature(message));
+        break;
+
+      case DBUS_MESSAGE_TYPE_METHOD_RETURN:
+        DBG("  Reply serial: %d", dbus_message_get_reply_serial(message));
+        break;
+
+      case DBUS_MESSAGE_TYPE_ERROR:
+        DBG("  Reply serial: %d", dbus_message_get_reply_serial(message));
+        break;
+
+      case DBUS_MESSAGE_TYPE_SIGNAL:
+        DBG("  Signature: %s", dbus_message_get_signature(message));
+        cb_signal_dispatcher(conn, message);
+        break;
+
+      default:
+        break;
+     }
+
+   return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+static void
+edbus_connection_setup(EDBus_Connection *conn)
+{
+   DBG("Setting up connection %p", conn);
+
+   /* connection_setup */
+   dbus_connection_set_exit_on_disconnect(conn->dbus_conn, EINA_FALSE);
+   dbus_connection_set_watch_functions(conn->dbus_conn,
+                                       cb_watch_add,
+                                       cb_watch_del,
+                                       cb_watch_toggle,
+                                       conn,
+                                       NULL);
+
+   dbus_connection_set_timeout_functions(conn->dbus_conn,
+                                         cb_timeout_add,
+                                         cb_timeout_del,
+                                         cb_timeout_toggle,
+                                         conn,
+                                         NULL);
+
+   dbus_connection_set_dispatch_status_function(conn->dbus_conn,
+                                                cb_dispatch_status,
+                                                conn, NULL);
+   dbus_connection_add_filter(conn->dbus_conn, edbus_filter, conn, NULL);
+
+   cb_dispatch_status(conn->dbus_conn,
+                      dbus_connection_get_dispatch_status(conn->dbus_conn),
+                      conn);
+}
+
+EAPI EDBus_Connection *
+edbus_connection_get(EDBus_Connection_Type type)
+{
+   EDBus_Connection *conn;
+   DBusError err;
+
+   DBG("Getting connection with type %d", type);
+
+   if ((type < EDBUS_CONNECTION_TYPE_SESSION) ||
+       (type > EDBUS_CONNECTION_TYPE_STARTER))
+     return NULL;
+
+   conn = shared_connections[type - 1];
+   if (conn)
+     {
+        DBG("Connection with type %d exists at %p; reffing and returning",
+           type, conn);
+        return edbus_connection_ref(conn);
+     }
+
+   conn = calloc(1, sizeof(EDBus_Connection));
+   EINA_SAFETY_ON_NULL_RETURN_VAL(conn, NULL);
+
+   dbus_error_init(&err);
+   conn->dbus_conn = dbus_bus_get_private(type - 1, &err);
+   if (dbus_error_is_set(&err))
+     {
+        free(conn);
+        ERR("Error connecting to bus: %s", err.message);
+        return NULL;
+     }
+   edbus_connection_setup(conn);
+
+   conn->type = type;
+   shared_connections[type - 1] = conn;
+
+   conn->refcount = 1;
+   EINA_MAGIC_SET(conn, EDBUS_CONNECTION_MAGIC);
+
+   conn->names = eina_hash_string_superfast_new(edbus_connection_name_free);
+
+   DBG("Returned new connection at %p", conn);
+   return conn;
+}
+
+EAPI EDBus_Connection *
+edbus_connection_ref(EDBus_Connection *conn)
+{
+   EDBUS_CONNECTION_CHECK_RETVAL(conn, NULL);
+   DBG("conn=%p, pre-refcount=%d", conn, conn->refcount);
+   conn->refcount++;
+   return conn;
+}
+
+static void
+_edbus_connection_unref(EDBus_Connection *conn)
+{
+   unsigned int i;
+   EDBus_Handler_Data *fd_handler;
+   EDBus_Timeout_Data *timer;
+   Eina_Inlist *list;
+   EDBus_Signal_Handler *h;
+   EDBus_Pending *p;
+
+   DBG("Connection %p: unref (currently at %d refs)",
+      conn, conn->refcount);
+
+   if (--conn->refcount > 0) return;
+
+   DBG("Freeing connection %p", conn);
+
+   _edbus_connection_event_callback_call
+     (conn, EDBUS_CONNECTION_EVENT_DEL, NULL);
+
+   conn->refcount = 1;
+   edbus_cbs_free_dispatch(&(conn->cbs_free), conn);
+
+   EINA_INLIST_FOREACH_SAFE(conn->pendings, list, p)
+     edbus_pending_cancel(p);
+
+   while (conn->signal_handlers)
+     {
+        list = conn->signal_handlers;
+        h = EINA_INLIST_CONTAINER_GET(conn->signal_handlers, EDBus_Signal_Handler);
+        edbus_signal_handler_del(h);
+     }
+   conn->refcount = 0;
+
+   /* after cbs_free dispatch these shouldn't exit, error if they do */
+
+   if (conn->pendings)
+     {
+        CRITICAL("Connection %p released with live pending calls!",
+                conn);
+        EINA_INLIST_FOREACH(conn->pendings, p)
+          ERR("conn=%p alive pending call=%p dest=%s path=%s %s.%s()",
+              conn, p,
+              edbus_pending_destination_get(p),
+              edbus_pending_path_get(p),
+              edbus_pending_interface_get(p),
+              edbus_pending_method_get(p));
+     }
+
+   for (i = 0; i < EDBUS_CONNECTION_EVENT_LAST; i++)
+     {
+        EDBus_Connection_Context_Event *ce = conn->event_handlers + i;
+        while (ce->list)
+          {
+             EDBus_Connection_Context_Event_Cb *ctx;
+
+             ctx = EINA_INLIST_CONTAINER_GET(ce->list,
+                                             EDBus_Connection_Context_Event_Cb);
+             _edbus_connection_context_event_cb_del(ce, ctx);
+          }
+        eina_list_free(ce->to_delete);
+     }
+
+   eina_hash_free(conn->names);
+
+   EINA_MAGIC_SET(conn, EINA_MAGIC_NONE);
+   dbus_connection_close(conn->dbus_conn);
+   dbus_connection_unref(conn->dbus_conn);
+   conn->dbus_conn = NULL;
+
+   EINA_INLIST_FOREACH_SAFE(conn->fd_handlers, list, fd_handler)
+     edbus_fd_handler_del(fd_handler);
+
+   EINA_INLIST_FOREACH_SAFE(conn->timeouts, list, timer)
+     edbus_timeout_data_free(timer->handler);
+
+   edbus_data_del_all(&conn->data);
+
+   if (conn->idler) ecore_idler_del(conn->idler);
+   shared_connections[conn->type - 1] = NULL;
+
+   free(conn);
+}
+
+EAPI void
+edbus_connection_unref(EDBus_Connection *conn)
+{
+   EDBUS_CONNECTION_CHECK(conn);
+   DBG("conn=%p, pre-refcount=%d", conn, conn->refcount);
+   _edbus_connection_unref(conn);
+}
+
+EAPI void
+edbus_connection_cb_free_add(EDBus_Connection *conn, EDBus_Free_Cb cb, const void *data)
+{
+   EDBUS_CONNECTION_CHECK(conn);
+   EINA_SAFETY_ON_NULL_RETURN(cb);
+   conn->cbs_free = edbus_cbs_free_add(conn->cbs_free, cb, data);
+}
+
+EAPI void
+edbus_connection_cb_free_del(EDBus_Connection *conn, EDBus_Free_Cb cb, const void *data)
+{
+   EDBUS_CONNECTION_CHECK(conn);
+   EINA_SAFETY_ON_NULL_RETURN(cb);
+   conn->cbs_free = edbus_cbs_free_del(conn->cbs_free, cb, data);
+}
+
+EAPI void
+edbus_connection_data_set(EDBus_Connection *conn, const char *key, const void *data)
+{
+   EDBUS_CONNECTION_CHECK(conn);
+   EINA_SAFETY_ON_NULL_RETURN(key);
+   EINA_SAFETY_ON_NULL_RETURN(data);
+   edbus_data_set(&(conn->data), key, data);
+}
+
+EAPI void *
+edbus_connection_data_get(const EDBus_Connection *conn, const char *key)
+{
+   EDBUS_CONNECTION_CHECK_RETVAL(conn, NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(key, NULL);
+   return edbus_data_get(&(((EDBus_Connection *)conn)->data), key);
+}
+
+EAPI void *
+edbus_connection_data_del(EDBus_Connection *conn, const char *key)
+{
+   EDBUS_CONNECTION_CHECK_RETVAL(conn, NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(key, NULL);
+   return edbus_data_del(&(((EDBus_Connection *)conn)->data), key);
+}
+
+static void
+edbus_dispatch_name_owner_change(EDBus_Connection_Name *cn, const char *old_id)
+{
+   EDBus_Connection_Context_NOC_Cb *ctx;
+   const char *previous_id = !old_id ? "" : old_id;
+   cn->event_handlers.walking++;
+   EINA_INLIST_FOREACH(cn->event_handlers.list, ctx)
+     {
+        if (ctx->deleted) continue;
+        if (!old_id && !ctx->allow_initial)
+          continue;
+        ctx->cb((void *)ctx->cb_data, cn->name, previous_id, cn->unique_id);
+     }
+   cn->event_handlers.walking--;
+}
+
+typedef struct _dispach_name_owner_data
+{
+   EDBus_Connection_Context_NOC_Cb *ctx;
+   const EDBus_Connection_Name *cn;
+} dispatch_name_owner_data;
+
+static Eina_Bool
+dispach_name_owner_cb(void *context)
+{
+   dispatch_name_owner_data *data = context;
+   data->ctx->cb((void *)data->ctx->cb_data, data->cn->name, "",
+                 data->cn->unique_id);
+   data->ctx->idler = NULL;
+   free(data);
+   return ECORE_CALLBACK_CANCEL;
+}
+
+EAPI void
+edbus_name_owner_changed_callback_add(EDBus_Connection *conn, const char *bus, EDBus_Name_Owner_Changed_Cb cb, const void *cb_data, Eina_Bool allow_initial_call)
+{
+   EDBus_Connection_Name *cn;
+   EDBus_Connection_Context_NOC_Cb *ctx;
+
+   EDBUS_CONNECTION_CHECK(conn);
+   EINA_SAFETY_ON_NULL_RETURN(bus);
+   EINA_SAFETY_ON_NULL_RETURN(cb);
+
+   cn = eina_hash_find(conn->names, bus);
+   if (cn)
+     edbus_connection_name_owner_monitor(conn, cn, EINA_TRUE);
+   else
+     {
+        cn = edbus_connection_name_new(bus);
+        EINA_SAFETY_ON_NULL_RETURN(cn);
+
+        eina_hash_direct_add(conn->names, cn->name, cn);
+        edbus_connection_name_owner_monitor(conn, cn, EINA_TRUE);
+     }
+
+   ctx = calloc(1, sizeof(EDBus_Connection_Context_NOC_Cb));
+   EINA_SAFETY_ON_NULL_GOTO(ctx, cleanup);
+   ctx->cb = cb;
+   ctx->cb_data = cb_data;
+   ctx->allow_initial = allow_initial_call;
+
+   cn->event_handlers.list = eina_inlist_append(cn->event_handlers.list,
+                                                EINA_INLIST_GET(ctx));
+   if (cn->unique_id && allow_initial_call)
+     {
+        dispatch_name_owner_data *dispatch_data;
+        dispatch_data = malloc(sizeof(dispatch_name_owner_data));
+        EINA_SAFETY_ON_NULL_RETURN(dispatch_data);
+        dispatch_data->cn = cn;
+        dispatch_data->ctx = ctx;
+        ctx->idler = ecore_idler_add(dispach_name_owner_cb, dispatch_data);
+     }
+   return;
+
+cleanup:
+   _edbus_connection_name_unref(conn, cn);
+}
+
+EAPI void
+edbus_name_owner_changed_callback_del(EDBus_Connection *conn, const char *bus, EDBus_Name_Owner_Changed_Cb cb, const void *cb_data)
+{
+   EDBus_Connection_Name *cn;
+   EDBus_Connection_Context_NOC_Cb *iter, *found = NULL;
+
+   EDBUS_CONNECTION_CHECK(conn);
+   EINA_SAFETY_ON_NULL_RETURN(bus);
+   EINA_SAFETY_ON_NULL_RETURN(cb);
+
+   cn = eina_hash_find(conn->names, bus);
+   EINA_SAFETY_ON_NULL_RETURN(cn);
+
+   EINA_INLIST_FOREACH(cn->event_handlers.list, iter)
+     {
+        if (cb != iter->cb) continue;
+        if ((cb_data) && (cb_data != iter->cb_data)) continue;
+
+        found = iter;
+        break;
+     }
+
+   EINA_SAFETY_ON_NULL_RETURN(found);
+   EINA_SAFETY_ON_TRUE_RETURN(found->deleted);
+
+   if (cn->event_handlers.walking)
+     {
+        found->deleted = EINA_TRUE;
+        cn->event_handlers.to_delete = eina_list_append
+            (cn->event_handlers.to_delete, found);
+        return;
+     }
+
+   cn->event_handlers.list = eina_inlist_remove(cn->event_handlers.list,
+                                                EINA_INLIST_GET(found));
+   if (found->idler)
+     {
+        dispatch_name_owner_data *data;
+        data = ecore_idler_del(found->idler);
+        free(data);
+     }
+   free(found);
+   edbus_connection_name_owner_monitor(conn, cn, EINA_FALSE);
+}
+
+EAPI void
+edbus_connection_event_callback_add(EDBus_Connection *conn, EDBus_Connection_Event_Type type, EDBus_Connection_Event_Cb cb, const void *cb_data)
+{
+   EDBus_Connection_Context_Event *ce;
+   EDBus_Connection_Context_Event_Cb *ctx;
+
+   EDBUS_CONNECTION_CHECK(conn);
+   EINA_SAFETY_ON_NULL_RETURN(cb);
+   EINA_SAFETY_ON_TRUE_RETURN(type >= EDBUS_CONNECTION_EVENT_LAST);
+
+   ce = conn->event_handlers + type;
+
+   ctx = calloc(1, sizeof(EDBus_Connection_Context_Event_Cb));
+   EINA_SAFETY_ON_NULL_RETURN(ctx);
+   ctx->cb = cb;
+   ctx->cb_data = cb_data;
+
+   ce->list = eina_inlist_append(ce->list, EINA_INLIST_GET(ctx));
+}
+
+static void
+_edbus_connection_context_event_cb_del(EDBus_Connection_Context_Event *ce, EDBus_Connection_Context_Event_Cb *ctx)
+{
+   ce->list = eina_inlist_remove(ce->list, EINA_INLIST_GET(ctx));
+   free(ctx);
+}
+
+EAPI void
+edbus_connection_event_callback_del(EDBus_Connection *conn, EDBus_Connection_Event_Type type, EDBus_Connection_Event_Cb cb, const void *cb_data)
+{
+   EDBus_Connection_Context_Event *ce;
+   EDBus_Connection_Context_Event_Cb *iter, *found = NULL;
+
+   EDBUS_CONNECTION_CHECK(conn);
+   EINA_SAFETY_ON_NULL_RETURN(cb);
+   EINA_SAFETY_ON_TRUE_RETURN(type >= EDBUS_CONNECTION_EVENT_LAST);
+
+   ce = conn->event_handlers + type;
+
+   EINA_INLIST_FOREACH(ce->list, iter)
+     {
+        if (cb != iter->cb) continue;
+        if ((cb_data) && (cb_data != iter->cb_data)) continue;
+
+        found = iter;
+        break;
+     }
+
+   EINA_SAFETY_ON_NULL_RETURN(found);
+   EINA_SAFETY_ON_TRUE_RETURN(found->deleted);
+
+   if (ce->walking)
+     {
+        found->deleted = EINA_TRUE;
+        ce->to_delete = eina_list_append(ce->to_delete, found);
+        return;
+     }
+
+   _edbus_connection_context_event_cb_del(ce, found);
+}
+
+static void
+_edbus_connection_event_callback_call(EDBus_Connection *conn, EDBus_Connection_Event_Type type, const void *event_info)
+{
+   EDBus_Connection_Context_Event *ce;
+   EDBus_Connection_Context_Event_Cb *iter;
+
+   ce = conn->event_handlers + type;
+
+   ce->walking++;
+   EINA_INLIST_FOREACH(ce->list, iter)
+     {
+        if (iter->deleted) continue;
+        iter->cb((void *)iter->cb_data, conn, (void *)event_info);
+     }
+   ce->walking--;
+   if (ce->walking > 0) return;
+
+   EINA_LIST_FREE(ce->to_delete, iter)
+     _edbus_connection_context_event_cb_del(ce, iter);
+}
+
+void
+edbus_connection_event_callback_call(EDBus_Connection *conn, EDBus_Connection_Event_Type type, const void *event_info)
+{
+   EDBUS_CONNECTION_CHECK(conn);
+   EINA_SAFETY_ON_TRUE_RETURN(type >= EDBUS_CONNECTION_EVENT_LAST);
+   EINA_SAFETY_ON_TRUE_RETURN(type == EDBUS_CONNECTION_EVENT_DEL);
+
+   _edbus_connection_event_callback_call(conn, type, event_info);
+}
+
+void
+edbus_connection_signal_handler_add(EDBus_Connection *conn, EDBus_Signal_Handler *handler)
+{
+   EDBUS_CONNECTION_CHECK(conn);
+   EINA_SAFETY_ON_NULL_RETURN(handler);
+   conn->signal_handlers = eina_inlist_append(conn->signal_handlers,
+                                              EINA_INLIST_GET(handler));
+}
+
+void
+edbus_connection_pending_add(EDBus_Connection *conn, EDBus_Pending *pending)
+{
+   EDBUS_CONNECTION_CHECK(conn);
+   EINA_SAFETY_ON_NULL_RETURN(pending);
+   conn->pendings = eina_inlist_append(conn->pendings,
+                                       EINA_INLIST_GET(pending));
+}
+
+void
+edbus_connection_signal_handler_del(EDBus_Connection *conn, EDBus_Signal_Handler *handler)
+{
+   EINA_SAFETY_ON_NULL_RETURN(conn);
+   EINA_SAFETY_ON_NULL_RETURN(handler);
+   conn->signal_handlers = eina_inlist_remove(conn->signal_handlers,
+                                              EINA_INLIST_GET(handler));
+}
+
+void
+edbus_connection_pending_del(EDBus_Connection *conn, EDBus_Pending *pending)
+{
+   EINA_SAFETY_ON_NULL_RETURN(conn);
+   EINA_SAFETY_ON_NULL_RETURN(pending);
+   conn->pendings = eina_inlist_remove(conn->pendings,
+                                       EINA_INLIST_GET(pending));
+}
diff --git a/src/lib/edbus_freedesktop.c b/src/lib/edbus_freedesktop.c
new file mode 100644 (file)
index 0000000..0247bff
--- /dev/null
@@ -0,0 +1,80 @@
+#include "edbus_private.h"
+#include "edbus_private_types.h"
+#include <dbus/dbus.h>
+
+static EDBus_Proxy *
+get_freedesktop_proxy(EDBus_Connection *conn)
+{
+   EDBus_Object *freedesktop_obj;
+
+   freedesktop_obj = edbus_object_get(conn, EDBUS_FDO_BUS, EDBUS_FDO_PATH);
+   return edbus_proxy_get(freedesktop_obj, EDBUS_FDO_INTERFACE);
+}
+
+EAPI EDBus_Pending *
+edbus_name_request(EDBus_Connection *conn, const char *name, unsigned int flags, EDBus_Message_Cb cb, const void *cb_data)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(conn, NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(name, NULL);
+
+   return edbus_proxy_call(get_freedesktop_proxy(conn), "RequestName", cb,
+                           cb_data, -1, "su", name, flags);
+}
+
+EAPI EDBus_Pending *
+edbus_name_release(EDBus_Connection *conn, const char *name, EDBus_Message_Cb cb, const void *cb_data)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(conn, NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(name, NULL);
+
+   return edbus_proxy_call(get_freedesktop_proxy(conn), "ReleaseName", cb,
+                           cb_data, -1, "s", name);
+}
+
+EAPI EDBus_Pending *
+edbus_name_owner_get(EDBus_Connection *conn, const char *name, EDBus_Message_Cb cb, const void *cb_data)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(conn, NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(name, NULL);
+
+   return edbus_proxy_call(get_freedesktop_proxy(conn), "GetNameOwner", cb,
+                           cb_data, -1, "s", name);
+}
+
+EAPI EDBus_Pending *
+edbus_name_owner_has(EDBus_Connection *conn, const char *name, EDBus_Message_Cb cb, const void *cb_data)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(conn, NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(name, NULL);
+
+   return edbus_proxy_call(get_freedesktop_proxy(conn), "NameHasOwner", cb,
+                           cb_data, -1, "s", name);
+}
+
+EAPI EDBus_Pending *
+edbus_names_list(EDBus_Connection *conn, EDBus_Message_Cb cb, const void *cb_data)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(conn, NULL);
+
+   return edbus_proxy_call(get_freedesktop_proxy(conn), "ListNames", cb,
+                           cb_data, -1, "");
+}
+
+EAPI EDBus_Pending *
+edbus_names_activatable_list(EDBus_Connection *conn, EDBus_Message_Cb cb, const void *cb_data)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(conn, NULL);
+
+   return edbus_proxy_call(get_freedesktop_proxy(conn), "ListActivatableNames", cb,
+                           cb_data, -1, "");
+}
+
+EAPI EDBus_Pending *
+edbus_name_start(EDBus_Connection *conn, const char *name, unsigned int flags, EDBus_Message_Cb cb, const void *cb_data)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(conn, NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(name, NULL);
+
+   return edbus_proxy_call(get_freedesktop_proxy(conn), "StartServiceByName", cb,
+                           cb_data, -1, "su", name, flags);
+}
diff --git a/src/lib/edbus_freedesktop.h b/src/lib/edbus_freedesktop.h
new file mode 100644 (file)
index 0000000..ab8b41f
--- /dev/null
@@ -0,0 +1,157 @@
+#ifndef EDBUS_FREEDESKTOP_H
+#define EDBUS_FREEDESKTOP_H 1
+
+/**
+ * @defgroup EDBus_Basic Basic Methods
+ *
+ * @{
+ */
+#define EDBUS_NAME_REQUEST_FLAG_ALLOW_REPLACEMENT 0x1 /**< Allow another service to become the primary owner if requested */
+#define EDBUS_NAME_REQUEST_FLAG_REPLACE_EXISTING  0x2 /**< Request to replace the current primary owner */
+#define EDBUS_NAME_REQUEST_FLAG_DO_NOT_QUEUE      0x4 /**< If we can not become the primary owner do not place us in the queue */
+
+/* Replies to request for a name */
+#define EDBUS_NAME_REQUEST_REPLY_PRIMARY_OWNER    1 /**< Service has become the primary owner of the requested name */
+#define EDBUS_NAME_REQUEST_REPLY_IN_QUEUE         2 /**< Service could not become the primary owner and has been placed in the queue */
+#define EDBUS_NAME_REQUEST_REPLY_EXISTS           3 /**< Service is already in the queue */
+#define EDBUS_NAME_REQUEST_REPLY_ALREADY_OWNER    4 /**< Service is already the primary owner */
+
+EAPI EDBus_Pending *edbus_name_request(EDBus_Connection *conn, const char *bus, unsigned int flags, EDBus_Message_Cb cb, const void *cb_data);
+
+/* Replies to releasing a name */
+#define EDBUS_NAME_RELEASE_REPLY_RELEASED     1    /**< Service was released from the given name */
+#define EDBUS_NAME_RELEASE_REPLY_NON_EXISTENT 2    /**< The given name does not exist on the bus */
+#define EDBUS_NAME_RELEASE_REPLY_NOT_OWNER    3    /**< Service is not an owner of the given name */
+
+EAPI EDBus_Pending *edbus_name_release(EDBus_Connection *conn, const char *bus, EDBus_Message_Cb cb, const void *cb_data);
+EAPI EDBus_Pending *edbus_name_owner_get(EDBus_Connection *conn, const char *bus, EDBus_Message_Cb cb, const void *cb_data);
+EAPI EDBus_Pending *edbus_name_owner_has(EDBus_Connection *conn, const char *bus, EDBus_Message_Cb cb, const void *cb_data);
+EAPI EDBus_Pending *edbus_names_list(EDBus_Connection *conn, EDBus_Message_Cb cb, const void *cb_data);
+EAPI EDBus_Pending *edbus_names_activatable_list(EDBus_Connection *conn, EDBus_Message_Cb cb, const void *cb_data);
+
+/* Replies to service starts */
+#define EDBUS_NAME_START_REPLY_SUCCESS         1 /**< Service was auto started */
+#define EDBUS_NAME_START_REPLY_ALREADY_RUNNING 2 /**< Service was already running */
+
+EAPI EDBus_Pending        *edbus_name_start(EDBus_Connection *conn, const char *bus, unsigned int flags, EDBus_Message_Cb cb, const void *cb_data);
+
+typedef void (*EDBus_Name_Owner_Changed_Cb)(void *data, const char *bus, const char *old_id, const char *new_id);
+
+/**
+ * Add a callback to be called when unique id of a bus name changed.
+ *
+ * This function implicitly calls edbus_name_owner_get() in order to be able to
+ * monitor the name. If the only interest is to receive notifications when the
+ * name in fact changes, pass EINA_FALSE to @param allow_initial_call so your
+ * callback will not be called on first retrieval of name owner. If the
+ * initial state is important, pass EINA_TRUE to this parameter.
+ *
+ * @param conn connection
+ * @param bus name of bus
+ * @param cb callback
+ * @param cb_data context data
+ * @param allow_initial_call allow call callback with actual id of the bus
+ */
+EAPI void                  edbus_name_owner_changed_callback_add(EDBus_Connection *conn, const char *bus, EDBus_Name_Owner_Changed_Cb cb, const void *cb_data, Eina_Bool allow_initial_call);
+/**
+ * Remove callback added with edbus_name_owner_changed_callback_add().
+ *
+ * @param conn connection
+ * @param bus name of bus
+ * @param cb callback
+ * @param cb_data context data
+ */
+EAPI void                  edbus_name_owner_changed_callback_del(EDBus_Connection *conn, const char *bus, EDBus_Name_Owner_Changed_Cb cb, const void *cb_data);
+
+/**
+ * @defgroup EDBus_FDO_Peer org.freedesktop.DBus.Peer
+ *
+ * @{
+ */
+EAPI EDBus_Pending        *edbus_object_peer_ping(EDBus_Object *obj, EDBus_Message_Cb cb, const void *data) EINA_ARG_NONNULL(1);
+EAPI EDBus_Pending        *edbus_object_peer_machine_id_get(EDBus_Object *obj, EDBus_Message_Cb cb, const void *data) EINA_ARG_NONNULL(1, 2);
+/**
+ * @}
+ */
+
+/**
+ * @defgroup EDBus_FDO_Introspectable org.freedesktop.DBus.Introspectable
+ *
+ * @{
+ */
+EAPI EDBus_Pending        *edbus_object_introspect(EDBus_Object *obj, EDBus_Message_Cb cb, const void *data) EINA_ARG_NONNULL(1, 2);
+/**
+ * @}
+ */
+
+/**
+ * @defgroup EDBus_FDO_Properties org.freedesktop.DBus.Properties
+ * @{
+ */
+
+/**
+ * Enable or disable local cache of properties.
+ *
+ * After enable you can call edbus_proxy_property_local_get() or
+ * edbus_proxy_property_local_get_all() to get cached properties.
+ *
+ * @note After enable, it will asynchrony get the properties values.
+ */
+EAPI void edbus_proxy_properties_monitor(EDBus_Proxy *proxy, Eina_Bool enable);
+
+EAPI EDBus_Pending        *edbus_proxy_property_get(EDBus_Proxy *proxy, const char *name, EDBus_Message_Cb cb, const void *data) EINA_ARG_NONNULL(1, 2, 3);
+EAPI EDBus_Pending        *edbus_proxy_property_set(EDBus_Proxy *proxy, const char *name, char type, const void *value, EDBus_Message_Cb cb, const void *data) EINA_ARG_NONNULL(1, 2, 4);
+EAPI EDBus_Pending        *edbus_proxy_property_get_all(EDBus_Proxy *proxy, EDBus_Message_Cb cb, const void *data) EINA_ARG_NONNULL(1, 2);
+EAPI EDBus_Signal_Handler *edbus_proxy_properties_changed_callback_add(EDBus_Proxy *proxy, EDBus_Signal_Cb cb, const void *data) EINA_ARG_NONNULL(1, 2);
+
+/**
+ * Return the cached value of property.
+ * This only work if you have enable edbus_proxy_properties_monitor or
+ * if you have call edbus_proxy_event_callback_add of type
+ * EDBUS_PROXY_EVENT_PROPERTY_CHANGED and the property you want had changed.
+ */
+EAPI Eina_Value           *edbus_proxy_property_local_get(EDBus_Proxy *proxy, const char *name) EINA_ARG_NONNULL(1, 2);
+
+/**
+ * Return a Eina_Hash with all cached properties.
+ * This only work if you have enable edbus_proxy_properties_monitor or
+ * if you have call edbus_proxy_event_callback_add of type
+ * EDBUS_PROXY_EVENT_PROPERTY_CHANGED.
+ */
+EAPI const Eina_Hash      *edbus_proxy_property_local_get_all(EDBus_Proxy *proxy) EINA_ARG_NONNULL(1);
+/**
+ * @}
+ */
+
+/**
+ * @defgroup EDBus_FDO_ObjectManager org.freedesktop.DBus.ObjectManager
+ *
+ * Whenever edbus_object_managed_objects_monitor() is called on an
+ * object it will start listening for children being added or
+ * interfaces changing on the object itself. It will then emit
+ * events with edbus_object_event_type being
+ * #EDBUS_OBJECT_EVENT_IFACE_ADDED,
+ * #EDBUS_OBJECT_EVENT_IFACE_REMOVED,
+ * #EDBUS_OBJECT_EVENT_PROPERTY_CHANGED and
+ * #EDBUS_OBJECT_EVENT_PROPERTY_REMOVED.
+ *
+ * One may manually query the managed objects with
+ * edbus_object_managed_objects_get() and listen for changes with
+ * edbus_object_interfaces_added_callback_add() and
+ * edbus_object_interfaces_removed_callback_add().
+ *
+ * @{
+ */
+EAPI void                  edbus_object_properties_monitor(EDBus_Object *obj);
+
+EAPI EDBus_Pending        *edbus_object_managed_objects_get(EDBus_Object *obj, EDBus_Message_Cb cb, const void *data) EINA_ARG_NONNULL(1, 2);
+EAPI EDBus_Signal_Handler *edbus_object_interfaces_added_callback_add(EDBus_Object *obj, EDBus_Message_Cb cb, const void *data) EINA_ARG_NONNULL(1, 2);
+EAPI EDBus_Signal_Handler *edbus_object_interfaces_removed_callback_add(EDBus_Object *obj, EDBus_Message_Cb cb, const void *data) EINA_ARG_NONNULL(1, 2);
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+#endif
diff --git a/src/lib/edbus_message.c b/src/lib/edbus_message.c
new file mode 100644 (file)
index 0000000..c36bde2
--- /dev/null
@@ -0,0 +1,819 @@
+#include "edbus_private.h"
+#include "edbus_private_types.h"
+#include <dbus/dbus.h>
+#include <stdint.h>
+
+/* TODO: mempool of EDBus_Message and EDBus_Message_Iter */
+
+#define EDBUS_MESSAGE_CHECK(msg)                        \
+  do                                                    \
+    {                                                   \
+       EINA_SAFETY_ON_NULL_RETURN(msg);                 \
+       if (!EINA_MAGIC_CHECK(msg, EDBUS_MESSAGE_MAGIC)) \
+         {                                              \
+            EINA_MAGIC_FAIL(msg, EDBUS_MESSAGE_MAGIC);  \
+            return;                                     \
+         }                                              \
+       EINA_SAFETY_ON_TRUE_RETURN(msg->refcount <= 0);  \
+    }                                                   \
+  while (0)
+
+#define EDBUS_MESSAGE_CHECK_RETVAL(msg, retval)                    \
+  do                                                               \
+    {                                                              \
+       EINA_SAFETY_ON_NULL_RETURN_VAL(msg, retval);                \
+       if (!EINA_MAGIC_CHECK(msg, EDBUS_MESSAGE_MAGIC))            \
+         {                                                         \
+            EINA_MAGIC_FAIL(msg, EDBUS_MESSAGE_MAGIC);             \
+            return retval;                                         \
+         }                                                         \
+       EINA_SAFETY_ON_TRUE_RETURN_VAL(msg->refcount <= 0, retval); \
+    }                                                              \
+  while (0)
+
+#define EDBUS_MESSAGE_ITERATOR_CHECK(iter)                        \
+  do                                                             \
+    {                                                            \
+       EINA_SAFETY_ON_NULL_RETURN(iter);                          \
+       if (!EINA_MAGIC_CHECK(iter, EDBUS_MESSAGE_ITERATOR_MAGIC)) \
+         {                                                       \
+            EINA_MAGIC_FAIL(iter, EDBUS_MESSAGE_ITERATOR_MAGIC);  \
+            return;                                              \
+         }                                                       \
+    }                                                            \
+  while (0)
+
+#define EDBUS_MESSAGE_ITERATOR_CHECK_RETVAL(iter, retval)          \
+  do                                                              \
+    {                                                             \
+       EINA_SAFETY_ON_NULL_RETURN_VAL(iter, retval);               \
+       if (!EINA_MAGIC_CHECK(iter, EDBUS_MESSAGE_ITERATOR_MAGIC))  \
+         {                                                        \
+            EINA_MAGIC_FAIL(iter, EDBUS_MESSAGE_ITERATOR_MAGIC);   \
+            return retval;                                        \
+         }                                                        \
+    }                                                             \
+  while (0)
+
+static Eina_Bool append_basic(char type, va_list *vl, DBusMessageIter *iter);
+
+Eina_Bool
+edbus_message_init(void)
+{
+   return EINA_TRUE;
+}
+
+void
+edbus_message_shutdown(void)
+{
+}
+
+static EDBus_Message_Iter *
+_message_iterator_new(Eina_Bool writable)
+{
+   EDBus_Message_Iter *iter;
+
+   iter = calloc(1, sizeof(EDBus_Message_Iter));
+   EINA_SAFETY_ON_NULL_RETURN_VAL(iter, NULL);
+   EINA_MAGIC_SET(iter, EDBUS_MESSAGE_ITERATOR_MAGIC);
+   iter->writable = writable;
+
+   return iter;
+}
+
+EDBus_Message *edbus_message_new(Eina_Bool writable)
+{
+   EDBus_Message *msg = calloc(1, sizeof(EDBus_Message));
+   EINA_SAFETY_ON_NULL_RETURN_VAL(msg, NULL);
+   EINA_MAGIC_SET(msg, EDBUS_MESSAGE_MAGIC);
+   msg->refcount = 1;
+
+   msg->iterator = _message_iterator_new(writable);
+   EINA_SAFETY_ON_NULL_GOTO(msg->iterator, fail);
+
+   return msg;
+
+fail:
+   edbus_message_unref(msg);
+   return NULL;
+}
+
+EAPI EDBus_Message *
+edbus_message_method_call_new(const char *dest, const char *path, const char *iface, const char *method)
+{
+   EDBus_Message *msg;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(dest, NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(path, NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(iface, NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(method, NULL);
+
+   msg = edbus_message_new(EINA_TRUE);
+   EINA_SAFETY_ON_NULL_GOTO(msg, fail);
+
+   msg->dbus_msg = dbus_message_new_method_call(dest, path, iface, method);
+   dbus_message_iter_init_append(msg->dbus_msg, &msg->iterator->dbus_iterator);
+
+   return msg;
+
+fail:
+   edbus_message_unref(msg);
+   return NULL;
+}
+
+EAPI EDBus_Message *
+edbus_message_ref(EDBus_Message *msg)
+{
+   EDBUS_MESSAGE_CHECK_RETVAL(msg, NULL);
+   DBG("msg=%p, pre-refcount=%d", msg, msg->refcount);
+   msg->refcount++;
+   return msg;
+}
+
+static void
+_message_iterator_free(EDBus_Message_Iter *iter)
+{
+   Eina_Inlist *lst, *next;
+   EDBus_Message_Iter *sub;
+   if (!iter) return;
+
+   lst = iter->iterators;
+   while (lst)
+     {
+        next = lst->next;
+        sub = EINA_INLIST_CONTAINER_GET(lst, EDBus_Message_Iter);
+        _message_iterator_free(sub);
+        lst = next;
+     }
+   free(iter);
+}
+
+EAPI void
+edbus_message_unref(EDBus_Message *msg)
+{
+   EDBUS_MESSAGE_CHECK(msg);
+   DBG("msg=%p, pre-refcount=%d", msg, msg->refcount);
+   msg->refcount--;
+   if (msg->refcount > 0) return;
+
+   DBG("message free %p", msg);
+
+   EINA_MAGIC_SET(msg, EINA_MAGIC_NONE);
+   if (msg->dbus_msg)
+     dbus_message_unref(msg->dbus_msg);
+   msg->dbus_msg = NULL;
+
+   _message_iterator_free(msg->iterator);
+   free(msg);
+}
+
+EAPI const char *
+edbus_message_path_get(const EDBus_Message *msg)
+{
+   EDBUS_MESSAGE_CHECK_RETVAL(msg, NULL);
+   return dbus_message_get_path(msg->dbus_msg);
+}
+
+EAPI const char *
+edbus_message_interface_get(const EDBus_Message *msg)
+{
+   EDBUS_MESSAGE_CHECK_RETVAL(msg, NULL);
+   return dbus_message_get_interface(msg->dbus_msg);
+}
+
+EAPI const char *
+edbus_message_member_get(const EDBus_Message *msg)
+{
+   EDBUS_MESSAGE_CHECK_RETVAL(msg, NULL);
+   return dbus_message_get_member(msg->dbus_msg);
+}
+
+EAPI const char *
+edbus_message_destination_get(const EDBus_Message *msg)
+{
+   EDBUS_MESSAGE_CHECK_RETVAL(msg, NULL);
+   return dbus_message_get_destination(msg->dbus_msg);
+}
+
+EAPI const char *
+edbus_message_sender_get(const EDBus_Message *msg)
+{
+   EDBUS_MESSAGE_CHECK_RETVAL(msg, NULL);
+   return dbus_message_get_sender(msg->dbus_msg);
+}
+
+EAPI const char *
+edbus_message_signature_get(const EDBus_Message *msg)
+{
+   EDBUS_MESSAGE_CHECK_RETVAL(msg, NULL);
+   return dbus_message_get_signature(msg->dbus_msg);
+}
+
+EAPI Eina_Bool
+edbus_message_error_get(const EDBus_Message *msg, const char **name, const char **text)
+{
+   if (name) *name = NULL;
+   if (text) *text = NULL;
+
+   EDBUS_MESSAGE_CHECK_RETVAL(msg, EINA_FALSE);
+
+   if (dbus_message_get_type(msg->dbus_msg) != DBUS_MESSAGE_TYPE_ERROR)
+     return EINA_FALSE;
+
+   if (name)
+     *name = dbus_message_get_error_name(msg->dbus_msg);
+
+   if (text)
+     dbus_message_get_args(msg->dbus_msg, NULL, DBUS_TYPE_STRING, text,
+                           DBUS_TYPE_INVALID);
+
+   return EINA_TRUE;
+}
+
+static Eina_Bool
+_edbus_message_arguments_vget(EDBus_Message *msg, const char *signature, va_list ap)
+{
+   EDBus_Message_Iter *iter;
+   iter = edbus_message_iter_get(msg);
+   EDBUS_MESSAGE_ITERATOR_CHECK_RETVAL(iter, EINA_FALSE);
+
+   return edbus_message_iter_arguments_vget(iter, signature, ap);
+}
+
+EAPI EDBus_Message_Iter *
+edbus_message_iter_get(const EDBus_Message *msg)
+{
+   EDBUS_MESSAGE_CHECK_RETVAL(msg, NULL);
+   /* Something went wrong, msg->iterator should not be NULL */
+   EINA_SAFETY_ON_NULL_RETURN_VAL(msg->iterator, NULL);
+
+   return msg->iterator;
+}
+
+EAPI Eina_Bool
+edbus_message_arguments_get(const EDBus_Message *msg, const char *signature, ...)
+{
+   Eina_Bool ret;
+   va_list ap;
+
+   EDBUS_MESSAGE_CHECK_RETVAL(msg, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(signature, EINA_FALSE);
+
+   va_start(ap, signature);
+   ret = _edbus_message_arguments_vget((EDBus_Message *)msg, signature, ap);
+   va_end(ap);
+   return ret;
+}
+
+EAPI Eina_Bool
+edbus_message_arguments_vget(const EDBus_Message *msg, const char *signature, va_list ap)
+{
+   EDBUS_MESSAGE_CHECK_RETVAL(msg, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(signature, EINA_FALSE);
+   return _edbus_message_arguments_vget((EDBus_Message *)msg, signature, ap);
+}
+
+EAPI Eina_Bool
+edbus_message_iter_arguments_vset(EDBus_Message_Iter *iter, const char *signature, va_list ap)
+{
+   DBusSignatureIter signature_iter;
+   Eina_Bool r = EINA_TRUE;
+   char *type;
+
+   EDBUS_MESSAGE_ITERATOR_CHECK_RETVAL(iter, EINA_FALSE);
+   EINA_SAFETY_ON_FALSE_RETURN_VAL(iter->writable, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(signature, EINA_FALSE);
+
+   dbus_signature_iter_init(&signature_iter, signature);
+   while ((type = dbus_signature_iter_get_signature(&signature_iter)))
+     {
+        if (type[0] != DBUS_TYPE_VARIANT && !type[1])
+          r = append_basic(type[0], MAKE_PTR_FROM_VA_LIST(ap),
+                           &iter->dbus_iterator);
+        else
+          {
+             EDBus_Message_Iter **user_itr;
+             EDBus_Message_Iter *sub;
+
+             user_itr = va_arg(ap, EDBus_Message_Iter **);
+             sub = _message_iterator_new(EINA_TRUE);
+             EINA_SAFETY_ON_NULL_GOTO(sub, error);
+             iter->iterators = eina_inlist_append(iter->iterators,
+                                                  EINA_INLIST_GET(sub));
+
+             if (type[0] == DBUS_TYPE_ARRAY)
+               r = dbus_message_iter_open_container(&iter->dbus_iterator,
+                                                    type[0], type+1,
+                                                    &sub->dbus_iterator);
+             else if(type[1] == DBUS_TYPE_VARIANT)
+               {
+                  ERR("variant not supported by \
+                      edbus_message_iter_arguments_set(), \
+                      try edbus_message_iter_container_new()");
+                  goto error;
+               }
+             else
+               {
+                  char real_type;
+
+                  if (type[0] == DBUS_STRUCT_BEGIN_CHAR)
+                    real_type = DBUS_TYPE_STRUCT;
+                  else real_type = DBUS_TYPE_DICT_ENTRY;
+                  r = dbus_message_iter_open_container(&iter->dbus_iterator,
+                                                       real_type, NULL,
+                                                       &sub->dbus_iterator);
+               }
+             *user_itr = sub;
+          }
+
+        dbus_free(type);
+        if (!r || !dbus_signature_iter_next(&signature_iter)) break;
+        continue;
+error:
+       r = EINA_FALSE;
+       dbus_free(type);
+       break;
+     }
+   return r;
+}
+
+EAPI Eina_Bool
+edbus_message_iter_arguments_set(EDBus_Message_Iter *iter, const char *signature, ...)
+{
+   Eina_Bool r;
+   va_list ap;
+   EDBUS_MESSAGE_ITERATOR_CHECK_RETVAL(iter, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(signature, EINA_FALSE);
+
+   va_start(ap, signature);
+   r = edbus_message_iter_arguments_vset(iter, signature, ap);
+   va_end(ap);
+   return r;
+}
+
+static Eina_Bool
+append_basic(char type, va_list *vl, DBusMessageIter *iter)
+{
+   switch (type)
+     {
+      case DBUS_TYPE_BYTE:
+        {
+           uint32_t read_byte = va_arg(*vl, uint32_t);
+           uint8_t byte = read_byte;
+           return dbus_message_iter_append_basic(iter, type, &byte);
+        }
+      case DBUS_TYPE_INT16:
+        {
+           int32_t read_int16 = va_arg(*vl, int32_t);
+           int16_t int16 = read_int16;
+           return dbus_message_iter_append_basic(iter, type, &int16);
+        }
+      case DBUS_TYPE_UINT16:
+        {
+           uint32_t read_uint16 = va_arg(*vl, uint32_t);
+           uint16_t uint16 = read_uint16;
+           return dbus_message_iter_append_basic(iter, type, &uint16);
+        }
+      case DBUS_TYPE_BOOLEAN:
+      case DBUS_TYPE_INT32:
+#ifdef DBUS_TYPE_UNIX_FD
+      case DBUS_TYPE_UNIX_FD:
+#endif
+        {
+           int32_t int32 = va_arg(*vl, int32_t);
+           return dbus_message_iter_append_basic(iter, type, &int32);
+        }
+      case DBUS_TYPE_UINT32:
+        {
+           uint32_t uint32 = va_arg(*vl, uint32_t);
+           return dbus_message_iter_append_basic(iter, type, &uint32);
+        }
+      case DBUS_TYPE_INT64:
+        {
+           int64_t int64 = va_arg(*vl, int64_t);
+           return dbus_message_iter_append_basic(iter, type, &int64);
+        }
+      case DBUS_TYPE_UINT64:
+        {
+           uint64_t uint64 = va_arg(*vl, uint64_t);
+           return dbus_message_iter_append_basic(iter, type, &uint64);
+        }
+      case DBUS_TYPE_DOUBLE:
+        {
+           double double_ieee = va_arg(*vl, double);
+           return dbus_message_iter_append_basic(iter, type, &double_ieee);
+        }
+      case DBUS_TYPE_STRING:
+      case DBUS_TYPE_OBJECT_PATH:
+      case DBUS_TYPE_SIGNATURE:
+        {
+           char *string = va_arg(*vl, char*);
+           return dbus_message_iter_append_basic(iter, type, &string);
+        }
+      default:
+         ERR("Type not handled %c", type);
+         return EINA_FALSE;
+     }
+}
+
+static Eina_Bool
+_edbus_message_arguments_vset(EDBus_Message *msg, const char *signature, va_list ap)
+{
+   DBusSignatureIter signature_iter;
+   EDBus_Message_Iter *iter;
+   char *type;
+   Eina_Bool r = EINA_TRUE;
+
+   if (!signature[0]) return EINA_TRUE;
+   EINA_SAFETY_ON_FALSE_RETURN_VAL(dbus_signature_validate(signature, NULL),
+                                   EINA_FALSE);
+
+   iter = edbus_message_iter_get(msg);
+   EINA_SAFETY_ON_FALSE_RETURN_VAL(iter->writable, EINA_FALSE);
+
+   dbus_signature_iter_init(&signature_iter, signature);
+   while ((type = dbus_signature_iter_get_signature(&signature_iter)))
+     {
+        if (dbus_type_is_basic(type[0]))
+          r = append_basic(type[0], MAKE_PTR_FROM_VA_LIST(ap),
+                           &iter->dbus_iterator);
+        else
+          {
+             ERR("sig = %s | edbus_message_arguments_set() and \
+                  edbus_message_arguments_vset() only support basic types, \
+                  to complex types use edbus_message_iter_* functions", signature);
+             r = EINA_FALSE;
+          }
+
+        dbus_free(type);
+        if (!r || !dbus_signature_iter_next(&signature_iter)) break;
+     }
+
+   return r;
+}
+
+EAPI Eina_Bool
+edbus_message_arguments_set(EDBus_Message *msg, const char *signature, ...)
+{
+   Eina_Bool ret;
+   va_list ap;
+
+   EDBUS_MESSAGE_CHECK_RETVAL(msg, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(signature, EINA_FALSE);
+
+   va_start(ap, signature);
+   ret = _edbus_message_arguments_vset(msg, signature, ap);
+   va_end(ap);
+   return ret;
+}
+
+EAPI Eina_Bool
+edbus_message_arguments_vset(EDBus_Message *msg, const char *signature, va_list ap)
+{
+   EDBUS_MESSAGE_CHECK_RETVAL(msg, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(signature, EINA_FALSE);
+   return _edbus_message_arguments_vset(msg, signature, ap);
+}
+
+EAPI EDBus_Message_Iter *
+edbus_message_iter_container_new(EDBus_Message_Iter *iter, int type, const char* contained_signature)
+{
+   EDBus_Message_Iter *sub;
+
+   EDBUS_MESSAGE_ITERATOR_CHECK_RETVAL(iter, NULL);
+   sub = _message_iterator_new(EINA_TRUE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(sub, NULL);
+
+   if (!dbus_message_iter_open_container(&iter->dbus_iterator, type,
+                                         contained_signature,
+                                         &sub->dbus_iterator))
+     goto cleanup;
+
+   iter->iterators = eina_inlist_append(iter->iterators, EINA_INLIST_GET(sub));
+   return sub;
+
+cleanup:
+   free(sub);
+   return NULL;
+}
+
+EAPI Eina_Bool
+edbus_message_iter_container_close(EDBus_Message_Iter *iter, EDBus_Message_Iter *sub)
+{
+   EDBUS_MESSAGE_ITERATOR_CHECK_RETVAL(iter, EINA_FALSE);
+   EDBUS_MESSAGE_ITERATOR_CHECK_RETVAL(sub, EINA_FALSE);
+   EINA_SAFETY_ON_FALSE_RETURN_VAL(iter->writable, EINA_FALSE);
+   return dbus_message_iter_close_container(&iter->dbus_iterator,
+                                            &sub->dbus_iterator);
+}
+
+EAPI Eina_Bool
+edbus_message_iter_basic_append(EDBus_Message_Iter *iter, int type, ...)
+{
+   Eina_Bool r;
+   va_list vl;
+   EDBUS_MESSAGE_ITERATOR_CHECK_RETVAL(iter, EINA_FALSE);
+   EINA_SAFETY_ON_FALSE_RETURN_VAL(iter->writable, EINA_FALSE);
+
+   va_start(vl, type);
+   r = append_basic(type, &vl, &iter->dbus_iterator);
+   va_end(vl);
+
+   return r;
+}
+
+EAPI void
+edbus_message_iter_basic_get(EDBus_Message_Iter *iter, void *value)
+{
+   EDBUS_MESSAGE_ITERATOR_CHECK(iter);
+   EINA_SAFETY_ON_TRUE_RETURN(iter->writable);
+   dbus_message_iter_get_basic(&iter->dbus_iterator, value);
+}
+
+EDBus_Message_Iter *
+edbus_message_iter_sub_iter_get(EDBus_Message_Iter *iter)
+{
+   EDBus_Message_Iter *sub;
+   EDBUS_MESSAGE_ITERATOR_CHECK_RETVAL(iter, NULL);
+   EINA_SAFETY_ON_TRUE_RETURN_VAL(iter->writable, NULL);
+
+   sub = _message_iterator_new(EINA_FALSE);
+   dbus_message_iter_recurse(&iter->dbus_iterator, &sub->dbus_iterator);
+   iter->iterators = eina_inlist_append(iter->iterators,
+                                        EINA_INLIST_GET(sub));
+   return sub;
+}
+
+EAPI char *
+edbus_message_iter_signature_get(EDBus_Message_Iter *iter)
+{
+   EDBUS_MESSAGE_ITERATOR_CHECK_RETVAL(iter, NULL);
+   return dbus_message_iter_get_signature(&iter->dbus_iterator);
+}
+
+EAPI Eina_Bool
+edbus_message_iter_next(EDBus_Message_Iter *iter)
+{
+   EDBUS_MESSAGE_ITERATOR_CHECK_RETVAL(iter, EINA_FALSE);
+   EINA_SAFETY_ON_TRUE_RETURN_VAL(iter->writable, EINA_FALSE);
+   return dbus_message_iter_next(&iter->dbus_iterator);
+}
+
+static void
+get_basic(char type, DBusMessageIter *iter, va_list *vl)
+{
+   switch (type)
+     {
+      case DBUS_TYPE_BYTE:
+        {
+           uint8_t *byte = va_arg(*vl, uint8_t *);
+           dbus_message_iter_get_basic(iter, byte);
+           break;
+        }
+      case DBUS_TYPE_BOOLEAN:
+        {
+           Eina_Bool *boolean = va_arg(*vl, Eina_Bool *);
+           dbus_bool_t val;
+           dbus_message_iter_get_basic(iter, &val);
+           *boolean = val;
+           break;
+        }
+      case DBUS_TYPE_INT16:
+        {
+           int16_t *int16 = va_arg(*vl, int16_t *);
+           dbus_message_iter_get_basic(iter, int16);
+           break;
+        }
+      case DBUS_TYPE_UINT16:
+        {
+           uint16_t *uint16 = va_arg(*vl, uint16_t *);
+           dbus_message_iter_get_basic(iter, uint16);
+           break;
+        }
+      case DBUS_TYPE_INT32:
+#ifdef DBUS_TYPE_UNIX_FD
+      case DBUS_TYPE_UNIX_FD:
+#endif
+        {
+           int32_t *int32 = va_arg(*vl, int32_t *);
+           dbus_message_iter_get_basic(iter, int32);
+           break;
+        }
+      case DBUS_TYPE_UINT32:
+        {
+           uint32_t *uint32 = va_arg(*vl, uint32_t *);
+           dbus_message_iter_get_basic(iter, uint32);
+           break;
+        }
+      case DBUS_TYPE_INT64:
+        {
+           int64_t *int64 = va_arg(*vl, int64_t *);
+           dbus_message_iter_get_basic(iter, int64);
+           break;
+        }
+      case DBUS_TYPE_UINT64:
+        {
+           uint64_t *uint64 = va_arg(*vl, uint64_t *);
+           dbus_message_iter_get_basic(iter, uint64);
+           break;
+        }
+      case DBUS_TYPE_DOUBLE:
+        {
+           double *double_ieee = va_arg(*vl, double *);
+           dbus_message_iter_get_basic(iter, double_ieee);
+           break;
+        }
+      case DBUS_TYPE_STRING:
+      case DBUS_TYPE_OBJECT_PATH:
+      case DBUS_TYPE_SIGNATURE:
+        {
+           char **string = va_arg(*vl, char**);
+           dbus_message_iter_get_basic(iter, string);
+           break;
+        }
+      default:
+        {
+           ERR("Type not handled %c", type);
+        }
+     }
+}
+
+EAPI Eina_Bool
+edbus_message_iter_fixed_array_get(EDBus_Message_Iter *iter, int signature, void *value, int *n_elements)
+{
+   EDBUS_MESSAGE_ITERATOR_CHECK_RETVAL(iter, EINA_FALSE);
+   EINA_SAFETY_ON_TRUE_RETURN_VAL(iter->writable, EINA_FALSE);
+
+   EINA_SAFETY_ON_FALSE_RETURN_VAL(
+        (dbus_message_iter_get_element_type(&iter->dbus_iterator) == signature),
+        EINA_FALSE);
+   dbus_message_iter_get_fixed_array(&iter->dbus_iterator, value, n_elements);
+   return EINA_TRUE;
+}
+
+/**
+ * Useful when iterating over arrays
+ */
+EAPI Eina_Bool
+edbus_message_iter_get_and_next(EDBus_Message_Iter *iter, char signature, ...)
+{
+   char type;
+   va_list vl;
+
+   EDBUS_MESSAGE_ITERATOR_CHECK_RETVAL(iter, EINA_FALSE);
+   EINA_SAFETY_ON_TRUE_RETURN_VAL(iter->writable, EINA_FALSE);
+   va_start(vl, signature);
+
+   type = dbus_message_iter_get_arg_type(&iter->dbus_iterator);
+   if (type == DBUS_TYPE_INVALID) return EINA_FALSE;
+   EINA_SAFETY_ON_FALSE_RETURN_VAL(type == signature, EINA_FALSE);
+
+   if (dbus_type_is_basic(type))
+     get_basic(type, &iter->dbus_iterator, &vl);
+   else
+     {
+        EDBus_Message_Iter *sub;
+        EDBus_Message_Iter **iter_var = va_arg(vl, EDBus_Message_Iter**);
+
+        sub = _message_iterator_new(EINA_FALSE);
+        EINA_SAFETY_ON_NULL_RETURN_VAL(sub, EINA_FALSE);
+        dbus_message_iter_recurse(&iter->dbus_iterator,
+                                  &sub->dbus_iterator);
+        iter->iterators = eina_inlist_append(iter->iterators,
+                                             EINA_INLIST_GET(sub));
+
+        *iter_var = sub;
+     }
+   va_end(vl);
+
+   dbus_message_iter_next(&iter->dbus_iterator);
+   return EINA_TRUE;
+}
+
+EAPI Eina_Bool
+edbus_message_iter_arguments_get(EDBus_Message_Iter *iter, const char *signature, ...)
+{
+   va_list ap;
+   Eina_Bool ret;
+
+   va_start(ap, signature);
+   ret = edbus_message_iter_arguments_vget(iter, signature, ap);
+   va_end(ap);
+
+   return ret;
+}
+
+EAPI Eina_Bool
+edbus_message_iter_arguments_vget(EDBus_Message_Iter *iter, const char *signature, va_list ap)
+{
+   int current_type;
+   DBusSignatureIter signature_iter;
+
+   EDBUS_MESSAGE_ITERATOR_CHECK_RETVAL(iter, EINA_FALSE);
+   EINA_SAFETY_ON_TRUE_RETURN_VAL(iter->writable, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(signature, EINA_FALSE);
+   EINA_SAFETY_ON_FALSE_RETURN_VAL(dbus_signature_validate(signature, NULL), EINA_FALSE);
+
+   dbus_signature_iter_init(&signature_iter, signature);
+   current_type = dbus_message_iter_get_arg_type(&iter->dbus_iterator);
+   while (current_type != DBUS_TYPE_INVALID)
+     {
+        char *iter_sig = dbus_signature_iter_get_signature(&signature_iter);
+        int c = iter_sig[0];
+
+        dbus_free(iter_sig);
+        dbus_signature_iter_next(&signature_iter);
+
+        if ((c != current_type) && !(current_type == 'r' && c == '('))
+          {
+             ERR("Type in iterator different of signature");
+             return EINA_FALSE;
+          }
+
+        if (dbus_type_is_basic(current_type))
+          get_basic(current_type, &iter->dbus_iterator, MAKE_PTR_FROM_VA_LIST(ap));
+        else
+          {
+             EDBus_Message_Iter **user_itr = va_arg(ap, EDBus_Message_Iter **);
+             EDBus_Message_Iter *sub_itr;
+
+             sub_itr = _message_iterator_new(EINA_FALSE);
+             EINA_SAFETY_ON_NULL_RETURN_VAL(sub_itr, EINA_FALSE);
+             dbus_message_iter_recurse(&iter->dbus_iterator,
+                                       &sub_itr->dbus_iterator);
+             iter->iterators = eina_inlist_append(iter->iterators,
+                                                  EINA_INLIST_GET(sub_itr));
+             *user_itr = sub_itr;
+          }
+        dbus_message_iter_next(&iter->dbus_iterator);
+        current_type = dbus_message_iter_get_arg_type(&iter->dbus_iterator);
+     }
+   return EINA_TRUE;
+}
+
+EAPI void
+edbus_message_iter_del(EDBus_Message_Iter *iter)
+{
+   EDBUS_MESSAGE_ITERATOR_CHECK(iter);
+   _message_iterator_free(iter);
+}
+
+/* TODO: proper doc
+ * Return the *reply* to @msg, i.e. @msg is the message we are replying to.
+ */
+EAPI EDBus_Message *
+edbus_message_error_new(const EDBus_Message *msg, const char *error_name, const char *error_msg)
+{
+   EDBus_Message *reply;
+
+   EDBUS_MESSAGE_CHECK_RETVAL(msg, NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(error_name, NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(error_msg, NULL);
+
+   reply = edbus_message_new(EINA_FALSE);
+   reply->dbus_msg = dbus_message_new_error(msg->dbus_msg,
+                                            error_name, error_msg);
+
+   /*
+    * Technically user should not append more arguments in an error message but
+    * we can't leave its iter as NULL.
+    */
+   dbus_message_iter_init_append(reply->dbus_msg,
+                                 &reply->iterator->dbus_iterator);
+
+   return reply;
+}
+
+EAPI EDBus_Message *
+edbus_message_method_return_new(const EDBus_Message *msg)
+{
+   EDBus_Message *reply;
+   EDBUS_MESSAGE_CHECK_RETVAL(msg, NULL);
+
+   reply = edbus_message_new(EINA_TRUE);
+   reply->dbus_msg = dbus_message_new_method_return(msg->dbus_msg);
+
+   dbus_message_iter_init_append(reply->dbus_msg,
+                                 &reply->iterator->dbus_iterator);
+
+   return reply;
+}
+
+EAPI EDBus_Message *
+edbus_message_signal_new(const char *path, const char *interface, const char *name)
+{
+   EDBus_Message *msg;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(path, NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(interface, NULL);
+   EINA_SAFETY_ON_FALSE_RETURN_VAL(name, NULL);
+
+   msg = edbus_message_new(EINA_TRUE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(msg, NULL);
+
+   msg->dbus_msg = dbus_message_new_signal(path, interface, name);
+   dbus_message_iter_init_append(msg->dbus_msg,
+                                 &msg->iterator->dbus_iterator);
+
+   return msg;
+}
diff --git a/src/lib/edbus_message.h b/src/lib/edbus_message.h
new file mode 100644 (file)
index 0000000..369bbe8
--- /dev/null
@@ -0,0 +1,281 @@
+#ifndef EDBUS_MESSAGE_H
+#define EDBUS_MESSAGE_H 1
+
+/**
+ * @defgroup EDBus_Message Message
+ *
+ * @{
+ */
+
+/**
+ * @brief Constructs a new message to invoke a method on a remote object.
+ *
+ * @param dest bus name or unique id of the remote applications
+ * @param path object path
+ * @param iface interface name
+ * @param method name of method that will be called
+ *
+ * @return a new EDBus_Message, free with edbus_message_unref()
+ */
+EAPI EDBus_Message        *edbus_message_method_call_new(const char *dest, const char *path, const char *iface, const char *method) EINA_ARG_NONNULL(1, 2, 3, 4) EINA_WARN_UNUSED_RESULT EINA_MALLOC;
+
+/**
+ * @brief Increase message reference.
+ */
+EAPI EDBus_Message        *edbus_message_ref(EDBus_Message *msg) EINA_ARG_NONNULL(1);
+/**
+ * @brief Decrease message reference.
+ * If reference == 0 message will be freed and all its children.
+ */
+EAPI void                  edbus_message_unref(EDBus_Message *msg) EINA_ARG_NONNULL(1);
+
+EAPI const char           *edbus_message_path_get(const EDBus_Message *msg) EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT;
+EAPI const char           *edbus_message_interface_get(const EDBus_Message *msg) EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT;
+EAPI const char           *edbus_message_member_get(const EDBus_Message *msg) EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT;
+EAPI const char           *edbus_message_destination_get(const EDBus_Message *msg) EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT;
+EAPI const char           *edbus_message_sender_get(const EDBus_Message *msg) EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT;
+EAPI const char           *edbus_message_signature_get(const EDBus_Message *msg) EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT;
+
+/**
+ * @brief Creates a new message that is an error reply to another message.
+ *
+ * @param reply the message we're replying to
+ * @param error_name the error name
+ * @param error_msg the error message string
+ *
+ * @return new EDBus_Message, free with edbus_message_unref()
+ */
+EAPI EDBus_Message        *edbus_message_error_new(const EDBus_Message *reply, const char *error_name, const char *error_msg) EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT;
+/**
+ * @brief Constructs a message that is a reply to a method call.
+ *
+ * @param msg the message we're replying to
+ *
+ * @return new EDBus_Message, free with edbus_message_unref()
+ */
+EAPI EDBus_Message        *edbus_message_method_return_new(const EDBus_Message *msg) EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT;
+/**
+ * @brief Constructs a new message representing a signal emission.
+ *
+ * @param path of the object that was emiting the signal
+ * @param interface
+ * @param name
+ *
+ * @return new EDBus_Message, free with edbus_message_unref()
+ */
+EAPI EDBus_Message        *edbus_message_signal_new(const char *path, const char *interface, const char *name) EINA_ARG_NONNULL(1, 2, 3) EINA_WARN_UNUSED_RESULT;
+
+/**
+ * @brief If EDBus_Message is a message error return EINA_TRUE and fills
+ * name and text if their pointers is not null.
+ */
+EAPI Eina_Bool             edbus_message_error_get(const EDBus_Message *msg, const char **name, const char **text) EINA_ARG_NONNULL(1);
+
+/**
+ * @brief Get data from EDBus_Message. For each complete type we must have
+ * a pointer to store its value. In case of complex type EDBus_Message_Iter
+ * needs to be need.
+ */
+EAPI Eina_Bool             edbus_message_arguments_get(const EDBus_Message *msg, const char *signature, ...) EINA_ARG_NONNULL(1, 2) EINA_WARN_UNUSED_RESULT;
+/**
+ * @brief Get data from EDBus_Message. For each complete type we must have
+ * a pointer to store its value, in case of complex type
+ * EDBus_Message_Iter needs to be used.
+ */
+EAPI Eina_Bool             edbus_message_arguments_vget(const EDBus_Message *msg, const char *signature, va_list ap) EINA_ARG_NONNULL(1, 2) EINA_WARN_UNUSED_RESULT;
+
+/**
+ * @brief Set data to EDBus_Message.
+ *
+ * This function only supports basic type, for complex types use
+ * edbus_message_iter_* functions.
+ */
+EAPI Eina_Bool             edbus_message_arguments_set(EDBus_Message *msg, const char *signature, ...) EINA_ARG_NONNULL(1, 2);
+/**
+ * @brief Set data to EDBus_Message.
+ *
+ * This function only supports basic types, for complex types use
+ * edbus_message_iter_* functions.
+ */
+EAPI Eina_Bool             edbus_message_arguments_vset(EDBus_Message *msg, const char *signature, va_list ap) EINA_ARG_NONNULL(1, 2);
+
+/**
+ * @defgroup EDBus_Message_Iter Iterator
+ * @{
+ */
+/**
+ * @brief Create and appends a typed iterator to another iterator.
+ *
+ * After append data to returned iterator it must be closed calling
+ * edbus_message_iter_container_close().
+ *
+ * Container types are for example struct, variant, and array.
+ * For variants, the contained_signature should be the type of the single
+ * value inside the variant. For structs and dict entries, contained_signature
+ * should be NULL; it will be set to whatever types you write into the struct.
+ * For arrays, contained_signature should be the type of the array elements.
+ *
+ * @param iter parent of the new iterator
+ * @param type of iterator (e.g struct, dict, variant or array)
+ * @param contained_signature signature of what iterator will store
+ *
+ * @return the new iterator
+ */
+EAPI EDBus_Message_Iter *edbus_message_iter_container_new(EDBus_Message_Iter *iter, int type, const char* contained_signature) EINA_ARG_NONNULL(1, 3) EINA_WARN_UNUSED_RESULT;
+/**
+ * @brief Append a basic type to EDBus_Iterator.
+ */
+EAPI Eina_Bool               edbus_message_iter_basic_append(EDBus_Message_Iter *iter, int type, ...) EINA_ARG_NONNULL(1, 3);
+/**
+ * @brief Set data to EDBus_Message_Iter. For each complete in signature
+ * you need pass the value, in case of complex type a pointer to be allocated a
+ * EDBus_Message_Iter that you need fill and close.
+ *
+ * It's not possible open two iterators at same Iterator. Example:
+ * "aiai", to set this you need create and put the first array with
+ * edbus_message_iter_container_new() fill array with data and close then
+ * you could open the second array with edbus_message_iter_container_new().
+ *
+ * @param iter iterator
+ * @param signature of data
+ * @param ... values
+ *
+ * @note This function don't support variant, use instead
+ * edbus_message_iter_container_new() to create the variant fill
+ * data and close it..
+ */
+EAPI Eina_Bool               edbus_message_iter_arguments_set(EDBus_Message_Iter *iter, const char *signature, ...) EINA_ARG_NONNULL(1, 2);
+/**
+ * @brief Set data to EDBus_Message_Iter. For each complete in signature
+ * you need pass the value, in case of complex type a pointer to be allocated a
+ * EDBus_Message_Iter that you need fill and close.
+ *
+ * It's not possible open two iterators at same Iterator. Example:
+ * "aiai", to set this you need create and put the first array with
+ * edbus_message_iter_container_new() fill array with data and close then
+ * you could open the second array with edbus_message_iter_container_new().
+ *
+ * @param iter iterator
+ * @param signature of data
+ * @param ap va_list with the values
+ *
+ * @note This function don't support variant, use instead
+ * edbus_message_iter_container_new() to create the variant fill
+ * data and close it.
+ */
+EAPI Eina_Bool               edbus_message_iter_arguments_vset(EDBus_Message_Iter *iter, const char *signature, va_list ap) EINA_ARG_NONNULL(1, 2, 3);
+/**
+ * @brief Closes a container-typed value appended to the message.
+ *
+ * @param iter parent of the sub-iterator
+ * @param sub the iterator that will be closed
+ *
+ * @return EINA_FALSE if iterator was already close or if not enough memory
+ */
+EAPI Eina_Bool               edbus_message_iter_container_close(EDBus_Message_Iter *iter, EDBus_Message_Iter *sub) EINA_ARG_NONNULL(1, 2);
+
+/**
+ * @brief Get the main EDBus_Message_Iter from the EDBus_Message.
+ */
+EAPI EDBus_Message_Iter *edbus_message_iter_get(const EDBus_Message *msg) EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT;
+/**
+ * @brief Get a basic type from EDBus_Iterator.
+ */
+EAPI void                    edbus_message_iter_basic_get(EDBus_Message_Iter *iter, void *value) EINA_ARG_NONNULL(1, 2);
+
+/**
+ * @brief Returns the current signature of a message iterator.
+ *
+ * @note The returned string must be freed.
+ */
+EAPI char                   *edbus_message_iter_signature_get(EDBus_Message_Iter *iter) EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT;
+/**
+ * @brief Moves the iterator to the next field, if any.
+ * @param iter iterator
+ *
+ * @return if iterator was reach to end return EINA_FALSE
+ */
+EAPI Eina_Bool               edbus_message_iter_next(EDBus_Message_Iter *iter) EINA_ARG_NONNULL(1);
+/**
+ * @brief Get a complete type from EDBus_Message_Iter if is not at the end
+ * of iterator and move to next field.
+ * Useful to iterate over arrays.
+ *
+ * @param iter iterator
+ * @param type of the next completed type in Iterator
+ * @param ... pointer of where data will be stored
+ *
+ * @param if iterator was reach to end or if type different of the type that
+ * iterator points return EINA_FALSE
+ *
+ */
+EAPI Eina_Bool               edbus_message_iter_get_and_next(EDBus_Message_Iter *iter, char type, ...) EINA_ARG_NONNULL(1, 2, 3);
+/**
+ * @brief Reads a block of fixed-length values from the message iterator.
+ *
+ * Fixed-length values are those basic types that are not string-like,
+ * such as integers, bool, double. The returned block will be from the
+ * current position in the array until the end of the array.
+ *
+ * There is one exception here: although EDBUS_TYPE_UNIX_FD is considered a
+ * 'fixed' type arrays of this type may not be read with this function.
+ *
+ * The value argument should be the address of a location to store the returned
+ * array. So for int32 it should be a "const dbus_int32_t**" The returned value
+ * is by reference and should not be freed.
+ *
+ * Because the array is not copied, this function runs in constant time and is
+ * fast; it's much preferred over walking the entire array with an iterator.
+ */
+EAPI Eina_Bool edbus_message_iter_fixed_array_get(EDBus_Message_Iter *iter, int signature, void *value, int *n_elements) EINA_ARG_NONNULL(1, 3, 4);
+/**
+ * @brief Get data from EDBus_Message_Iter, for each complete type must have
+ * a pointer to store his value, in case of complex type a
+ * EDBus_Message_Iter will be need.
+ *
+ * @param iter iterator
+ * @param signature of the complete data types on interator
+ * @param ... pointers of where data will be stored
+ *
+ * @return EINA_FALSE if signature different from signature in iterator
+ */
+EAPI Eina_Bool               edbus_message_iter_arguments_get(EDBus_Message_Iter *iter, const char *signature, ...) EINA_ARG_NONNULL(1, 2);
+/**
+ * @brief Get data from EDBus_Message_Iter, for each complete type must have
+ * a pointer to store his value, in case of complex type a
+ * EDBus_Message_Iter will be need.
+ *
+ * @param iter iterator
+ * @param signature of the complete data types on interator
+ * @param ap va_list of the pointers of where data will be stored
+ *
+ * @return EINA_FALSE if signature different from signature in iterator
+ */
+EAPI Eina_Bool               edbus_message_iter_arguments_vget(EDBus_Message_Iter *iter, const char *signature, va_list ap) EINA_ARG_NONNULL(1, 2);
+
+/**
+ * @brief Manually delete the iterator.
+ *
+ * Iterators are usually bound to the life of @ref EDBus_Message
+ * they were created from, being deleted automatically once the
+ * message is deleted.
+ *
+ * However when dealing with huge arrays or dicts it may become a
+ * major memory impact to leave the unused iterators alive. By
+ * calling this function one states the iterator is not used anymore
+ * and can be deleted.
+ *
+ * @param iter the iterator to be deleted.
+ */
+EAPI void                  edbus_message_iter_del(EDBus_Message_Iter *iter) EINA_ARG_NONNULL(1);
+/**
+ * @}
+ */
+
+#include "edbus_message_helper.h"
+#include "edbus_message_eina_value.h"
+
+/**
+ * @}
+ */
+#endif
diff --git a/src/lib/edbus_message_eina_value.h b/src/lib/edbus_message_eina_value.h
new file mode 100644 (file)
index 0000000..4c47f1a
--- /dev/null
@@ -0,0 +1,26 @@
+/**
+ * @defgroup Eina_Value
+ * @{
+ */
+
+/**
+ * Convert EDBus_Message to Eina_Value
+ *
+ * @param msg Message
+ * @return Eina_Value of type Eina_Value_Type_Struct
+ */
+EAPI Eina_Value *edbus_message_to_eina_value(const EDBus_Message *msg);
+
+/**
+ * Convert Eina_Value to EDBus_Message
+ *
+ * @param signature dbus signature
+ * @param msg where data will be put
+ * @param value source of data, must be of type Eina_Value_Type_Struct
+ * @return success or not
+ */
+EAPI Eina_Bool edbus_message_from_eina_value(const char *signature, EDBus_Message *msg, const Eina_Value *value);
+
+/**
+ * @}
+ */
diff --git a/src/lib/edbus_message_from_eina_value.c b/src/lib/edbus_message_from_eina_value.c
new file mode 100644 (file)
index 0000000..095c632
--- /dev/null
@@ -0,0 +1,371 @@
+#include "edbus_private.h"
+#include "edbus_private_types.h"
+
+static Eina_Bool _message_iter_from_eina_value_struct(const char *signature, EDBus_Message_Iter *iter, const Eina_Value *value);
+
+static Eina_Bool
+_compatible_type(int dbus_type, const Eina_Value_Type *value_type)
+{
+   switch (dbus_type)
+     {
+      case 'i':
+      case 'h':
+         return value_type == EINA_VALUE_TYPE_INT;
+      case 's':
+      case 'o':
+      case 'g':
+         return value_type == EINA_VALUE_TYPE_STRING;
+      case 'b':
+      case 'y':
+         return value_type == EINA_VALUE_TYPE_UCHAR;
+      case 'n':
+         return value_type == EINA_VALUE_TYPE_SHORT;
+      case 'q':
+         return value_type == EINA_VALUE_TYPE_USHORT;
+      case 'u':
+         return value_type == EINA_VALUE_TYPE_UINT;
+      case 'x':
+         return value_type == EINA_VALUE_TYPE_INT64;
+      case 't':
+         return value_type == EINA_VALUE_TYPE_UINT64;
+      case 'd':
+         return value_type == EINA_VALUE_TYPE_DOUBLE;
+      case 'a':
+         return value_type == EINA_VALUE_TYPE_ARRAY;
+      case '(':
+      case '{':
+      case 'e':
+      case 'r':
+         return value_type == EINA_VALUE_TYPE_STRUCT;
+      default:
+         ERR("Unknown type %c", dbus_type);
+         return EINA_FALSE;
+     }
+}
+
+static Eina_Bool
+_array_append(const char *type, const Eina_Value *value_array, EDBus_Message_Iter *iter)
+{
+   EDBus_Message_Iter *array;
+
+   EINA_SAFETY_ON_FALSE_RETURN_VAL(
+            edbus_message_iter_arguments_set(iter, type, &array), EINA_FALSE);
+   DBG("array of type %c", type[1]);
+   switch (type[1])
+     {
+      case '{':
+      case '(':
+        {
+           unsigned i = strlen(type+2);//remove 'a()' of len a(sv)
+           char *entry_sig = malloc(sizeof(char) * i);
+           memcpy(entry_sig, type+2, i);
+           entry_sig[i-1] = 0;
+
+           for (i = 0; i < eina_value_array_count(value_array); i++)
+             {
+                Eina_Value st;
+                EDBus_Message_Iter *entry;
+                eina_value_array_value_get(value_array, i, &st);
+                edbus_message_iter_arguments_set(array, type+1, &entry);
+                _message_iter_from_eina_value_struct(entry_sig, entry, &st);
+                edbus_message_iter_container_close(array, entry);
+                eina_value_flush(&st);
+             }
+           free(entry_sig);
+           break;
+        }
+      case 'a':
+        {
+           unsigned i;
+           for (i = 0; i < eina_value_array_count(value_array); i++)
+             {
+                Eina_Value inner_array;
+                EDBus_Message_Iter *sub_array;
+                eina_value_array_value_get(value_array, i, &inner_array);
+                edbus_message_iter_arguments_set(array, type+1, &sub_array);
+                _array_append(type+1, &inner_array, sub_array);
+                edbus_message_iter_container_close(array, sub_array);
+                eina_value_flush(&inner_array);
+             }
+        }
+      case 'v':
+        {
+           ERR("Variant not supported.");
+           return EINA_FALSE;
+        }
+      case 'i':
+      case 'h'://fd
+        {
+           int32_t z;
+           unsigned i;
+           for (i = 0; i < eina_value_array_count(value_array); i++)
+             {
+                eina_value_array_get(value_array, i, &z);
+                edbus_message_iter_basic_append(array, type[1], z);
+             }
+           break;
+        }
+      case 's':
+      case 'o'://object path
+      case 'g'://signature
+        {
+           const char *txt;
+           unsigned i;
+           for (i = 0; i < eina_value_array_count(value_array); i++)
+             {
+                eina_value_array_get(value_array, i, &txt);
+                edbus_message_iter_basic_append(array, type[1], txt);
+             }
+           break;
+        }
+      case 'b'://boolean
+      case 'y'://byte
+        {
+           unsigned char z;
+           unsigned i;
+           for (i = 0; i < eina_value_array_count(value_array); i++)
+             {
+                eina_value_array_get(value_array, i, &z);
+                edbus_message_iter_basic_append(array, type[1], z);
+             }
+           break;
+        }
+      case 'n'://int16
+        {
+           int16_t z;
+           unsigned i;
+           for (i = 0; i < eina_value_array_count(value_array); i++)
+             {
+                eina_value_array_get(value_array, i, &z);
+                edbus_message_iter_basic_append(array, type[1], z);
+             }
+           break;
+        }
+      case 'q'://uint16
+        {
+           uint16_t z;
+           unsigned i;
+           for (i = 0; i < eina_value_array_count(value_array); i++)
+             {
+                eina_value_array_get(value_array, i, &z);
+                edbus_message_iter_basic_append(array, type[1], z);
+             }
+           break;
+        }
+      case 'u'://uint32
+        {
+           uint32_t z;
+           unsigned i;
+           for (i = 0; i < eina_value_array_count(value_array); i++)
+             {
+                eina_value_array_get(value_array, i, &z);
+                edbus_message_iter_basic_append(array, type[1], z);
+             }
+           break;
+        }
+      case 'x'://int64
+        {
+           int64_t z;
+           unsigned i;
+           for (i = 0; i < eina_value_array_count(value_array); i++)
+             {
+                eina_value_array_get(value_array, i, &z);
+                edbus_message_iter_basic_append(array, type[1], z);
+             }
+           break;
+        }
+      case 't'://uint64
+        {
+           uint64_t z;
+           unsigned i;
+           for (i = 0; i < eina_value_array_count(value_array); i++)
+             {
+                eina_value_array_get(value_array, i, &z);
+                edbus_message_iter_basic_append(array, type[1], z);
+             }
+           break;
+        }
+      case 'd'://double
+        {
+           double z;
+           unsigned i;
+           for (i = 0; i < eina_value_array_count(value_array); i++)
+             {
+                eina_value_array_get(value_array, i, &z);
+                edbus_message_iter_basic_append(array, type[1], z);
+             }
+           break;
+        }
+      default:
+        {
+           ERR("Unknown type %c", type[1]);
+           return EINA_FALSE;
+        }
+     }
+   edbus_message_iter_container_close(iter, array);
+   return EINA_TRUE;
+}
+
+static Eina_Bool
+_basic_append(char type, const Eina_Value *value, const Eina_Value_Struct_Desc *desc, unsigned idx, EDBus_Message_Iter *iter)
+{
+   EINA_SAFETY_ON_FALSE_RETURN_VAL(
+            _compatible_type(type, desc->members[idx].type), EINA_FALSE);
+   switch (type)
+     {
+      case 'i'://int
+      case 'h'://fd
+        {
+           int32_t i;
+           eina_value_struct_get(value, desc->members[idx].name, &i);
+           edbus_message_iter_basic_append(iter, type, i);
+           break;
+        }
+      case 's':
+      case 'o'://object path
+      case 'g'://signature
+        {
+           const char *txt;
+           eina_value_struct_get(value, desc->members[idx].name, &txt);
+           edbus_message_iter_basic_append(iter, type, txt);
+           break;
+        }
+      case 'b'://boolean
+      case 'y'://byte
+        {
+           unsigned char byte;
+           eina_value_struct_get(value, desc->members[idx].name, &byte);
+           edbus_message_iter_basic_append(iter, type, byte);
+           break;
+        }
+      case 'n'://int16
+        {
+           int16_t i;
+           eina_value_struct_get(value, desc->members[idx].name, &i);
+           edbus_message_iter_basic_append(iter, type, i);
+           break;
+        }
+      case 'q'://uint16
+        {
+           uint16_t i;
+           eina_value_struct_get(value, desc->members[idx].name, &i);
+           edbus_message_iter_basic_append(iter, type, i);
+           break;
+        }
+      case 'u'://uint32
+        {
+           uint32_t i;
+           eina_value_struct_get(value, desc->members[idx].name, &i);
+           edbus_message_iter_basic_append(iter, type, i);
+           break;
+        }
+      case 'x'://int64
+        {
+           int64_t i;
+           eina_value_struct_get(value, desc->members[idx].name, &i);
+           edbus_message_iter_basic_append(iter, type, i);
+           break;
+        }
+      case 't'://uint64
+        {
+           uint64_t i;
+           eina_value_struct_get(value, desc->members[idx].name, &i);
+           edbus_message_iter_basic_append(iter, type, i);
+           break;
+        }
+      case 'd'://double
+        {
+           double d;
+           eina_value_struct_get(value, desc->members[idx].name, &d);
+           edbus_message_iter_basic_append(iter, type, d);
+           break;
+        }
+      default:
+        ERR("Unexpected type %c", type);
+        return EINA_FALSE;
+     }
+   return EINA_TRUE;
+}
+
+static Eina_Bool
+_message_iter_from_eina_value_struct(const char *signature, EDBus_Message_Iter *iter, const Eina_Value *value)
+{
+   unsigned i;
+   DBusSignatureIter signature_iter;
+   Eina_Bool r = EINA_TRUE;
+   char *type;
+   Eina_Value_Struct st;
+
+   EINA_SAFETY_ON_FALSE_RETURN_VAL(
+            eina_value_type_get(value) == EINA_VALUE_TYPE_STRUCT, EINA_FALSE);
+   eina_value_pget(value, &st);
+
+   dbus_signature_iter_init(&signature_iter, signature);
+   i = 0;
+   while ((type = dbus_signature_iter_get_signature(&signature_iter)))
+     {
+        DBG("type: %s", type);
+        if (type[0] != 'v' && !type[1])
+          r = _basic_append(type[0], value, st.desc, i, iter);
+        else if (type[0] == 'a')
+          {
+             Eina_Value value_array;
+
+             EINA_SAFETY_ON_FALSE_RETURN_VAL(
+                      _compatible_type(type[0], st.desc->members[i].type),
+                      EINA_FALSE);
+             eina_value_struct_value_get(value, st.desc->members[i].name,
+                                         &value_array);
+             r = _array_append(type, &value_array, iter);
+             eina_value_flush(&value_array);
+          }
+        else if (type[0] == '(')
+          {
+             Eina_Value inner_st;
+             EDBus_Message_Iter *sub_iter;
+             char *sub_sig;
+             unsigned len = strlen(type+1) -1;
+             sub_sig = malloc(sizeof(char) * len);
+             memcpy(sub_sig, type+1, len);
+             sub_sig[len-1] = 0;
+             EINA_SAFETY_ON_FALSE_RETURN_VAL(
+                         _compatible_type(type[0], st.desc->members[i].type),
+                         EINA_FALSE);
+             eina_value_struct_value_get(value, st.desc->members[i].name, &inner_st);
+             edbus_message_iter_arguments_set(iter, type, &sub_iter);
+             r = _message_iter_from_eina_value_struct(sub_sig, sub_iter,
+                                                      &inner_st);
+             edbus_message_iter_container_close(iter, sub_iter);
+             free(sub_sig);
+          }
+        else if (type[0] == 'v')
+          {
+             ERR("Variant not supported");
+             r = EINA_FALSE;
+          }
+        else
+          {
+             ERR("Unknown type %c", type[0]);
+             r = EINA_FALSE;
+          }
+        i++;
+        dbus_free(type);
+        if (!r || !dbus_signature_iter_next(&signature_iter)) break;
+     }
+   return r;
+}
+
+EAPI Eina_Bool
+edbus_message_from_eina_value(const char *signature, EDBus_Message *msg, const Eina_Value *value)
+{
+   EDBus_Message_Iter *iter;
+   EINA_SAFETY_ON_NULL_RETURN_VAL(signature, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(msg, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(value, EINA_FALSE);
+
+   iter = edbus_message_iter_get(msg);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(iter, EINA_FALSE);
+   EINA_SAFETY_ON_FALSE_RETURN_VAL(iter->writable, EINA_FALSE);
+
+   return _message_iter_from_eina_value_struct(signature, iter, value);
+}
diff --git a/src/lib/edbus_message_helper.c b/src/lib/edbus_message_helper.c
new file mode 100644 (file)
index 0000000..dad50bb
--- /dev/null
@@ -0,0 +1,31 @@
+#include "edbus_private.h"
+#include "edbus_private_types.h"
+
+EAPI void
+edbus_message_iter_dict_iterate(EDBus_Message_Iter *array, const char *signature, EDBus_Dict_Cb_Get cb, const void *data)
+{
+   EDBus_Message_Iter *entry;
+   char *iter_sig;
+   unsigned len;
+   EINA_SAFETY_ON_FALSE_RETURN(array);
+   EINA_SAFETY_ON_NULL_RETURN(signature);
+
+   iter_sig = edbus_message_iter_signature_get(array);
+   len = strlen(iter_sig + 1);
+   if (strncmp(signature, iter_sig + 1, len - 1))
+     {
+        ERR("Unexpected signature, expected is: %s", iter_sig);
+        free(iter_sig);
+        return;
+     }
+   free(iter_sig);
+
+   while (edbus_message_iter_get_and_next(array, 'e', &entry))
+     {
+        const void *key;
+        EDBus_Message_Iter *var;
+        if (!edbus_message_iter_arguments_get(entry, signature, &key, &var))
+          continue;
+        cb((void *)data, key, var);
+     }
+}
diff --git a/src/lib/edbus_message_helper.h b/src/lib/edbus_message_helper.h
new file mode 100644 (file)
index 0000000..4bad095
--- /dev/null
@@ -0,0 +1,21 @@
+/**
+ * @defgroup EDBus_Message_Helpers Helpers
+ *
+ * @{
+ */
+
+typedef void (*EDBus_Dict_Cb_Get)(void *data, const void *key, EDBus_Message_Iter *var);
+
+/**
+ * Iterate over a dictionary.
+ *
+ * @param dict iterator with array of entry
+ * @param signature of entry, example: "sv"
+ * @param cb callback that will be called in each entry
+ * @param data context data
+ */
+EAPI void edbus_message_iter_dict_iterate(EDBus_Message_Iter *dict, const char *signature, EDBus_Dict_Cb_Get cb, const void *data);
+
+/**
+ * @}
+ */
diff --git a/src/lib/edbus_message_to_eina_value.c b/src/lib/edbus_message_to_eina_value.c
new file mode 100644 (file)
index 0000000..5efbe42
--- /dev/null
@@ -0,0 +1,435 @@
+#include "edbus_private.h"
+#include "edbus_private_types.h"
+
+static void _message_iter_basic_array_to_eina_value(char type, Eina_Value *value, EDBus_Message_Iter *iter);
+
+static const Eina_Value_Type *
+_dbus_type_to_eina_value_type(char type)
+{
+   switch (type)
+     {
+      case 'i':
+      case 'h':
+         return EINA_VALUE_TYPE_INT;
+      case 's':
+      case 'o':
+      case 'g':
+         return EINA_VALUE_TYPE_STRING;
+      case 'b':
+      case 'y':
+         return EINA_VALUE_TYPE_UCHAR;
+      case 'n':
+         return EINA_VALUE_TYPE_SHORT;
+      case 'q':
+         return EINA_VALUE_TYPE_USHORT;
+      case 'u':
+         return EINA_VALUE_TYPE_UINT;
+      case 'x':
+         return EINA_VALUE_TYPE_INT64;
+      case 't':
+         return EINA_VALUE_TYPE_UINT64;
+      case 'd':
+         return EINA_VALUE_TYPE_DOUBLE;
+      case 'a':
+         return EINA_VALUE_TYPE_ARRAY;
+      case '(':
+      case '{':
+      case 'e':
+      case 'r':
+      case 'v':
+         return EINA_VALUE_TYPE_STRUCT;
+      default:
+         ERR("Unknown type %c", type);
+         return NULL;
+     }
+}
+
+static unsigned int
+_type_size(char type)
+{
+   switch (type)
+     {
+      case 'i':
+      case 'h':
+      case 'u':
+         return(sizeof(int32_t));
+      case 's':
+      case 'o':
+      case 'g':
+         return(sizeof(char *));
+      case 'b':
+      case 'y':
+         return(sizeof(unsigned char));
+      case 'n':
+      case 'q':
+         return(sizeof(int16_t));
+      case 'x':
+      case 't':
+         return(sizeof(int64_t));
+      case 'd':
+         return(sizeof(double));
+      case 'a':
+         return(sizeof(Eina_Value_Array));
+      case '(':
+      case '{':
+      case 'e':
+      case 'r':
+      case 'v':
+         return(sizeof(Eina_Value_Struct));
+      default:
+         ERR("Unknown type %c", type);
+         return 0;
+     }
+}
+
+static unsigned int
+_type_offset(char type, unsigned base)
+{
+   unsigned size, padding;
+   size = _type_size(type);
+   if (!(base % size))
+     return base;
+   padding = abs(base - size);
+   return base + padding;
+}
+
+static Eina_Value *
+_message_iter_array_to_eina_value(EDBus_Message_Iter *iter)
+{
+   Eina_Value *array_value;
+   char *sig;
+
+   sig = edbus_message_iter_signature_get(iter);
+   DBG("array of %s", sig);
+   array_value = eina_value_array_new(_dbus_type_to_eina_value_type(sig[0]), 0);
+   if (sig[0] == '(' || sig[0] == '{' || sig[0] == 'v')
+     {
+        EDBus_Message_Iter *entry;
+
+        if (sig[0] == '{')
+          sig[0] = 'e';
+        else if (sig[0] == '(')
+          sig[0] = 'r';
+
+        while (edbus_message_iter_get_and_next(iter, sig[0], &entry))
+          {
+             Eina_Value *data = _message_iter_struct_to_eina_value(entry);
+             Eina_Value_Struct st;
+             eina_value_get(data, &st);
+             eina_value_array_append(array_value, st);
+          }
+     }
+   else if (sig[0] == 'a')
+     {
+        EDBus_Message_Iter *entry;
+        while (edbus_message_iter_get_and_next(iter, sig[0], &entry))
+          {
+             Eina_Value *data = _message_iter_array_to_eina_value(entry);
+             Eina_Value_Array inner_array;
+             eina_value_get(data, &inner_array);
+             eina_value_array_append(array_value, inner_array);
+          }
+     }
+   else
+     _message_iter_basic_array_to_eina_value(sig[0], array_value, iter);
+
+   DBG("return array of %s", sig);
+   free(sig);
+   return array_value;
+}
+
+static void
+_message_iter_basic_array_to_eina_value(char type, Eina_Value *value, EDBus_Message_Iter *iter)
+{
+   switch (type)
+    {
+       case 'i':
+       case 'h'://fd
+         {
+            int32_t i;
+            while (edbus_message_iter_get_and_next(iter, type, &i))
+              eina_value_array_append(value, i);
+            break;
+         }
+       case 's':
+       case 'o'://object path
+       case 'g'://signature
+         {
+            const char *txt;
+            while (edbus_message_iter_get_and_next(iter, type, &txt))
+              eina_value_array_append(value, txt);
+            break;
+         }
+       case 'b'://boolean
+       case 'y'://byte
+         {
+            unsigned char byte;
+            while (edbus_message_iter_get_and_next(iter, type, &byte))
+              eina_value_array_append(value, byte);
+            break;
+         }
+       case 'n'://int16
+         {
+            int16_t i;
+            while (edbus_message_iter_get_and_next(iter, type, &i))
+              eina_value_array_append(value, i);
+            break;
+         }
+       case 'q'://uint16
+         {
+            uint16_t i;
+            while (edbus_message_iter_get_and_next(iter, type, &i))
+              eina_value_array_append(value, i);
+            break;
+         }
+       case 'u'://uint32
+         {
+            uint32_t i;
+            while (edbus_message_iter_get_and_next(iter, type, &i))
+              eina_value_array_append(value, i);
+            break;
+         }
+       case 'x'://int64
+         {
+            int64_t i;
+            while (edbus_message_iter_get_and_next(iter, type, &i))
+              eina_value_array_append(value, i);
+            break;
+         }
+       case 't'://uint64
+         {
+            uint64_t i;
+            while (edbus_message_iter_get_and_next(iter, type, &i))
+              eina_value_array_append(value, i);
+            break;
+         }
+       case 'd'://double
+         {
+            double d;
+            while (edbus_message_iter_get_and_next(iter, type, &d))
+              eina_value_array_append(value, d);
+            break;
+         }
+    }
+}
+
+#define ARG "arg%d"
+
+typedef struct _EDBus_Struct_Desc
+{
+   Eina_Value_Struct_Desc base;
+   int refcount;
+} EDBus_Struct_Desc;
+
+static void *
+_ops_malloc(const Eina_Value_Struct_Operations *ops, const Eina_Value_Struct_Desc *desc)
+{
+   EDBus_Struct_Desc *edesc = (EDBus_Struct_Desc*)desc;
+   edesc->refcount++;
+   DBG("%p refcount=%d", edesc, edesc->refcount);
+   return malloc(desc->size);
+}
+
+static void
+_ops_free(const Eina_Value_Struct_Operations *ops, const Eina_Value_Struct_Desc *desc, void *memory)
+{
+   EDBus_Struct_Desc *edesc = (EDBus_Struct_Desc*) desc;
+   edesc->refcount--;
+   free(memory);
+   DBG("%p refcount=%d", edesc, edesc->refcount);
+   if (edesc->refcount <= 0)
+     {
+        unsigned i;
+        for (i = 0; i < edesc->base.member_count; i++)
+          free((char *)edesc->base.members[i].name);
+        free((Eina_Value_Struct_Member *)edesc->base.members);
+        free(edesc);
+     }
+}
+
+static Eina_Value_Struct_Operations operations =
+{
+   EINA_VALUE_STRUCT_OPERATIONS_VERSION,
+   _ops_malloc,
+   _ops_free,
+   NULL,
+   NULL,
+   NULL
+};
+
+Eina_Value *
+_message_iter_struct_to_eina_value(EDBus_Message_Iter *iter)
+{
+   int type;
+   Eina_Value *value_st;
+   Eina_Array *st_members = eina_array_new(1);
+   unsigned int offset = 0, z;
+   static char name[7];//arg000 + \0
+   Eina_Value_Struct_Member *members;
+   EDBus_Struct_Desc *st_desc;
+   Eina_Array *st_values = eina_array_new(1);
+
+   DBG("begin struct");
+   st_desc = calloc(1, sizeof(EDBus_Struct_Desc));
+   st_desc->base.version = EINA_VALUE_STRUCT_DESC_VERSION;
+   st_desc->base.ops = &operations;
+
+   //create member list
+   z = 0;
+   while ((type = dbus_message_iter_get_arg_type(&iter->dbus_iterator)) != DBUS_TYPE_INVALID)
+     {
+        Eina_Value_Struct_Member *m;
+        Eina_Value *v;
+
+        m = calloc(1, sizeof(Eina_Value_Struct_Member));
+        sprintf(name, ARG, z);
+        m->name = strdup(name);
+        offset = _type_offset(type, offset);
+        m->offset = offset;
+        offset += _type_size(type);
+        m->type = _dbus_type_to_eina_value_type(type);
+        eina_array_push(st_members, m);
+
+        DBG("type = %c", type);
+        switch (type)
+          {
+           case 'i'://int
+           case 'h'://fd
+             {
+                int32_t i;
+                v = eina_value_new(EINA_VALUE_TYPE_INT);
+                edbus_message_iter_basic_get(iter, &i);
+                eina_value_set(v, i);
+                break;
+             }
+           case 's':
+           case 'o'://object path
+           case 'g'://signature
+             {
+                const char *txt;
+                v = eina_value_new(EINA_VALUE_TYPE_STRING);
+                edbus_message_iter_basic_get(iter, &txt);
+                eina_value_set(v, txt);
+                break;
+             }
+           case 'b'://boolean
+           case 'y'://byte
+             {
+                unsigned char byte;
+                v = eina_value_new(EINA_VALUE_TYPE_UCHAR);
+                edbus_message_iter_basic_get(iter, &byte);
+                eina_value_set(v, byte);
+                break;
+             }
+           case 'n'://int16
+             {
+                int16_t i;
+                v = eina_value_new(EINA_VALUE_TYPE_SHORT);
+                edbus_message_iter_basic_get(iter, &i);
+                eina_value_set(v, i);
+                break;
+             }
+           case 'q'://uint16
+             {
+                uint16_t i;
+                v = eina_value_new(EINA_VALUE_TYPE_USHORT);
+                edbus_message_iter_basic_get(iter, &i);
+                eina_value_set(v, i);
+                break;
+             }
+           case 'u'://uint32
+             {
+                uint32_t i;
+                v = eina_value_new(EINA_VALUE_TYPE_UINT);
+                edbus_message_iter_basic_get(iter, &i);
+                eina_value_set(v, i);
+                break;
+             }
+           case 'x'://int64
+             {
+                int64_t i;
+                v = eina_value_new(EINA_VALUE_TYPE_INT64);
+                edbus_message_iter_basic_get(iter, &i);
+                eina_value_set(v, i);
+                break;
+             }
+           case 't'://uint64
+             {
+                uint64_t i;
+                v = eina_value_new(EINA_VALUE_TYPE_UINT64);
+                edbus_message_iter_basic_get(iter, &i);
+                eina_value_set(v, i);
+                break;
+             }
+           case 'd'://double
+             {
+                double d;
+                v = eina_value_new(EINA_VALUE_TYPE_DOUBLE);
+                edbus_message_iter_basic_get(iter, &d);
+                eina_value_set(v, d);
+                break;
+             }
+           case 'a'://array
+             {
+                EDBus_Message_Iter *dbus_array;
+                dbus_array = edbus_message_iter_sub_iter_get(iter);
+                v = _message_iter_array_to_eina_value(dbus_array);
+                break;
+             }
+           case '('://struct
+           case 'r'://struct
+           case 'v'://variant
+             {
+                EDBus_Message_Iter *dbus_st;
+                dbus_st = edbus_message_iter_sub_iter_get(iter);
+                v = _message_iter_struct_to_eina_value(dbus_st);
+                break;
+             }
+           default:
+             ERR("Unexpected type %c", type);
+             v = NULL;
+          }
+        eina_array_push(st_values, v);
+        edbus_message_iter_next(iter);
+        z++;
+     }
+
+   members = malloc(eina_array_count(st_members) * sizeof(Eina_Value_Struct_Member));
+   for (z = 0; z < eina_array_count(st_members); z++)
+     {
+        Eina_Value_Struct_Member *m = eina_array_data_get(st_members, z);
+        members[z].name = m->name;
+        members[z].offset = m->offset;
+        members[z].type = m->type;
+        free(m);
+     }
+
+   //setup
+   st_desc->base.members = members;
+   st_desc->base.member_count = eina_array_count(st_members);
+   st_desc->base.size = offset;
+   value_st = eina_value_struct_new((Eina_Value_Struct_Desc *)st_desc);
+   eina_array_free(st_members);
+
+   //filling with data
+   for (z = 0; z < eina_array_count(st_values); z++)
+     {
+        Eina_Value *v = eina_array_data_get(st_values, z);
+        sprintf(name, ARG, z);
+        eina_value_struct_value_set(value_st, name, v);
+        eina_value_free(v);
+     }
+   eina_array_free(st_values);
+   DBG("end struct");
+   return value_st;
+}
+
+EAPI Eina_Value *
+edbus_message_to_eina_value(const EDBus_Message *msg)
+{
+   EDBus_Message_Iter *iter;
+   EINA_SAFETY_ON_FALSE_RETURN_VAL(msg, NULL);
+   iter = edbus_message_iter_get(msg);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(iter, NULL);
+   return _message_iter_struct_to_eina_value(iter);
+}
diff --git a/src/lib/edbus_object.c b/src/lib/edbus_object.c
new file mode 100644 (file)
index 0000000..6bb1510
--- /dev/null
@@ -0,0 +1,470 @@
+#include "edbus_private.h"
+#include "edbus_private_types.h"
+#include <dbus/dbus.h>
+
+/* TODO: mempool of EDBus_Object, Edbus_Object_Context_Event_Cb and
+ * EDBus_Object_Context_Event
+ */
+
+#define EDBUS_OBJECT_CHECK(obj)                        \
+  do                                                   \
+    {                                                  \
+       EINA_SAFETY_ON_NULL_RETURN(obj);                \
+       if (!EINA_MAGIC_CHECK(obj, EDBUS_OBJECT_MAGIC)) \
+         {                                             \
+            EINA_MAGIC_FAIL(obj, EDBUS_OBJECT_MAGIC);  \
+            return;                                    \
+         }                                             \
+       EINA_SAFETY_ON_TRUE_RETURN(obj->refcount <= 0); \
+    }                                                  \
+  while (0)
+
+#define EDBUS_OBJECT_CHECK_RETVAL(obj, retval)                     \
+  do                                                               \
+    {                                                              \
+       EINA_SAFETY_ON_NULL_RETURN_VAL(obj, retval);                \
+       if (!EINA_MAGIC_CHECK(obj, EDBUS_OBJECT_MAGIC))             \
+         {                                                         \
+            EINA_MAGIC_FAIL(obj, EDBUS_OBJECT_MAGIC);              \
+            return retval;                                         \
+         }                                                         \
+       EINA_SAFETY_ON_TRUE_RETURN_VAL(obj->refcount <= 0, retval); \
+    }                                                              \
+  while (0)
+
+#define EDBUS_OBJECT_CHECK_GOTO(obj, label)                 \
+  do                                                        \
+    {                                                       \
+       EINA_SAFETY_ON_NULL_GOTO(obj, label);                \
+       if (!EINA_MAGIC_CHECK(obj, EDBUS_OBJECT_MAGIC))      \
+         {                                                  \
+            EINA_MAGIC_FAIL(obj, EDBUS_OBJECT_MAGIC);       \
+            goto label;                                     \
+         }                                                  \
+       EINA_SAFETY_ON_TRUE_GOTO(obj->refcount <= 0, label); \
+    }                                                       \
+  while (0)
+
+Eina_Bool
+edbus_object_init(void)
+{
+   return EINA_TRUE;
+}
+
+void
+edbus_object_shutdown(void)
+{
+}
+
+static void _edbus_object_event_callback_call(EDBus_Object *obj, EDBus_Object_Event_Type type, const void *event_info);
+static void _edbus_object_context_event_cb_del(EDBus_Object_Context_Event *ce, EDBus_Object_Context_Event_Cb *ctx);
+static void _on_connection_free(void *data, const void *dead_pointer);
+static void _on_signal_handler_free(void *data, const void *dead_pointer);
+
+static void
+_edbus_object_call_del(EDBus_Object *obj)
+{
+   EDBus_Object_Context_Event *ce;
+
+   _edbus_object_event_callback_call(obj, EDBUS_OBJECT_EVENT_DEL, NULL);
+
+   /* clear all del callbacks so we don't call them twice at
+    * _edbus_object_clear()
+    */
+   ce = obj->event_handlers + EDBUS_OBJECT_EVENT_DEL;
+   while (ce->list)
+     {
+        EDBus_Object_Context_Event_Cb *ctx;
+
+        ctx = EINA_INLIST_CONTAINER_GET(ce->list,
+                                        EDBus_Object_Context_Event_Cb);
+        _edbus_object_context_event_cb_del(ce, ctx);
+     }
+}
+
+static void
+_edbus_object_clear(EDBus_Object *obj)
+{
+   EDBus_Signal_Handler *h;
+   EDBus_Pending *p;
+   Eina_List *iter, *iter_next;
+   Eina_Inlist *in_l;
+   DBG("obj=%p, refcount=%d, name=%s, path=%s",
+       obj, obj->refcount, obj->name, obj->path);
+
+   obj->refcount = 1;
+   _edbus_object_call_del(obj);
+   edbus_connection_name_object_del(obj->conn, obj);
+
+   /* NOTE: obj->proxies is deleted from obj->cbs_free. */
+
+   EINA_LIST_FOREACH_SAFE(obj->signal_handlers, iter, iter_next, h)
+     {
+        DBG("obj=%p delete owned signal handler %p %s",
+            obj, h, edbus_signal_handler_match_get(h));
+        edbus_signal_handler_del(h);
+     }
+   EINA_INLIST_FOREACH_SAFE(obj->pendings, in_l, p)
+     {
+        DBG("obj=%p delete owned pending call=%p dest=%s path=%s %s.%s()",
+            obj, p,
+            edbus_pending_destination_get(p),
+            edbus_pending_path_get(p),
+            edbus_pending_interface_get(p),
+            edbus_pending_method_get(p));
+        edbus_pending_cancel(p);
+     }
+
+   edbus_cbs_free_dispatch(&(obj->cbs_free), obj);
+   obj->refcount = 0;
+}
+
+static void
+_edbus_object_free(EDBus_Object *obj)
+{
+   unsigned int i;
+   EDBus_Signal_Handler *h;
+
+   if (obj->proxies)
+     {
+        Eina_Iterator *iterator = eina_hash_iterator_data_new(obj->proxies);
+        EDBus_Proxy *proxy;
+        EINA_ITERATOR_FOREACH(iterator, proxy)
+          ERR("obj=%p alive proxy=%p %s", obj, proxy,
+              edbus_proxy_interface_get(proxy));
+        eina_iterator_free(iterator);
+        eina_hash_free(obj->proxies);
+     }
+
+   EINA_LIST_FREE(obj->signal_handlers, h)
+     {
+        if (h->dangling)
+          edbus_signal_handler_cb_free_del(h, _on_signal_handler_free, obj);
+        else
+          ERR("obj=%p alive handler=%p %s", obj, h,
+              edbus_signal_handler_match_get(h));
+     }
+
+   if (obj->pendings)
+     CRITICAL("Object %p released with live pending calls!", obj);
+
+   for (i = 0; i < EDBUS_OBJECT_EVENT_LAST; i++)
+     {
+        EDBus_Object_Context_Event *ce = obj->event_handlers + i;
+        while (ce->list)
+          {
+             EDBus_Object_Context_Event_Cb *ctx;
+
+             ctx = EINA_INLIST_CONTAINER_GET(ce->list,
+                                             EDBus_Object_Context_Event_Cb);
+             _edbus_object_context_event_cb_del(ce, ctx);
+          }
+        eina_list_free(ce->to_delete);
+     }
+
+   eina_stringshare_del(obj->name);
+   eina_stringshare_del(obj->path);
+   EINA_MAGIC_SET(obj, EINA_MAGIC_NONE);
+
+   free(obj);
+}
+
+static void
+_on_connection_free(void *data, const void *dead_pointer)
+{
+   EDBus_Object *obj = data;
+   EDBUS_OBJECT_CHECK(obj);
+   _edbus_object_clear(obj);
+   _edbus_object_free(obj);
+}
+
+EAPI EDBus_Object *
+edbus_object_get(EDBus_Connection *conn, const char *bus, const char *path)
+{
+   EDBus_Object *obj;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(conn, NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(bus, NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(path, NULL);
+
+   obj = edbus_connection_name_object_get(conn, bus, path);
+   if (obj) return obj;
+
+   obj = calloc(1, sizeof(EDBus_Object));
+   EINA_SAFETY_ON_NULL_RETURN_VAL(obj, NULL);
+
+   obj->conn = conn;
+   obj->refcount = 1;
+   obj->path = eina_stringshare_add(path);
+   obj->name = eina_stringshare_add(bus);
+   obj->proxies = eina_hash_string_small_new(NULL);
+   EINA_SAFETY_ON_NULL_GOTO(obj->proxies, cleanup);
+   EINA_MAGIC_SET(obj, EDBUS_OBJECT_MAGIC);
+
+   edbus_connection_name_object_set(conn, obj);
+   edbus_connection_cb_free_add(obj->conn, _on_connection_free, obj);
+
+   return obj;
+
+cleanup:
+   eina_stringshare_del(obj->path);
+   eina_stringshare_del(obj->name);
+   free(obj);
+
+   return NULL;
+}
+
+static void _on_signal_handler_free(void *data, const void *dead_pointer);
+
+static void
+_edbus_object_unref(EDBus_Object *obj)
+{
+   obj->refcount--;
+   if (obj->refcount > 0) return;
+
+   edbus_connection_cb_free_del(obj->conn, _on_connection_free, obj);
+   _edbus_object_clear(obj);
+   _edbus_object_free(obj);
+}
+
+EAPI EDBus_Object *
+edbus_object_ref(EDBus_Object *obj)
+{
+   EDBUS_OBJECT_CHECK_RETVAL(obj, NULL);
+   DBG("obj=%p, pre-refcount=%d, name=%s, path=%s",
+       obj, obj->refcount, obj->name, obj->path);
+   obj->refcount++;
+   return obj;
+}
+
+EAPI void
+edbus_object_unref(EDBus_Object *obj)
+{
+   EDBUS_OBJECT_CHECK(obj);
+   DBG("obj=%p, pre-refcount=%d, name=%s, path=%s",
+       obj, obj->refcount, obj->name, obj->path);
+   _edbus_object_unref(obj);
+}
+
+EAPI void
+edbus_object_cb_free_add(EDBus_Object *obj, EDBus_Free_Cb cb, const void *data)
+{
+   EDBUS_OBJECT_CHECK(obj);
+   EINA_SAFETY_ON_NULL_RETURN(cb);
+   obj->cbs_free = edbus_cbs_free_add(obj->cbs_free, cb, data);
+}
+
+EAPI void
+edbus_object_cb_free_del(EDBus_Object *obj, EDBus_Free_Cb cb, const void *data)
+{
+   EDBUS_OBJECT_CHECK(obj);
+   EINA_SAFETY_ON_NULL_RETURN(cb);
+   obj->cbs_free = edbus_cbs_free_del(obj->cbs_free, cb, data);
+}
+
+EAPI void
+edbus_object_event_callback_add(EDBus_Object *obj, EDBus_Object_Event_Type type, EDBus_Object_Event_Cb cb, const void *cb_data)
+{
+   EDBus_Object_Context_Event *ce;
+   EDBus_Object_Context_Event_Cb *ctx;
+
+   EDBUS_OBJECT_CHECK(obj);
+   EINA_SAFETY_ON_NULL_RETURN(cb);
+   EINA_SAFETY_ON_TRUE_RETURN(type >= EDBUS_OBJECT_EVENT_LAST);
+
+   ce = obj->event_handlers + type;
+
+   ctx = calloc(1, sizeof(EDBus_Object_Context_Event_Cb));
+   EINA_SAFETY_ON_NULL_RETURN(ctx);
+
+   ctx->cb = cb;
+   ctx->cb_data = cb_data;
+
+   ce->list = eina_inlist_append(ce->list, EINA_INLIST_GET(ctx));
+}
+
+static void
+_edbus_object_context_event_cb_del(EDBus_Object_Context_Event *ce, EDBus_Object_Context_Event_Cb *ctx)
+{
+   ce->list = eina_inlist_remove(ce->list, EINA_INLIST_GET(ctx));
+   free(ctx);
+}
+
+EAPI void
+edbus_object_event_callback_del(EDBus_Object *obj, EDBus_Object_Event_Type type, EDBus_Object_Event_Cb cb, const void *cb_data)
+{
+   EDBus_Object_Context_Event *ce;
+   EDBus_Object_Context_Event_Cb *iter, *found = NULL;
+
+   EDBUS_OBJECT_CHECK(obj);
+   EINA_SAFETY_ON_NULL_RETURN(cb);
+   EINA_SAFETY_ON_TRUE_RETURN(type >= EDBUS_OBJECT_EVENT_LAST);
+
+   ce = obj->event_handlers + type;
+
+   EINA_INLIST_FOREACH(ce->list, iter)
+     {
+        if (cb != iter->cb) continue;
+        if ((cb_data) && (cb_data != iter->cb_data)) continue;
+
+        found = iter;
+        break;
+     }
+
+   EINA_SAFETY_ON_NULL_RETURN(found);
+   EINA_SAFETY_ON_TRUE_RETURN(found->deleted);
+
+   if (ce->walking)
+     {
+        found->deleted = EINA_TRUE;
+        ce->to_delete = eina_list_append(ce->to_delete, found);
+        return;
+     }
+
+   _edbus_object_context_event_cb_del(ce, found);
+}
+
+static void
+_edbus_object_event_callback_call(EDBus_Object *obj, EDBus_Object_Event_Type type, const void *event_info)
+{
+   EDBus_Object_Context_Event *ce;
+   EDBus_Object_Context_Event_Cb *iter;
+
+   ce = obj->event_handlers + type;
+
+   ce->walking++;
+   EINA_INLIST_FOREACH(ce->list, iter)
+     {
+        if (iter->deleted) continue;
+        iter->cb((void *)iter->cb_data, obj, (void *)event_info);
+     }
+   ce->walking--;
+   if (ce->walking > 0) return;
+
+   EINA_LIST_FREE(ce->to_delete, iter)
+     _edbus_object_context_event_cb_del(ce, iter);
+}
+
+EAPI EDBus_Connection *
+edbus_object_connection_get(const EDBus_Object *obj)
+{
+   EDBUS_OBJECT_CHECK_RETVAL(obj, NULL);
+   return obj->conn;
+}
+
+EAPI const char *
+edbus_object_bus_name_get(const EDBus_Object *obj)
+{
+   EDBUS_OBJECT_CHECK_RETVAL(obj, NULL);
+   return obj->name;
+}
+
+EAPI const char *
+edbus_object_bus_path_get(const EDBus_Object *obj)
+{
+   EDBUS_OBJECT_CHECK_RETVAL(obj, NULL);
+   return obj->path;
+}
+
+static void
+_on_pending_free(void *data, const void *dead_pointer)
+{
+   EDBus_Object *obj = data;
+   EDBus_Pending *pending = (EDBus_Pending*) dead_pointer;
+   EDBUS_OBJECT_CHECK(obj);
+   obj->pendings = eina_inlist_remove(obj->pendings, EINA_INLIST_GET(pending));
+}
+
+EAPI EDBus_Pending *
+edbus_object_send(EDBus_Object *obj, EDBus_Message *msg, EDBus_Message_Cb cb, const void *cb_data, double timeout)
+{
+   EDBus_Pending *pending;
+
+   EDBUS_OBJECT_CHECK_RETVAL(obj, NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(msg, NULL);
+
+   pending = _edbus_connection_send(obj->conn, msg, cb, cb_data, timeout);
+   if (!cb) return NULL;
+   EINA_SAFETY_ON_NULL_RETURN_VAL(pending, NULL);
+
+   edbus_pending_cb_free_add(pending, _on_pending_free, obj);
+   obj->pendings = eina_inlist_append(obj->pendings, EINA_INLIST_GET(pending));
+
+   return pending;
+}
+
+static void
+_on_signal_handler_free(void *data, const void *dead_pointer)
+{
+   EDBus_Object *obj = data;
+   EDBUS_OBJECT_CHECK(obj);
+   obj->signal_handlers = eina_list_remove(obj->signal_handlers, dead_pointer);
+}
+
+EAPI EDBus_Signal_Handler *
+edbus_object_signal_handler_add(EDBus_Object *obj, const char *interface, const char *member, EDBus_Signal_Cb cb, const void *cb_data)
+{
+   EDBus_Signal_Handler *handler;
+
+   EDBUS_OBJECT_CHECK_RETVAL(obj, NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(cb, NULL);
+
+   handler = edbus_signal_handler_add(obj->conn, obj->name, obj->path,
+                                      interface, member, cb, cb_data);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(handler, NULL);
+
+   edbus_signal_handler_cb_free_add(handler, _on_signal_handler_free, obj);
+   obj->signal_handlers = eina_list_append(obj->signal_handlers, handler);
+
+   return handler;
+}
+
+Eina_Bool
+edbus_object_proxy_add(EDBus_Object *obj, EDBus_Proxy *proxy)
+{
+   return eina_hash_add(obj->proxies, edbus_proxy_interface_get(proxy), proxy);
+}
+
+EDBus_Proxy *
+edbus_object_proxy_get(EDBus_Object *obj, const char *interface)
+{
+   return eina_hash_find(obj->proxies, interface);
+}
+
+Eina_Bool
+edbus_object_proxy_del(EDBus_Object *obj, EDBus_Proxy *proxy, const char *interface)
+{
+   return eina_hash_del(obj->proxies, interface, proxy);
+}
+
+static EDBus_Proxy *
+get_peer_proxy(EDBus_Object *obj)
+{
+   return edbus_proxy_get(obj, "org.freedesktop.DBus.Peer");
+}
+
+EAPI EDBus_Pending *
+edbus_object_peer_ping(EDBus_Object *obj, EDBus_Message_Cb cb, const void *data)
+{
+   EDBUS_OBJECT_CHECK_RETVAL(obj, NULL);
+   return edbus_proxy_call(get_peer_proxy(obj), "Ping", cb,
+                           data, -1, "");
+}
+
+EAPI EDBus_Pending *
+edbus_object_peer_machine_id_get(EDBus_Object *obj, EDBus_Message_Cb cb, const void *data)
+{
+   EDBUS_OBJECT_CHECK_RETVAL(obj, NULL);
+   return edbus_proxy_call(get_peer_proxy(obj), "GetMachineId", cb,
+                           data, -1, "");
+}
+
+EAPI EDBus_Pending *
+edbus_object_introspect(EDBus_Object *obj, EDBus_Message_Cb cb, const void *data)
+{
+   EDBus_Proxy *introspectable;
+   EDBUS_OBJECT_CHECK_RETVAL(obj, NULL);
+
+   introspectable = edbus_proxy_get(obj, "org.freedesktop.DBus.Introspectable");
+   return edbus_proxy_call(introspectable, "Introspect", cb, data, -1, "");
+}
diff --git a/src/lib/edbus_object.h b/src/lib/edbus_object.h
new file mode 100644 (file)
index 0000000..de1f345
--- /dev/null
@@ -0,0 +1,117 @@
+#ifndef EDBUS_OBJECT_H
+#define EDBUS_OBJECT_H 1
+
+/**
+ * @defgroup EDBus_Object_Mapper Object Mapper
+ *
+ * @{
+ */
+/**
+ * @brief Get an object of the given bus and path.
+ *
+ * @param conn connection where object belongs
+ * @param bus name of bus or unique-id of who listens for calls of this object
+ * @param path object path of this object
+ */
+EAPI EDBus_Object *edbus_object_get(EDBus_Connection *conn, const char *bus, const char *path) EINA_ARG_NONNULL(1, 2, 3) EINA_WARN_UNUSED_RESULT;
+/**
+ * @brief Increase object reference.
+ */
+EAPI EDBus_Object *edbus_object_ref(EDBus_Object *obj) EINA_ARG_NONNULL(1);
+/**
+ * @brief Decrease object reference.
+ * If reference == 0 object will be freed and all its children.
+ */
+EAPI void          edbus_object_unref(EDBus_Object *obj) EINA_ARG_NONNULL(1);
+
+/**
+ * @brief Add a callback function to be called when object will be freed.
+ *
+ * @param obj object that you want to monitor
+ * @param cb callback that will be executed
+ * @param data passed to callback
+ */
+EAPI void          edbus_object_cb_free_add(EDBus_Object *obj, EDBus_Free_Cb cb, const void *data) EINA_ARG_NONNULL(1, 2);
+/**
+ * @brief Remove callback registered in edbus_object_cb_free_add().
+ */
+EAPI void          edbus_object_cb_free_del(EDBus_Object *obj, EDBus_Free_Cb cb, const void *data) EINA_ARG_NONNULL(1, 2);
+
+typedef enum
+{
+   EDBUS_OBJECT_EVENT_IFACE_ADDED = 0,
+   EDBUS_OBJECT_EVENT_IFACE_REMOVED,
+   EDBUS_OBJECT_EVENT_PROPERTY_CHANGED,
+   EDBUS_OBJECT_EVENT_PROPERTY_REMOVED,
+   EDBUS_OBJECT_EVENT_DEL,
+   EDBUS_OBJECT_EVENT_LAST    /**< sentinel, not a real event type */
+} EDBus_Object_Event_Type;
+
+typedef struct _EDBus_Object_Event_Interface_Added
+{
+   const char  *interface;
+   EDBus_Proxy *proxy;
+} EDBus_Object_Event_Interface_Added;
+
+typedef struct _EDBus_Object_Event_Interface_Removed
+{
+   const char *interface;
+} EDBus_Object_Event_Interface_Removed;
+
+typedef struct _EDBus_Object_Event_Property_Changed
+{
+   const char       *interface;
+   EDBus_Proxy      *proxy;
+   const char       *name;
+   const Eina_Value *value;
+} EDBus_Object_Event_Property_Changed;
+
+typedef struct _EDBus_Object_Event_Property_Removed
+{
+   const char  *interface;
+   EDBus_Proxy *proxy;
+   const char  *name;
+} EDBus_Object_Event_Property_Removed;
+
+typedef void (*EDBus_Object_Event_Cb)(void *data, EDBus_Object *obj, void *event_info);
+
+/**
+ * @brief Add a callback function to be called when an event of the specified
+ * type occurs.
+ */
+EAPI void                  edbus_object_event_callback_add(EDBus_Object *obj, EDBus_Object_Event_Type type, EDBus_Object_Event_Cb cb, const void *cb_data) EINA_ARG_NONNULL(1, 3);
+/**
+ * @brief Remove callback registered in edbus_object_event_callback_add().
+ */
+EAPI void                  edbus_object_event_callback_del(EDBus_Object *obj, EDBus_Object_Event_Type type, EDBus_Object_Event_Cb cb, const void *cb_data) EINA_ARG_NONNULL(1, 3);
+
+EAPI EDBus_Connection     *edbus_object_connection_get(const EDBus_Object *obj) EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT;
+EAPI const char           *edbus_object_bus_name_get(const EDBus_Object *obj) EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT;
+EAPI const char           *edbus_object_bus_path_get(const EDBus_Object *obj) EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT;
+
+/**
+ * @brief Send a message.
+ *
+ * @param obj the msg will be sent in connection to this object
+ * @param msg message that will be sent
+ * @param cb if msg is a method call a callback should be passed
+ * to be executed when a response arrives
+ * @param cb_data data passed to callback
+ * @param timeout timeout in milliseconds, -1 to default internal value or
+ * EDBUS_TIMEOUT_INFINITE for no timeout
+ */
+EAPI EDBus_Pending        *edbus_object_send(EDBus_Object *obj, EDBus_Message *msg, EDBus_Message_Cb cb, const void *cb_data, double timeout) EINA_ARG_NONNULL(1, 2);
+/**
+ * @brief Add a signal handler.
+ *
+ * @param obj where the signal is emitted
+ * @param interface of the signal
+ * @param member name of the signal
+ * @param cb callback that will be called when this signal is received
+ * @param cb_data data that will be passed to callback
+ */
+EAPI EDBus_Signal_Handler *edbus_object_signal_handler_add(EDBus_Object *obj, const char *interface, const char *member, EDBus_Signal_Cb cb, const void *cb_data) EINA_ARG_NONNULL(1, 4);
+/**
+ * @}
+ */
+#endif
diff --git a/src/lib/edbus_pending.c b/src/lib/edbus_pending.c
new file mode 100644 (file)
index 0000000..6dba810
--- /dev/null
@@ -0,0 +1,260 @@
+#include "edbus_private.h"
+#include "edbus_private_types.h"
+#include <dbus/dbus.h>
+
+/* TODO: mempool of EDBus_Pending */
+#define EDBUS_PENDING_CHECK(pending)                        \
+  do                                                        \
+    {                                                       \
+       EINA_SAFETY_ON_NULL_RETURN(pending);                 \
+       if (!EINA_MAGIC_CHECK(pending, EDBUS_PENDING_MAGIC)) \
+         {                                                  \
+            EINA_MAGIC_FAIL(pending, EDBUS_PENDING_MAGIC);  \
+            return;                                         \
+         }                                                  \
+    }                                                       \
+  while (0)
+
+#define EDBUS_PENDING_CHECK_RETVAL(pending, retval)         \
+  do                                                        \
+    {                                                       \
+       EINA_SAFETY_ON_NULL_RETURN_VAL(pending, retval);     \
+       if (!EINA_MAGIC_CHECK(pending, EDBUS_PENDING_MAGIC)) \
+         {                                                  \
+            EINA_MAGIC_FAIL(pending, EDBUS_PENDING_MAGIC);  \
+            return retval;                                  \
+         }                                                  \
+    }                                                       \
+  while (0)
+
+static void edbus_pending_dispatch(EDBus_Pending *pending, EDBus_Message *msg);
+
+Eina_Bool
+edbus_pending_init(void)
+{
+   return EINA_TRUE;
+}
+
+void
+edbus_pending_shutdown(void)
+{
+}
+
+static void
+cb_pending(DBusPendingCall *dbus_pending, void *user_data)
+{
+   EDBus_Message *msg;
+   EDBus_Pending *pending = user_data;
+
+   if (!dbus_pending_call_get_completed(dbus_pending))
+     {
+        INF("timeout to pending %p", pending);
+        dbus_pending_call_cancel(dbus_pending);
+        msg = edbus_message_error_new(pending->msg_sent,
+                                      "org.enlightenment.DBus.Timeout",
+                                      "This call was not completed.");
+        edbus_pending_dispatch(pending, msg);
+        return;
+     }
+
+   msg = edbus_message_new(EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN(msg);
+   msg->dbus_msg = dbus_pending_call_steal_reply(dbus_pending);
+   if (!msg->dbus_msg)
+     {
+        EINA_SAFETY_ON_NULL_GOTO(pending->cb, cleanup);
+
+        msg->dbus_msg = dbus_message_new_error(NULL,
+                            "org.enlightenment.DBus.NoReply",
+                            "There was no reply to this method call.");
+        EINA_SAFETY_ON_NULL_GOTO(msg->dbus_msg, cleanup);
+     }
+
+   dbus_message_iter_init(msg->dbus_msg, &msg->iterator->dbus_iterator);
+   edbus_pending_dispatch(pending, msg);
+
+   return;
+
+cleanup:
+   edbus_message_unref(msg);
+}
+
+static void
+_on_pending_free(void *data, const void *dead_pointer)
+{
+   EDBus_Connection *conn = data;
+   edbus_connection_pending_del(conn, (void *)dead_pointer);
+}
+
+EAPI EDBus_Pending *
+edbus_connection_send(EDBus_Connection *conn, EDBus_Message *msg, EDBus_Message_Cb cb, const void *cb_data, double timeout)
+{
+   EDBus_Pending *pending;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(conn, NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(msg, NULL);
+
+   pending = _edbus_connection_send(conn, msg, cb, cb_data, timeout);
+   if (!cb) return NULL;
+   EINA_SAFETY_ON_NULL_RETURN_VAL(pending, NULL);
+
+   edbus_connection_pending_add(conn, pending);
+   edbus_pending_cb_free_add(pending, _on_pending_free, conn);
+   return pending;
+}
+
+EDBus_Pending *
+_edbus_connection_send(EDBus_Connection *conn, EDBus_Message *msg, EDBus_Message_Cb cb, const void *cb_data, double timeout)
+{
+   EDBus_Pending *pending;
+   EDBus_Message *error_msg;
+   DBG("conn=%p, msg=%p, cb=%p, cb_data=%p, timeout=%f",
+          conn, msg, cb, cb_data, timeout);
+
+   if (!cb)
+     {
+        dbus_connection_send(conn->dbus_conn, msg->dbus_msg, NULL);
+        return NULL;
+     }
+
+   pending = calloc(1, sizeof(EDBus_Pending));
+   EINA_SAFETY_ON_NULL_RETURN_VAL(pending, NULL);
+
+   pending->cb = cb;
+   pending->cb_data = cb_data;
+   pending->conn = conn;
+   pending->dest = eina_stringshare_add(dbus_message_get_member(msg->dbus_msg));
+   pending->interface = eina_stringshare_add(dbus_message_get_interface(msg->dbus_msg));
+   pending->method = eina_stringshare_add(dbus_message_get_member(msg->dbus_msg));
+   pending->path = eina_stringshare_add(dbus_message_get_path(msg->dbus_msg));
+   pending->msg_sent = edbus_message_ref(msg);
+   EINA_MAGIC_SET(pending, EDBUS_PENDING_MAGIC);
+
+   if (!dbus_connection_send_with_reply(conn->dbus_conn,
+                                        msg->dbus_msg,
+                                        &pending->dbus_pending, timeout))
+     {
+        error_msg = edbus_message_error_new(msg, "org.enlightenment.DBus.NoConnection",
+                                            "EDBus_Connection was closed.");
+        edbus_pending_dispatch(pending, error_msg);
+        return NULL;
+     }
+   if (dbus_pending_call_set_notify(pending->dbus_pending, cb_pending, pending, NULL))
+     return pending;
+
+   dbus_pending_call_cancel(pending->dbus_pending);
+   error_msg = edbus_message_error_new(pending->msg_sent,
+                                       "org.enlightenment.DBus.Error",
+                                       "Error when try set callback to message.");
+   edbus_pending_dispatch(pending, error_msg);
+   return NULL;
+}
+
+EAPI void
+edbus_pending_data_set(EDBus_Pending *pending, const char *key, const void *data)
+{
+   EDBUS_PENDING_CHECK(pending);
+   EINA_SAFETY_ON_NULL_RETURN(key);
+   EINA_SAFETY_ON_NULL_RETURN(data);
+   edbus_data_set(&(pending->data), key, data);
+}
+
+EAPI void *
+edbus_pending_data_get(const EDBus_Pending *pending, const char *key)
+{
+   EDBUS_PENDING_CHECK_RETVAL(pending, NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(key, NULL);
+   return edbus_data_get(&(((EDBus_Pending *)pending)->data), key);
+}
+
+EAPI void *
+edbus_pending_data_del(EDBus_Pending *pending, const char *key)
+{
+   EDBUS_PENDING_CHECK_RETVAL(pending, NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(key, NULL);
+   return edbus_data_del(&(((EDBus_Pending *)pending)->data), key);
+}
+
+static void
+edbus_pending_dispatch(EDBus_Pending *pending, EDBus_Message *msg)
+{
+   DBG("pending=%p msg=%p", pending, msg);
+   if (pending->cb)
+     pending->cb((void *)pending->cb_data, msg, pending);
+
+   edbus_cbs_free_dispatch(&(pending->cbs_free), pending);
+   edbus_data_del_all(&(pending->data));
+
+   if (msg) edbus_message_unref(msg);
+   edbus_message_unref(pending->msg_sent);
+   dbus_pending_call_unref(pending->dbus_pending);
+
+   pending->cb = NULL;
+   pending->dbus_pending = NULL;
+   eina_stringshare_del(pending->dest);
+   eina_stringshare_del(pending->path);
+   eina_stringshare_del(pending->interface);
+   eina_stringshare_del(pending->method);
+   EINA_MAGIC_SET(pending, EINA_MAGIC_NONE);
+   free(pending);
+}
+
+EAPI void
+edbus_pending_cancel(EDBus_Pending *pending)
+{
+   EDBus_Message *error_message;
+   EDBUS_PENDING_CHECK(pending);
+   EINA_SAFETY_ON_NULL_RETURN(pending->dbus_pending);
+
+   DBG("pending=%p", pending);
+   dbus_pending_call_cancel(pending->dbus_pending);
+
+   error_message = edbus_message_error_new(pending->msg_sent,
+                                           "org.enlightenment.DBus.Canceled",
+                                           "Canceled by user.");
+   edbus_pending_dispatch(pending, error_message);
+}
+
+EAPI void
+edbus_pending_cb_free_add(EDBus_Pending *pending, EDBus_Free_Cb cb, const void *data)
+{
+   EDBUS_PENDING_CHECK(pending);
+   EINA_SAFETY_ON_NULL_RETURN(cb);
+   pending->cbs_free = edbus_cbs_free_add(pending->cbs_free, cb, data);
+}
+
+EAPI void
+edbus_pending_cb_free_del(EDBus_Pending *pending, EDBus_Free_Cb cb, const void *data)
+{
+   EDBUS_PENDING_CHECK(pending);
+   EINA_SAFETY_ON_NULL_RETURN(cb);
+   pending->cbs_free = edbus_cbs_free_del(pending->cbs_free, cb, data);
+}
+
+EAPI const char *
+edbus_pending_destination_get(const EDBus_Pending *pending)
+{
+   EDBUS_PENDING_CHECK_RETVAL(pending, NULL);
+   return pending->dest;
+}
+
+EAPI const char *
+edbus_pending_path_get(const EDBus_Pending *pending)
+{
+   EDBUS_PENDING_CHECK_RETVAL(pending, NULL);
+   return pending->path;
+}
+
+EAPI const char *
+edbus_pending_interface_get(const EDBus_Pending *pending)
+{
+   EDBUS_PENDING_CHECK_RETVAL(pending, NULL);
+   return pending->interface;
+}
+
+EAPI const char *
+edbus_pending_method_get(const EDBus_Pending *pending)
+{
+   EDBUS_PENDING_CHECK_RETVAL(pending, NULL);
+   return pending->method;
+}
diff --git a/src/lib/edbus_pending.h b/src/lib/edbus_pending.h
new file mode 100644 (file)
index 0000000..d0071ff
--- /dev/null
@@ -0,0 +1,30 @@
+#ifndef EDBUS_PENDING_H
+#define EDBUS_PENDING_H 1
+
+/**
+ * @defgroup EDBus_Pending Pending
+ *
+ * @{
+ */
+EAPI void                  edbus_pending_data_set(EDBus_Pending *pending, const char *key, const void *data) EINA_ARG_NONNULL(1, 2, 3);
+EAPI void                 *edbus_pending_data_get(const EDBus_Pending *pending, const char *key) EINA_ARG_NONNULL(1, 2);
+EAPI void                 *edbus_pending_data_del(EDBus_Pending *pending, const char *key) EINA_ARG_NONNULL(1, 2);
+EAPI void                  edbus_pending_cancel(EDBus_Pending *pending) EINA_ARG_NONNULL(1);
+
+EAPI const char           *edbus_pending_destination_get(const EDBus_Pending *pending) EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT;
+EAPI const char           *edbus_pending_path_get(const EDBus_Pending *pending) EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT;
+EAPI const char           *edbus_pending_interface_get(const EDBus_Pending *pending) EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT;
+EAPI const char           *edbus_pending_method_get(const EDBus_Pending *pending) EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT;
+
+/**
+ * @brief Add a callback function to be called when pending will be freed.
+ */
+EAPI void                  edbus_pending_cb_free_add(EDBus_Pending *pending, EDBus_Free_Cb cb, const void *data) EINA_ARG_NONNULL(1, 2);
+/**
+ * @brief Remove callback registered in edbus_pending_cb_free_add().
+ */
+EAPI void                  edbus_pending_cb_free_del(EDBus_Pending *pending, EDBus_Free_Cb cb, const void *data) EINA_ARG_NONNULL(1, 2);
+/**
+ * @}
+ */
+#endif
diff --git a/src/lib/edbus_private.h b/src/lib/edbus_private.h
new file mode 100644 (file)
index 0000000..1e10bfa
--- /dev/null
@@ -0,0 +1,84 @@
+#ifndef EDBUS_PRIVATE_H
+#define EDBUS_PRIVATE_H
+
+#include <Eina.h>
+#include "eina_safety_checks.h"
+#include "EDBus.h"
+#include "edbus_private_types.h"
+
+extern int _edbus_log_dom;
+#define DBG(...)      EINA_LOG_DOM_DBG(_edbus_log_dom, __VA_ARGS__)
+#define INF(...)      EINA_LOG_DOM_INFO(_edbus_log_dom, __VA_ARGS__)
+#define WRN(...)      EINA_LOG_DOM_WARN(_edbus_log_dom, __VA_ARGS__)
+#define ERR(...)      EINA_LOG_DOM_ERR(_edbus_log_dom, __VA_ARGS__)
+#define CRITICAL(...) EINA_LOG_DOM_CRIT(_edbus_log_dom, __VA_ARGS__)
+
+#define EDBUS_CONNECTION_MAGIC        (0xdb050001)
+#define EDBUS_MESSAGE_MAGIC           (0xdb050002)
+#define EDBUS_SIGNAL_HANDLER_MAGIC    (0xdb050003)
+#define EDBUS_PENDING_MAGIC           (0xdb050004)
+#define EDBUS_OBJECT_MAGIC            (0xdb050005)
+#define EDBUS_PROXY_MAGIC             (0xdb050006)
+#define EDBUS_MESSAGE_ITERATOR_MAGIC  (0xdb050007)
+#define EDBUS_SERVICE_INTERFACE_MAGIC (0xdb050008)
+
+void                   edbus_cbs_free_dispatch(Eina_Inlist **p_lst, const void *dead_pointer);
+Eina_Inlist           *edbus_cbs_free_add(Eina_Inlist *lst, EDBus_Free_Cb cb, const void *data);
+Eina_Inlist           *edbus_cbs_free_del(Eina_Inlist *lst, EDBus_Free_Cb cb, const void *data);
+
+void                   edbus_data_set(Eina_Inlist **p_lst, const char *key, const void *data) EINA_ARG_NONNULL(1, 2, 3);
+void                  *edbus_data_get(Eina_Inlist **p_lst, const char *key) EINA_ARG_NONNULL(1, 2);
+void                  *edbus_data_del(Eina_Inlist **p_lst, const char *key) EINA_ARG_NONNULL(1, 2);
+void                   edbus_data_del_all(Eina_Inlist **p_list) EINA_ARG_NONNULL(1);
+
+Eina_Bool              edbus_message_init(void);
+void                   edbus_message_shutdown(void);
+EDBus_Message         *edbus_message_new(Eina_Bool writable);
+
+Eina_Bool              edbus_signal_handler_init(void);
+void                   edbus_signal_handler_shutdown(void);
+
+Eina_Bool              edbus_pending_init(void);
+void                   edbus_pending_shutdown(void);
+
+Eina_Bool              edbus_object_init(void);
+void                   edbus_object_shutdown(void);
+
+Eina_Bool              edbus_proxy_init(void);
+void                   edbus_proxy_shutdown(void);
+
+Eina_Bool              edbus_service_init(void);
+void                   edbus_service_shutdown(void);
+
+void                   edbus_connection_event_callback_call(EDBus_Connection *conn, EDBus_Connection_Event_Type type, const void *event_info) EINA_ARG_NONNULL(1);
+
+Eina_Bool              edbus_object_proxy_del(EDBus_Object *obj, EDBus_Proxy *proxy, const char *interface) EINA_ARG_NONNULL(1, 2);
+
+void                   edbus_connection_signal_handler_add(EDBus_Connection *conn, EDBus_Signal_Handler *handler) EINA_ARG_NONNULL(1, 2);
+void                   edbus_connection_pending_add(EDBus_Connection *conn, EDBus_Pending *pending) EINA_ARG_NONNULL(1, 2);
+void                   edbus_connection_signal_handler_del(EDBus_Connection *conn, EDBus_Signal_Handler *handler) EINA_ARG_NONNULL(1, 2);
+void                   edbus_connection_signal_handler_del(EDBus_Connection *conn, EDBus_Signal_Handler *handler) EINA_ARG_NONNULL(1, 2);
+void                   edbus_connection_pending_del(EDBus_Connection *conn, EDBus_Pending *pending) EINA_ARG_NONNULL(1, 2);
+
+EDBus_Object          *edbus_connection_name_object_get(EDBus_Connection *conn, const char *name, const char *path);
+void                   edbus_connection_name_object_set(EDBus_Connection *conn, EDBus_Object *obj);
+
+Eina_Bool              edbus_object_proxy_add(EDBus_Object *obj, EDBus_Proxy *proxy) EINA_ARG_NONNULL(1, 2);
+EDBus_Proxy           *edbus_object_proxy_get(EDBus_Object *obj, const char *interface);
+
+void                   edbus_connection_name_object_del(EDBus_Connection *conn, const EDBus_Object *obj);
+EDBus_Connection_Name *edbus_connection_name_get(EDBus_Connection *conn, const char *name);
+void                   edbus_connection_name_owner_monitor(EDBus_Connection *conn, EDBus_Connection_Name *cn, Eina_Bool enable);
+
+EDBus_Pending         *_edbus_connection_send(EDBus_Connection *conn, EDBus_Message *msg, EDBus_Message_Cb cb, const void *cb_data, double timeout);
+
+EDBus_Message_Iter    *edbus_message_iter_sub_iter_get(EDBus_Message_Iter *iter);
+Eina_Value            *_message_iter_struct_to_eina_value(EDBus_Message_Iter *iter);
+
+#ifdef HAVE_VA_LIST_AS_ARRAY
+#define MAKE_PTR_FROM_VA_LIST(arg) ((va_list *)(arg))
+#else
+#define MAKE_PTR_FROM_VA_LIST(arg) (&(arg))
+#endif
+
+#endif
diff --git a/src/lib/edbus_private_types.h b/src/lib/edbus_private_types.h
new file mode 100644 (file)
index 0000000..a6c818f
--- /dev/null
@@ -0,0 +1,162 @@
+#ifndef EDBUS_PRIVATE_TYPES_H
+#define EDBUS_PRIVATE_TYPES_H 1
+
+#include "EDBus.h"
+#include <Eina.h>
+#include <dbus/dbus.h>
+#include <Ecore.h>
+
+typedef struct _EDBus_Connection_Name
+{
+   const char *name;
+   const char *unique_id;
+   Eina_Hash  *objects;
+   int refcount;
+   struct
+   {
+      Eina_Inlist *list; //EDBus_Connection_Context_NOC_Cb
+      int          walking;
+      Eina_List   *to_delete;
+   } event_handlers;
+   EDBus_Signal_Handler *name_owner_changed;
+} EDBus_Connection_Name;
+
+typedef struct _EDBus_Object_Context_Event_Cb
+{
+   EINA_INLIST;
+   EDBus_Object_Event_Cb cb;
+   const void           *cb_data;
+   Eina_Bool             deleted : 1;
+} EDBus_Object_Context_Event_Cb;
+
+typedef struct _EDBus_Object_Context_Event
+{
+   Eina_Inlist *list;
+   int          walking;
+   Eina_List   *to_delete;
+} EDBus_Object_Context_Event;
+
+
+typedef struct _EDBus_Connection_Context_Event
+{
+   Eina_Inlist *list;
+   int          walking;
+   Eina_List   *to_delete;
+} EDBus_Connection_Context_Event;
+
+struct _EDBus_Connection
+{
+   EINA_MAGIC;
+   EINA_INLIST;
+   int                            refcount;
+   EDBus_Connection_Type          type;
+   DBusConnection                *dbus_conn;
+   Eina_Hash                     *names; //EDBus_Connection_Name
+   Eina_Inlist                   *data;
+   Eina_Inlist                   *cbs_free;
+   Eina_Inlist                   *signal_handlers;
+   Eina_Inlist                   *pendings;
+   Eina_Inlist                   *fd_handlers;
+   Eina_Inlist                   *timeouts;
+   Ecore_Idler                   *idler;
+   Eina_Bool                      running_signal;
+   EDBus_Connection_Context_Event event_handlers[EDBUS_CONNECTION_EVENT_LAST];
+};
+
+struct _EDBus_Object
+{
+   EINA_MAGIC;
+   EINA_INLIST;
+   int                        refcount;
+   EDBus_Connection          *conn;
+   const char                *name;
+   const char                *path;
+   Eina_Hash                 *proxies;
+   Eina_Inlist               *pendings;
+   Eina_List                 *signal_handlers;
+   Eina_Inlist               *cbs_free;
+   EDBus_Object_Context_Event event_handlers[EDBUS_OBJECT_EVENT_LAST];
+};
+
+struct _EDBus_Signal_Handler
+{
+   EINA_MAGIC;
+   EINA_INLIST;
+   int                       refcount;
+   const char               *sender;
+   const char               *path;
+   const char               *interface;
+   const char               *member;
+   Eina_Strbuf              *match;
+   Eina_Inlist              *args;
+   Eina_Inlist_Sorted_State *state_args;
+   EDBus_Connection         *conn;
+   EDBus_Signal_Cb           cb;
+   EDBus_Connection_Name    *bus;
+   const void               *cb_data;
+   Eina_Inlist              *cbs_free;
+   Eina_Bool                 dangling;
+};
+
+struct _EDBus_Pending
+{
+   EINA_MAGIC;
+   EINA_INLIST;
+   EDBus_Message_Cb  cb;
+   const void       *cb_data;
+   DBusPendingCall  *dbus_pending;
+   EDBus_Connection *conn;
+   const char       *dest;
+   const char       *path;
+   const char       *interface;
+   const char       *method;
+   Eina_Inlist      *data;
+   Eina_Inlist      *cbs_free;
+   EDBus_Message    *msg_sent;
+};
+
+struct _EDBus_Message_Iter
+{
+   EINA_MAGIC;
+   EINA_INLIST;
+   DBusMessageIter dbus_iterator;
+   Eina_Inlist *iterators;
+   Eina_Bool writable;
+};
+
+struct _EDBus_Message
+{
+   EINA_MAGIC;
+   int          refcount;
+   DBusMessage *dbus_msg;
+   EDBus_Message_Iter *iterator;
+};
+
+typedef struct _EDBus_Service_Object
+{
+   EDBus_Connection *conn;
+   const char *path;
+   Eina_Hash *interfaces;
+   Eina_Strbuf *introspection_data;
+   Eina_Bool introspection_dirty;
+   Eina_Inlist *data;
+} EDBus_Service_Object;
+
+struct _EDBus_Service_Interface
+{
+   EINA_MAGIC;
+   const char *name;
+   Eina_Hash *methods;
+   const EDBus_Signal *signals;
+   Eina_Array *sign_of_signals;
+   EDBus_Service_Object *obj;
+};
+
+typedef struct _Signal_Argument
+{
+   EINA_INLIST;
+   unsigned short index;
+   const char *value;
+} Signal_Argument;
+
+#endif
diff --git a/src/lib/edbus_proxy.c b/src/lib/edbus_proxy.c
new file mode 100644 (file)
index 0000000..2586b99
--- /dev/null
@@ -0,0 +1,781 @@
+#include "edbus_private.h"
+#include "edbus_private_types.h"
+
+/* TODO: mempool of EDBus_Proxy, Edbus_Proxy_Context_Event_Cb and
+ * EDBus_Proxy_Context_Event
+ */
+
+typedef struct _EDBus_Proxy_Context_Event_Cb
+{
+   EINA_INLIST;
+   EDBus_Proxy_Event_Cb cb;
+   const void          *cb_data;
+   Eina_Bool            deleted : 1;
+} EDBus_Proxy_Context_Event_Cb;
+
+typedef struct _EDBus_Proxy_Context_Event
+{
+   Eina_Inlist *list;
+   int          walking;
+   Eina_List   *to_delete;
+} EDBus_Proxy_Context_Event;
+
+struct _EDBus_Proxy
+{
+   EINA_MAGIC;
+   int                       refcount;
+   EDBus_Object             *obj;
+   const char               *interface;
+   Eina_Inlist              *pendings;
+   Eina_List                *handlers;
+   Eina_Inlist              *cbs_free;
+   EDBus_Proxy_Context_Event event_handlers[EDBUS_PROXY_EVENT_LAST];
+   Eina_Hash *props;
+   EDBus_Signal_Handler *properties_changed;
+   Eina_Bool monitor_enabled:1;
+};
+
+#define EDBUS_PROXY_CHECK(proxy)                         \
+  do                                                     \
+    {                                                    \
+       EINA_SAFETY_ON_NULL_RETURN(proxy);                \
+       if (!EINA_MAGIC_CHECK(proxy, EDBUS_PROXY_MAGIC))  \
+         {                                               \
+            EINA_MAGIC_FAIL(proxy, EDBUS_PROXY_MAGIC);   \
+            return;                                      \
+         }                                               \
+       EINA_SAFETY_ON_TRUE_RETURN(proxy->refcount <= 0); \
+    }                                                    \
+  while (0)
+
+#define EDBUS_PROXY_CHECK_RETVAL(proxy, retval)                      \
+  do                                                                 \
+    {                                                                \
+       EINA_SAFETY_ON_NULL_RETURN_VAL(proxy, retval);                \
+       if (!EINA_MAGIC_CHECK(proxy, EDBUS_PROXY_MAGIC))              \
+         {                                                           \
+            EINA_MAGIC_FAIL(proxy, EDBUS_PROXY_MAGIC);               \
+            return retval;                                           \
+         }                                                           \
+       EINA_SAFETY_ON_TRUE_RETURN_VAL(proxy->refcount <= 0, retval); \
+    }                                                                \
+  while (0)
+
+#define EDBUS_PROXY_CHECK_GOTO(proxy, label)                  \
+  do                                                          \
+    {                                                         \
+       EINA_SAFETY_ON_NULL_GOTO(proxy, label);                \
+       if (!EINA_MAGIC_CHECK(proxy, EDBUS_PROXY_MAGIC))       \
+         {                                                    \
+            EINA_MAGIC_FAIL(proxy, EDBUS_PROXY_MAGIC);        \
+            goto label;                                       \
+         }                                                    \
+       EINA_SAFETY_ON_TRUE_GOTO(proxy->refcount <= 0, label); \
+    }                                                         \
+  while (0)
+
+Eina_Bool
+edbus_proxy_init(void)
+{
+   return EINA_TRUE;
+}
+
+void
+edbus_proxy_shutdown(void)
+{
+}
+
+static void _edbus_proxy_event_callback_call(EDBus_Proxy *proxy, EDBus_Proxy_Event_Type type, const void *event_info);
+static void _edbus_proxy_context_event_cb_del(EDBus_Proxy_Context_Event *ce, EDBus_Proxy_Context_Event_Cb *ctx);
+static void _on_signal_handler_free(void *data, const void *dead_pointer);
+static EDBus_Proxy *get_properties_proxy(EDBus_Proxy *proxy);
+
+static void
+_edbus_proxy_call_del(EDBus_Proxy *proxy)
+{
+   EDBus_Proxy_Context_Event *ce;
+
+   _edbus_proxy_event_callback_call(proxy, EDBUS_PROXY_EVENT_DEL, NULL);
+
+   /* clear all del callbacks so we don't call them twice at
+    * _edbus_proxy_clear()
+    */
+   ce = proxy->event_handlers + EDBUS_PROXY_EVENT_DEL;
+   while (ce->list)
+     {
+        EDBus_Proxy_Context_Event_Cb *ctx;
+
+        ctx = EINA_INLIST_CONTAINER_GET(ce->list,
+                                        EDBus_Proxy_Context_Event_Cb);
+        _edbus_proxy_context_event_cb_del(ce, ctx);
+     }
+}
+
+static void
+_edbus_proxy_clear(EDBus_Proxy *proxy)
+{
+   EDBus_Signal_Handler *h;
+   EDBus_Pending *p;
+   Eina_List *iter, *iter_next;
+   Eina_Inlist *in_l;
+   DBG("proxy=%p, refcount=%d, interface=%s, obj=%p",
+       proxy, proxy->refcount, proxy->interface, proxy->obj);
+   proxy->refcount = 1;
+   edbus_object_proxy_del(proxy->obj, proxy, proxy->interface);
+   _edbus_proxy_call_del(proxy);
+
+   EINA_LIST_FOREACH_SAFE(proxy->handlers, iter, iter_next, h)
+     {
+        DBG("proxy=%p delete owned signal handler %p %s",
+            proxy, h, edbus_signal_handler_match_get(h));
+        edbus_signal_handler_del(h);
+     }
+
+   EINA_INLIST_FOREACH_SAFE(proxy->pendings, in_l, p)
+     {
+        DBG("proxy=%p delete owned pending call=%p dest=%s path=%s %s.%s()",
+            proxy, p,
+            edbus_pending_destination_get(p),
+            edbus_pending_path_get(p),
+            edbus_pending_interface_get(p),
+            edbus_pending_method_get(p));
+        edbus_pending_cancel(p);
+     }
+
+   edbus_cbs_free_dispatch(&(proxy->cbs_free), proxy);
+   if (proxy->props)
+     eina_hash_free(proxy->props);
+   if (proxy->properties_changed)
+     edbus_signal_handler_del(proxy->properties_changed);
+   proxy->refcount = 0;
+}
+
+static void
+_edbus_proxy_free(EDBus_Proxy *proxy)
+{
+   unsigned int i;
+   EDBus_Signal_Handler *h;
+
+   EINA_LIST_FREE(proxy->handlers, h)
+     {
+        if (h->dangling)
+         edbus_signal_handler_cb_free_del(h, _on_signal_handler_free, proxy);
+        else
+           ERR("proxy=%p alive handler=%p %s", proxy, h,
+               edbus_signal_handler_match_get(h));
+     }
+
+   if (proxy->pendings)
+     CRITICAL("Proxy %p released with live pending calls!", proxy);
+
+   for (i = 0; i < EDBUS_PROXY_EVENT_LAST; i++)
+     {
+        EDBus_Proxy_Context_Event *ce = proxy->event_handlers + i;
+        while (ce->list)
+          {
+             EDBus_Proxy_Context_Event_Cb *ctx;
+             ctx = EINA_INLIST_CONTAINER_GET(ce->list,
+                                             EDBus_Proxy_Context_Event_Cb);
+             _edbus_proxy_context_event_cb_del(ce, ctx);
+          }
+        eina_list_free(ce->to_delete);
+     }
+
+   eina_stringshare_del(proxy->interface);
+   EINA_MAGIC_SET(proxy, EINA_MAGIC_NONE);
+   free(proxy);
+}
+
+static void
+_on_object_free(void *data, const void *dead_pointer)
+{
+   EDBus_Proxy *proxy = data;
+   EDBUS_PROXY_CHECK(proxy);
+   DBG("proxy=%p, refcount=%d, interface=%s, obj=%p",
+       proxy, proxy->refcount, proxy->interface, proxy->obj);
+   _edbus_proxy_clear(proxy);
+   _edbus_proxy_free(proxy);
+}
+
+EAPI EDBus_Proxy *
+edbus_proxy_get(EDBus_Object *obj, const char *interface)
+{
+   EDBus_Proxy *proxy;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(obj, NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(interface, NULL);
+
+   proxy = edbus_object_proxy_get(obj, interface);
+   if (proxy) return proxy;
+
+   proxy = calloc(1, sizeof(EDBus_Proxy));
+   EINA_SAFETY_ON_NULL_RETURN_VAL(proxy, NULL);
+
+   proxy->refcount = 1;
+   proxy->obj = obj;
+   proxy->interface = eina_stringshare_add(interface);
+   EINA_MAGIC_SET(proxy, EDBUS_PROXY_MAGIC);
+   if (!edbus_object_proxy_add(obj, proxy))
+     goto cleanup;
+   edbus_object_cb_free_add(obj, _on_object_free, proxy);
+
+   return proxy;
+
+cleanup:
+   eina_stringshare_del(proxy->interface);
+   free(proxy);
+   return NULL;
+}
+
+static void _on_signal_handler_free(void *data, const void *dead_pointer);
+
+static void
+_edbus_proxy_unref(EDBus_Proxy *proxy)
+{
+   proxy->refcount--;
+   if (proxy->refcount > 0) return;
+
+   edbus_object_cb_free_del(proxy->obj, _on_object_free, proxy);
+   _edbus_proxy_clear(proxy);
+   _edbus_proxy_free(proxy);
+}
+
+EAPI EDBus_Proxy *
+edbus_proxy_ref(EDBus_Proxy *proxy)
+{
+   EDBUS_PROXY_CHECK_RETVAL(proxy, NULL);
+   DBG("proxy=%p, pre-refcount=%d, interface=%s, obj=%p",
+       proxy, proxy->refcount, proxy->interface, proxy->obj);
+   proxy->refcount++;
+   return proxy;
+}
+
+EAPI void
+edbus_proxy_unref(EDBus_Proxy *proxy)
+{
+   EDBUS_PROXY_CHECK(proxy);
+   DBG("proxy=%p, pre-refcount=%d, interface=%s, obj=%p",
+       proxy, proxy->refcount, proxy->interface, proxy->obj);
+   _edbus_proxy_unref(proxy);
+}
+
+EAPI void
+edbus_proxy_cb_free_add(EDBus_Proxy *proxy, EDBus_Free_Cb cb, const void *data)
+{
+   EDBUS_PROXY_CHECK(proxy);
+   EINA_SAFETY_ON_NULL_RETURN(cb);
+   proxy->cbs_free = edbus_cbs_free_add(proxy->cbs_free, cb, data);
+}
+
+EAPI void
+edbus_proxy_cb_free_del(EDBus_Proxy *proxy, EDBus_Free_Cb cb, const void *data)
+{
+   EDBUS_PROXY_CHECK(proxy);
+   EINA_SAFETY_ON_NULL_RETURN(cb);
+   proxy->cbs_free = edbus_cbs_free_del(proxy->cbs_free, cb, data);
+}
+
+static void
+_property_changed_iter(void *data, const void *key, EDBus_Message_Iter *var)
+{
+   EDBus_Proxy *proxy = data;
+   const char *skey = key;
+   Eina_Value *st_value, stack_value, *value;
+   EDBus_Proxy_Event_Property_Changed event;
+
+   st_value = _message_iter_struct_to_eina_value(var);
+   eina_value_struct_value_get(st_value, "arg0", &stack_value);
+
+   value = eina_hash_find(proxy->props, skey);
+   if (value)
+     {
+        eina_value_flush(value);
+        eina_value_copy(&stack_value, value);
+     }
+   else
+     {
+        value = calloc(1, sizeof(Eina_Value));
+        eina_value_copy(&stack_value, value);
+        eina_hash_add(proxy->props, skey, value);
+     }
+
+   event.name = skey;
+   event.value = value;
+   _edbus_proxy_event_callback_call(proxy, EDBUS_PROXY_EVENT_PROPERTY_CHANGED,
+                                    &event);
+   eina_value_free(st_value);
+   eina_value_flush(&stack_value);
+}
+
+static void
+_properties_changed(void *data, const EDBus_Message *msg)
+{
+   EDBus_Proxy *proxy = data;
+   EDBus_Message_Iter *array, *invalidate;
+   const char *iface;
+   const char *invalidate_prop;
+
+   if (!edbus_message_arguments_get(msg, "sa{sv}as", &iface, &array, &invalidate))
+     {
+        ERR("Error getting data from properties changed signal.");
+        return;
+     }
+   if (proxy->props)
+     edbus_message_iter_dict_iterate(array, "sv", _property_changed_iter,
+                                     proxy);
+
+   while (edbus_message_iter_get_and_next(invalidate, 's', &invalidate_prop))
+     {
+        EDBus_Proxy_Event_Property_Removed event;
+        event.interface = proxy->interface;
+        event.name = invalidate_prop;
+        event.proxy = proxy;
+        if (proxy->props)
+          eina_hash_del(proxy->props, event.name, NULL);
+        _edbus_proxy_event_callback_call(proxy, EDBUS_PROXY_EVENT_PROPERTY_REMOVED,
+                                         &event);
+     }
+}
+
+static void
+_props_cache_free(void *data)
+{
+   Eina_Value *value = data;
+   eina_value_free(value);
+}
+
+EAPI void
+edbus_proxy_event_callback_add(EDBus_Proxy *proxy, EDBus_Proxy_Event_Type type, EDBus_Proxy_Event_Cb cb, const void *cb_data)
+{
+   EDBus_Proxy_Context_Event *ce;
+   EDBus_Proxy_Context_Event_Cb *ctx;
+
+   EDBUS_PROXY_CHECK(proxy);
+   EINA_SAFETY_ON_NULL_RETURN(cb);
+   EINA_SAFETY_ON_TRUE_RETURN(type >= EDBUS_PROXY_EVENT_LAST);
+
+   ce = proxy->event_handlers + type;
+
+   ctx = calloc(1, sizeof(EDBus_Proxy_Context_Event_Cb));
+   EINA_SAFETY_ON_NULL_RETURN(ctx);
+   ctx->cb = cb;
+   ctx->cb_data = cb_data;
+
+   ce->list = eina_inlist_append(ce->list, EINA_INLIST_GET(ctx));
+
+   if (type == EDBUS_PROXY_EVENT_PROPERTY_CHANGED)
+     {
+        if (proxy->properties_changed) return;
+        if (!proxy->props)
+          proxy->props = eina_hash_string_superfast_new(_props_cache_free);
+        proxy->properties_changed =
+                 edbus_proxy_properties_changed_callback_add(proxy,
+                                                             _properties_changed,
+                                                             proxy);
+     }
+   else if (type == EDBUS_PROXY_EVENT_PROPERTY_REMOVED)
+     {
+        if (proxy->properties_changed) return;
+        proxy->properties_changed =
+                 edbus_proxy_properties_changed_callback_add(proxy,
+                                                             _properties_changed,
+                                                             proxy);
+     }
+}
+
+static void
+_edbus_proxy_context_event_cb_del(EDBus_Proxy_Context_Event *ce, EDBus_Proxy_Context_Event_Cb *ctx)
+{
+   ce->list = eina_inlist_remove(ce->list, EINA_INLIST_GET(ctx));
+   free(ctx);
+}
+
+EAPI void
+edbus_proxy_event_callback_del(EDBus_Proxy *proxy, EDBus_Proxy_Event_Type type, EDBus_Proxy_Event_Cb cb, const void *cb_data)
+{
+   EDBus_Proxy_Context_Event *ce;
+   EDBus_Proxy_Context_Event_Cb *iter, *found = NULL;
+
+   EDBUS_PROXY_CHECK(proxy);
+   EINA_SAFETY_ON_NULL_RETURN(cb);
+   EINA_SAFETY_ON_TRUE_RETURN(type >= EDBUS_PROXY_EVENT_LAST);
+
+   ce = proxy->event_handlers + type;
+
+   EINA_INLIST_FOREACH(ce->list, iter)
+     {
+        if (cb != iter->cb) continue;
+        if ((cb_data) && (cb_data != iter->cb_data)) continue;
+
+        found = iter;
+        break;
+     }
+
+   EINA_SAFETY_ON_NULL_RETURN(found);
+   EINA_SAFETY_ON_TRUE_RETURN(found->deleted);
+
+   if (ce->walking)
+     {
+        found->deleted = EINA_TRUE;
+        ce->to_delete = eina_list_append(ce->to_delete, found);
+        return;
+     }
+
+   _edbus_proxy_context_event_cb_del(ce, found);
+
+   if (type == EDBUS_PROXY_EVENT_PROPERTY_CHANGED)
+     {
+        EDBus_Proxy_Context_Event *ce_prop_remove;
+        ce_prop_remove = proxy->event_handlers +
+                 EDBUS_PROXY_EVENT_PROPERTY_REMOVED;
+        if (!ce->list && !proxy->monitor_enabled)
+          {
+             eina_hash_free(proxy->props);
+             proxy->props = NULL;
+          }
+
+        if (!ce_prop_remove->list && !ce->list && !proxy->monitor_enabled)
+          {
+             edbus_signal_handler_unref(proxy->properties_changed);
+             proxy->properties_changed = NULL;
+          }
+     }
+   else if (type == EDBUS_PROXY_EVENT_PROPERTY_REMOVED)
+     {
+        EDBus_Proxy_Context_Event *ce_prop_changed;
+        ce_prop_changed = proxy->event_handlers +
+                 EDBUS_PROXY_EVENT_PROPERTY_CHANGED;
+
+        if (!ce_prop_changed->list && !ce->list && !proxy->monitor_enabled)
+          {
+             edbus_signal_handler_unref(proxy->properties_changed);
+             proxy->properties_changed = NULL;
+          }
+     }
+}
+
+static void
+_edbus_proxy_event_callback_call(EDBus_Proxy *proxy, EDBus_Proxy_Event_Type type, const void *event_info)
+{
+   EDBus_Proxy_Context_Event *ce;
+   EDBus_Proxy_Context_Event_Cb *iter;
+
+   ce = proxy->event_handlers + type;
+
+   ce->walking++;
+   EINA_INLIST_FOREACH(ce->list, iter)
+     {
+        if (iter->deleted) continue;
+        iter->cb((void *)iter->cb_data, proxy, (void *)event_info);
+     }
+   ce->walking--;
+   if (ce->walking > 0) return;
+
+   EINA_LIST_FREE(ce->to_delete, iter)
+     _edbus_proxy_context_event_cb_del(ce, iter);
+}
+
+EAPI EDBus_Object *
+edbus_proxy_object_get(const EDBus_Proxy *proxy)
+{
+   EDBUS_PROXY_CHECK_RETVAL(proxy, NULL);
+   return proxy->obj;
+}
+
+EAPI const char *
+edbus_proxy_interface_get(const EDBus_Proxy *proxy)
+{
+   EDBUS_PROXY_CHECK_RETVAL(proxy, NULL);
+   return proxy->interface;
+}
+
+static void
+_on_pending_free(void *data, const void *dead_pointer)
+{
+   EDBus_Proxy *proxy = data;
+   EDBus_Pending *pending = (EDBus_Pending *)dead_pointer;
+   EDBUS_PROXY_CHECK(proxy);
+   proxy->pendings = eina_inlist_remove(proxy->pendings,
+                                        EINA_INLIST_GET(pending));
+}
+
+static EDBus_Pending *
+_edbus_proxy_send(EDBus_Proxy *proxy, EDBus_Message *msg, EDBus_Message_Cb cb, const void *cb_data, double timeout)
+{
+   EDBus_Pending *pending;
+
+   pending = _edbus_connection_send(proxy->obj->conn, msg, cb, cb_data, timeout);
+   if (!cb) return NULL;
+   EINA_SAFETY_ON_NULL_RETURN_VAL(pending, NULL);
+
+   edbus_pending_cb_free_add(pending, _on_pending_free, proxy);
+   proxy->pendings = eina_inlist_append(proxy->pendings,
+                                        EINA_INLIST_GET(pending));
+
+   return pending;
+}
+
+EAPI EDBus_Pending *
+edbus_proxy_send(EDBus_Proxy *proxy, EDBus_Message *msg, EDBus_Message_Cb cb, const void *cb_data, double timeout)
+{
+   EDBUS_PROXY_CHECK_RETVAL(proxy, NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(msg, NULL);
+
+   return _edbus_proxy_send(proxy, msg, cb, cb_data, timeout);
+}
+
+EAPI EDBus_Message *
+edbus_proxy_method_call_new(EDBus_Proxy *proxy, const char *member)
+{
+   EDBus_Message *msg;
+   EDBUS_PROXY_CHECK_RETVAL(proxy, NULL);
+
+   msg = edbus_message_method_call_new(
+                           edbus_object_bus_name_get(proxy->obj),
+                           edbus_object_bus_path_get(proxy->obj),
+                           proxy->interface, member);
+   return msg;
+}
+
+static EDBus_Pending *
+_edbus_proxy_vcall(EDBus_Proxy *proxy, const char *member, EDBus_Message_Cb cb, const void *cb_data, double timeout, const char *signature, va_list ap)
+{
+   EDBus_Pending *pending;
+   EDBus_Message *msg = edbus_proxy_method_call_new(proxy, member);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(msg, NULL);
+
+   if (!edbus_message_arguments_vset(msg, signature, ap))
+     {
+        edbus_message_unref(msg);
+        ERR("Error setting arguments");
+        return NULL;
+     }
+
+   pending = _edbus_proxy_send(proxy, msg, cb, cb_data, timeout);
+   edbus_message_unref(msg);
+   return pending;
+}
+
+EAPI EDBus_Pending *
+edbus_proxy_call(EDBus_Proxy *proxy, const char *member, EDBus_Message_Cb cb, const void *cb_data, double timeout, const char *signature, ...)
+{
+   EDBus_Pending *pending;
+   va_list ap;
+
+   EDBUS_PROXY_CHECK_RETVAL(proxy, NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(member, NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(signature, NULL);
+
+   va_start(ap, signature);
+   pending = _edbus_proxy_vcall(proxy, member, cb, cb_data, timeout,
+                                signature, ap);
+   va_end(ap);
+
+   return pending;
+}
+
+EAPI EDBus_Pending *
+edbus_proxy_vcall(EDBus_Proxy *proxy, const char *member, EDBus_Message_Cb cb, const void *cb_data, double timeout, const char *signature, va_list ap)
+{
+   EDBUS_PROXY_CHECK_RETVAL(proxy, NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(member, NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(signature, NULL);
+
+   return _edbus_proxy_vcall(proxy, member, cb, cb_data, timeout,
+                             signature, ap);
+}
+
+static void
+_on_signal_handler_free(void *data, const void *dead_pointer)
+{
+   EDBus_Proxy *proxy = data;
+   EDBUS_PROXY_CHECK(proxy);
+   proxy->handlers = eina_list_remove(proxy->handlers, dead_pointer);
+}
+
+EAPI EDBus_Signal_Handler *
+edbus_proxy_signal_handler_add(EDBus_Proxy *proxy, const char *member, EDBus_Signal_Cb cb, const void *cb_data)
+{
+   EDBus_Signal_Handler *handler;
+   const char *name, *path;
+
+   EDBUS_PROXY_CHECK_RETVAL(proxy, NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(cb, NULL);
+
+   name = edbus_object_bus_name_get(proxy->obj);
+   path = edbus_object_bus_path_get(proxy->obj);
+
+   handler = edbus_signal_handler_add(proxy->obj->conn, name, path,
+                                      proxy->interface, member, cb, cb_data);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(handler, NULL);
+
+   edbus_signal_handler_cb_free_add(handler, _on_signal_handler_free, proxy);
+   proxy->handlers = eina_list_append(proxy->handlers, handler);
+
+   return handler;
+}
+
+static EDBus_Proxy *
+get_properties_proxy(EDBus_Proxy *proxy)
+{
+   return edbus_proxy_get(proxy->obj, EDBUS_FDO_INTERFACE_PROPERTIES);
+}
+
+EAPI EDBus_Pending *
+edbus_proxy_property_get(EDBus_Proxy *proxy, const char *name, EDBus_Message_Cb cb, const void *data)
+{
+   EDBUS_PROXY_CHECK_RETVAL(proxy, NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(name, NULL);
+   return edbus_proxy_call(get_properties_proxy(proxy), "Get", cb, data, -1,
+                           "ss", proxy->interface, name);
+}
+
+EAPI EDBus_Pending *
+edbus_proxy_property_set(EDBus_Proxy *proxy, const char *name, char type, const void *value, EDBus_Message_Cb cb, const void *data)
+{
+   EDBus_Message *msg;
+   EDBus_Message_Iter *iter, *variant;
+   EDBus_Pending *pending;
+   char sig[2];
+   EDBUS_PROXY_CHECK_RETVAL(proxy, NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(name, NULL);
+
+   if (!dbus_type_is_basic(type))
+     {
+        ERR("Only basic types may be set using edbus_proxy_property_set()");
+        return NULL;
+     }
+
+   sig[0] = type;
+   sig[1] = 0;
+   msg = edbus_proxy_method_call_new(get_properties_proxy(proxy), "Set");
+   iter = edbus_message_iter_get(msg);
+   edbus_message_iter_basic_append(iter, 's', proxy->interface);
+   edbus_message_iter_basic_append(iter, 's', name);
+   variant = edbus_message_iter_container_new(iter, 'v', sig);
+   edbus_message_iter_basic_append(variant, type, value);
+   edbus_message_iter_container_close(iter, variant);
+
+   pending = edbus_proxy_send(get_properties_proxy(proxy), msg, cb, data, -1);
+   edbus_message_unref(msg);
+
+   return pending;
+}
+
+EAPI EDBus_Pending *
+edbus_proxy_property_get_all(EDBus_Proxy *proxy, EDBus_Message_Cb cb, const void *data)
+{
+   EDBUS_PROXY_CHECK_RETVAL(proxy, NULL);
+   return edbus_proxy_call(get_properties_proxy(proxy), "GetAll", cb, data, -1,
+                           "s", proxy->interface);
+}
+
+EAPI EDBus_Signal_Handler *
+edbus_proxy_properties_changed_callback_add(EDBus_Proxy *proxy, EDBus_Signal_Cb cb, const void *data)
+{
+   EDBus_Signal_Handler *sh;
+   EDBUS_PROXY_CHECK_RETVAL(proxy, NULL);
+   sh = edbus_proxy_signal_handler_add(get_properties_proxy(proxy),
+                                       "PropertiesChanged", cb, data);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(sh, NULL);
+   edbus_signal_handler_match_extra_set(sh, "arg0", proxy->interface, NULL);
+   return sh;
+}
+
+static void
+_property_iter(void *data, const void *key, EDBus_Message_Iter *var)
+{
+   EDBus_Proxy *proxy = data;
+   const char *skey = key;
+   Eina_Value *st_value, stack_value, *value;
+
+   st_value = _message_iter_struct_to_eina_value(var);
+   eina_value_struct_value_get(st_value, "arg0", &stack_value);
+
+   value = eina_hash_find(proxy->props, skey);
+   if (value)
+     {
+        eina_value_flush(value);
+        eina_value_copy(&stack_value, value);
+     }
+   else
+     {
+        value = calloc(1, sizeof(Eina_Value));
+        eina_value_copy(&stack_value, value);
+        eina_hash_add(proxy->props, skey, value);
+     }
+
+   eina_value_free(st_value);
+   eina_value_flush(&stack_value);
+}
+
+static void
+_props_get_all(void *data, const EDBus_Message *msg, EDBus_Pending *pending)
+{
+   EDBus_Proxy *proxy = data;
+   EDBus_Message_Iter *dict;
+
+   if (!edbus_message_arguments_get(msg, "a{sv}", &dict))
+     {
+        ERR("Error getting data from properties getAll.");
+        return;
+     }
+   edbus_message_iter_dict_iterate(dict, "sv", _property_iter, proxy);
+}
+
+EAPI void
+edbus_proxy_properties_monitor(EDBus_Proxy *proxy, Eina_Bool enable)
+{
+   EDBUS_PROXY_CHECK(proxy);
+   if (proxy->monitor_enabled == enable)
+     return;
+
+   proxy->monitor_enabled = enable;
+   if (enable)
+     {
+        if (!proxy->props)
+          proxy->props = eina_hash_string_superfast_new(_props_cache_free);
+        edbus_proxy_property_get_all(proxy, _props_get_all, proxy);
+
+        if (proxy->properties_changed)
+          return;
+        proxy->properties_changed =
+                 edbus_proxy_properties_changed_callback_add(proxy,
+                                                             _properties_changed,
+                                                             proxy);
+     }
+   else
+     {
+        EDBus_Proxy_Context_Event *ce_prop_changed, *ce_prop_removed;
+        ce_prop_changed = proxy->event_handlers + EDBUS_PROXY_EVENT_PROPERTY_CHANGED;
+        ce_prop_removed = proxy->event_handlers + EDBUS_PROXY_EVENT_PROPERTY_REMOVED;
+
+        if (!ce_prop_changed->list)
+          {
+             eina_hash_free(proxy->props);
+             proxy->props = NULL;
+          }
+        if (!ce_prop_changed->list && !ce_prop_removed->list)
+          {
+             edbus_signal_handler_unref(proxy->properties_changed);
+             proxy->properties_changed = NULL;
+          }
+     }
+}
+
+EAPI Eina_Value *
+edbus_proxy_property_local_get(EDBus_Proxy *proxy, const char *name)
+{
+   EDBUS_PROXY_CHECK_RETVAL(proxy, NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(name, NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(proxy->props, NULL);
+   return eina_hash_find(proxy->props, name);
+}
+
+EAPI const Eina_Hash *
+edbus_proxy_property_local_get_all(EDBus_Proxy *proxy)
+{
+   EDBUS_PROXY_CHECK_RETVAL(proxy, NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(proxy->props, NULL);
+   return proxy->props;
+}
diff --git a/src/lib/edbus_proxy.h b/src/lib/edbus_proxy.h
new file mode 100644 (file)
index 0000000..86732b8
--- /dev/null
@@ -0,0 +1,137 @@
+#ifndef EDBUS_PROXY_H
+#define EDBUS_PROXY_H 1
+
+/**
+ * @defgroup EDBus_Proxy Proxy
+ *
+ * @{
+ */
+/**
+ * @brief Get a proxy of the following interface name in a EDBus_Object.
+ */
+EAPI EDBus_Proxy          *edbus_proxy_get(EDBus_Object *obj, const char *interface) EINA_ARG_NONNULL(1, 2) EINA_WARN_UNUSED_RESULT;
+/**
+ * @brief Increase proxy reference.
+ */
+EAPI EDBus_Proxy          *edbus_proxy_ref(EDBus_Proxy *proxy) EINA_ARG_NONNULL(1);
+/**
+ * @brief Decrease proxy reference.
+ * If reference == 0 proxy will be freed and all your children.
+ */
+EAPI void                  edbus_proxy_unref(EDBus_Proxy *proxy) EINA_ARG_NONNULL(1);
+
+EAPI EDBus_Object         *edbus_proxy_object_get(const EDBus_Proxy *proxy) EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT;
+EAPI const char           *edbus_proxy_interface_get(const EDBus_Proxy *proxy) EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT;
+
+EAPI void                  edbus_proxy_data_set(EDBus_Proxy *proxy, const char *key, const void *data) EINA_ARG_NONNULL(1, 2, 3);
+EAPI void                 *edbus_proxy_data_get(const EDBus_Proxy *proxy, const char *key) EINA_ARG_NONNULL(1, 2);
+EAPI void                 *edbus_proxy_data_del(EDBus_Proxy *proxy, const char *key) EINA_ARG_NONNULL(1, 2);
+
+/**
+ * @brief Add a callback function to be called when occurs a event of the
+ * type passed.
+ */
+EAPI void                  edbus_proxy_cb_free_add(EDBus_Proxy *proxy, EDBus_Free_Cb cb, const void *data) EINA_ARG_NONNULL(1, 2);
+/**
+ * @brief Remove callback registered in edbus_proxy_cb_free_add().
+ */
+EAPI void                  edbus_proxy_cb_free_del(EDBus_Proxy *proxy, EDBus_Free_Cb cb, const void *data) EINA_ARG_NONNULL(1, 2);
+
+/**
+ * @brief Constructs a new message to invoke a method on a remote interface.
+ */
+EAPI EDBus_Message        *edbus_proxy_method_call_new(EDBus_Proxy *proxy, const char *member);
+
+/**
+ * @brief Send a message.
+ *
+ * @param proxy the msg will be send in connection that proxy belongs
+ * @param msg message that will be send
+ * @param cb if msg is a method call a callback should be passed
+ * @param cb_data data passed to callback
+ * @param timeout timeout in milliseconds, -1 to default internal value or
+ * EDBUS_TIMEOUT_INFINITE for no timeout
+ */
+EAPI EDBus_Pending        *edbus_proxy_send(EDBus_Proxy *proxy, EDBus_Message *msg, EDBus_Message_Cb cb, const void *cb_data, double timeout) EINA_ARG_NONNULL(1, 2);
+/**
+ * @brief Call a method in proxy.
+ * Send a method call to interface that proxy belong with data.
+ *
+ * @param proxy
+ * @param member method name
+ * @param cb if msg is a method call a callback should be passed
+ * to be execute when response arrive
+ * @param cb_data data passed to callback
+ * @param timeout timeout in milliseconds, -1 to default internal value or
+ * EDBUS_TIMEOUT_INFINITE for no timeout
+ * @param signature of data that will be send
+ * @param ... data value
+ *
+ * @note This function only support basic type to complex types use
+ * edbus_message_iter_* functions.
+ */
+EAPI EDBus_Pending        *edbus_proxy_call(EDBus_Proxy *proxy, const char *member, EDBus_Message_Cb cb, const void *cb_data, double timeout, const char *signature, ...) EINA_ARG_NONNULL(1, 2, 6);
+/**
+ * @brief Call a method in proxy.
+ * Send a method call to interface that proxy belong with data.
+ *
+ * @param proxy
+ * @param member method name
+ * @param cb callback that will be called when response arrive.
+ * @param cb_data data passed to callback
+ * @param timeout timeout in milliseconds, -1 to default internal value or
+ * EDBUS_TIMEOUT_INFINITE for no timeout
+ * @param signature of data that will be send
+ * @param ap va_list of data value
+ *
+ * @note This function only support basic type to complex types use
+ * edbus_message_iter_* functions.
+ */
+EAPI EDBus_Pending        *edbus_proxy_vcall(EDBus_Proxy *proxy, const char *member, EDBus_Message_Cb cb, const void *cb_data, double timeout, const char *signature, va_list ap) EINA_ARG_NONNULL(1, 2, 6);
+/**
+ * @brief Add a signal handler.
+ *
+ * @param proxy interface where the signal is emitted
+ * @param member name of the signal
+ * @param cb callback that will be called when this signal is received
+ * @param cb_data data that will be passed to callback
+ */
+EAPI EDBus_Signal_Handler *edbus_proxy_signal_handler_add(EDBus_Proxy *proxy, const char *member, EDBus_Signal_Cb cb, const void *cb_data) EINA_ARG_NONNULL(1, 3);
+
+typedef enum
+{
+   EDBUS_PROXY_EVENT_PROPERTY_CHANGED = 0,
+   EDBUS_PROXY_EVENT_PROPERTY_REMOVED,
+   EDBUS_PROXY_EVENT_DEL,
+   EDBUS_PROXY_EVENT_LAST    /**< sentinel, not a real event type */
+} EDBus_Proxy_Event_Type;
+
+typedef struct _EDBus_Proxy_Event_Property_Changed
+{
+   const char       *name;
+   const Eina_Value *value;
+} EDBus_Proxy_Event_Property_Changed;
+
+typedef struct _EDBus_Proxy_Event_Property_Removed
+{
+   const char  *interface;
+   EDBus_Proxy *proxy;
+   const char  *name;
+} EDBus_Proxy_Event_Property_Removed;
+
+typedef void (*EDBus_Proxy_Event_Cb)(void *data, EDBus_Proxy *proxy, void *event_info);
+
+/**
+ * @brief Add a callback function to be called when occurs a event of the
+ * type passed.
+ */
+EAPI void edbus_proxy_event_callback_add(EDBus_Proxy *proxy, EDBus_Proxy_Event_Type type, EDBus_Proxy_Event_Cb cb, const void *cb_data) EINA_ARG_NONNULL(1, 3);
+/**
+ * @brief Remove callback registered in edbus_proxy_event_callback_add().
+ */
+EAPI void edbus_proxy_event_callback_del(EDBus_Proxy *proxy, EDBus_Proxy_Event_Type type, EDBus_Proxy_Event_Cb cb, const void *cb_data) EINA_ARG_NONNULL(1, 3);
+
+/**
+ * @}
+ */
+#endif
diff --git a/src/lib/edbus_service.c b/src/lib/edbus_service.c
new file mode 100644 (file)
index 0000000..278e647
--- /dev/null
@@ -0,0 +1,587 @@
+#include "edbus_private_types.h"
+#include "edbus_private.h"
+
+#define DBUS_ANNOTATION(name, value) \
+        "<annotation" \
+        " name=\"org.freedesktop.DBus." name "\"" \
+        " value=\"" value "\"" \
+        "/>"
+
+#define DBUS_ANNOTATION_DEPRECATED  DBUS_ANNOTATION("Deprecated", "true")
+#define DBUS_ANNOTATION_NOREPLY     DBUS_ANNOTATION("Method.NoReply", "true")
+
+#define EDBUS_SERVICE_INTERFACE_CHECK(obj)                         \
+  do                                                            \
+    {                                                           \
+       EINA_SAFETY_ON_NULL_RETURN(obj);                         \
+       if (!EINA_MAGIC_CHECK(obj, EDBUS_SERVICE_INTERFACE_MAGIC))  \
+         {                                                      \
+            EINA_MAGIC_FAIL(obj, EDBUS_SERVICE_INTERFACE_MAGIC);   \
+            return;                                             \
+         }                                                      \
+    }                                                           \
+  while (0)
+
+#define EDBUS_SERVICE_INTERFACE_CHECK_RETVAL(obj, retval)                  \
+  do                                                                    \
+    {                                                                   \
+       EINA_SAFETY_ON_NULL_RETURN_VAL(obj, retval);                     \
+       if (!EINA_MAGIC_CHECK(obj, EDBUS_SERVICE_INTERFACE_MAGIC))          \
+         {                                                              \
+            EINA_MAGIC_FAIL(obj, EDBUS_SERVICE_INTERFACE_MAGIC);           \
+            return retval;                                              \
+         }                                                              \
+    }                                                                   \
+  while (0)
+
+
+static void _object_unregister(DBusConnection *conn, void *user_data);
+static DBusHandlerResult _object_handler(DBusConnection *conn, DBusMessage *message, void *user_data);
+static void _object_free(EDBus_Service_Object *obj);
+static void _interface_free(EDBus_Service_Interface *interface);
+static void _on_connection_free(void *data, const void *dead_pointer);
+
+static DBusObjectPathVTable vtable = {
+  _object_unregister,
+  _object_handler,
+  NULL,
+  NULL,
+  NULL,
+  NULL
+};
+
+EDBus_Service_Interface *introspectable;
+
+static void
+_introspect_append_signal(Eina_Strbuf *buf, const EDBus_Signal *sig)
+{
+   int i;
+   const char *part, *name;
+
+   eina_strbuf_append_printf(buf, "<signal name=\"%s\">", sig->name);
+   if (sig->flags & EDBUS_SIGNAL_FLAG_DEPRECATED)
+     eina_strbuf_append(buf, DBUS_ANNOTATION_DEPRECATED);
+
+   for (i = 0; &sig->args[i] && sig->args[i].signature; i++)
+     {
+        part = sig->args[i].signature;
+        name = sig->args[i].name;
+
+        if (name && name[0])
+          eina_strbuf_append_printf(buf, "<arg type=\"%s\" name=\"%s\"/>",
+                                    part, name);
+        else
+          eina_strbuf_append_printf(buf, "<arg type=\"%s\"/>", part);
+     }
+   eina_strbuf_append(buf, "</signal>");
+}
+
+static void
+_introspect_append_method(Eina_Strbuf *buf, const EDBus_Method *method)
+{
+   int i;
+   const char *part, *name;
+
+   eina_strbuf_append_printf(buf, "<method name=\"%s\">", method->member);
+   if (method->flags & EDBUS_METHOD_FLAG_DEPRECATED)
+     eina_strbuf_append(buf, DBUS_ANNOTATION_DEPRECATED);
+   if (method->flags & EDBUS_METHOD_FLAG_NOREPLY)
+     eina_strbuf_append(buf, DBUS_ANNOTATION_NOREPLY);
+
+   for (i = 0; &method->in[i] && method->in[i].signature; i++)
+     {
+        part = method->in[i].signature;
+        name = method->in[i].name;
+
+        if (name && name[0])
+          eina_strbuf_append_printf(buf,
+                                    "<arg type=\"%s\" name=\"%s\" direction=\"in\"/>",
+                                    part, name);
+        else
+          eina_strbuf_append_printf(buf, "<arg type=\"%s\" direction=\"in\"/>",
+                                    part);
+     }
+
+   for (i = 0; &method->out[i] && method->out[i].signature; i++)
+     {
+        part = method->out[i].signature;
+        name = method->out[i].name;
+
+        if (name && name[0])
+          eina_strbuf_append_printf(buf,
+                                    "<arg type=\"%s\" name=\"%s\" direction=\"out\"/>",
+                                    part, name);
+        else
+          eina_strbuf_append_printf(buf, "<arg type=\"%s\" direction=\"out\"/>",
+                                    part);
+     }
+   eina_strbuf_append(buf, "</method>");
+}
+
+static void
+_introspect_append_interface(Eina_Strbuf *buf, EDBus_Service_Interface *iface)
+{
+   EDBus_Method *method;
+   Eina_Iterator *iterator;
+   unsigned short i;
+   unsigned int size;
+
+   eina_strbuf_append_printf(buf, "<interface name=\"%s\">", iface->name);
+   iterator = eina_hash_iterator_data_new(iface->methods);
+   EINA_ITERATOR_FOREACH(iterator, method)
+     _introspect_append_method(buf, method);
+   eina_iterator_free(iterator);
+
+   size = eina_array_count(iface->sign_of_signals);
+   for (i = 0; i < size; i++)
+     _introspect_append_signal(buf, &iface->signals[i]);
+
+   eina_strbuf_append(buf, "</interface>");
+}
+
+static EDBus_Message *
+cb_introspect(const EDBus_Service_Interface *_iface, const EDBus_Message *message)
+{
+   EDBus_Service_Object *obj = _iface->obj;
+   EDBus_Message *reply = edbus_message_method_return_new(message);
+   if (obj->introspection_dirty || !obj->introspection_data)
+     {
+        Eina_Iterator *iterator;
+        EDBus_Service_Interface *iface;
+
+        if (obj->introspection_data)
+          eina_strbuf_reset(obj->introspection_data);
+        else
+          obj->introspection_data = eina_strbuf_new();
+        EINA_SAFETY_ON_NULL_RETURN_VAL(obj->introspection_data, NULL);
+
+        eina_strbuf_append(obj->introspection_data, "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\" \"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">");
+        eina_strbuf_append_printf(obj->introspection_data,
+                                  "<node name=\"%s\">", obj->path);
+
+        iterator = eina_hash_iterator_data_new(obj->interfaces);
+        EINA_ITERATOR_FOREACH(iterator, iface)
+          _introspect_append_interface(obj->introspection_data, iface);
+        eina_iterator_free(iterator);
+        eina_strbuf_append(obj->introspection_data, "</node>");
+
+        obj->introspection_dirty = EINA_FALSE;
+     }
+
+   edbus_message_arguments_set(reply, "s", eina_strbuf_string_get(obj->introspection_data));
+   return reply;
+}
+
+static const EDBus_Method introspect = {
+   "Introspect", NULL, EDBUS_ARGS({ "s", "xml" }), cb_introspect
+};
+
+static void
+_introspectable_create(void)
+{
+   introspectable = calloc(1, sizeof(EDBus_Service_Interface));
+   EINA_SAFETY_ON_NULL_RETURN(introspectable);
+
+   EINA_MAGIC_SET(introspectable, EDBUS_SERVICE_INTERFACE_MAGIC);
+   introspectable->sign_of_signals = eina_array_new(1);
+   introspectable->name = eina_stringshare_add("org.freedesktop.DBus.Introspectable");
+   introspectable->methods = eina_hash_string_small_new(NULL);
+
+   eina_hash_add(introspectable->methods, introspect.member, &introspect);
+}
+
+static void
+_introspectable_free(void)
+{
+   eina_hash_free(introspectable->methods);
+   eina_stringshare_del(introspectable->name);
+   eina_array_free(introspectable->sign_of_signals);
+   free(introspectable);
+}
+
+Eina_Bool
+edbus_service_init(void)
+{
+   _introspectable_create();
+   EINA_SAFETY_ON_NULL_RETURN_VAL(introspectable, EINA_FALSE);
+
+   return EINA_TRUE;
+}
+
+void
+edbus_service_shutdown(void)
+{
+   _introspectable_free();
+}
+
+static EDBus_Service_Object *
+_edbus_service_object_add(EDBus_Connection *conn, const char *path)
+{
+   EDBus_Service_Object *obj;
+
+   obj = calloc(1, sizeof(EDBus_Service_Object));
+   EINA_SAFETY_ON_NULL_RETURN_VAL(obj, NULL);
+
+   if (!dbus_connection_register_object_path(conn->dbus_conn, path, &vtable,
+                                             obj))
+     {
+        free(obj);
+        return NULL;
+     }
+
+   obj->conn = conn;
+   obj->path = eina_stringshare_add(path);
+   obj->interfaces = eina_hash_string_superfast_new(NULL);
+   edbus_connection_cb_free_add(conn, _on_connection_free, obj);
+
+   eina_hash_add(obj->interfaces, introspectable->name, introspectable);
+
+   return obj;
+}
+
+static EDBus_Service_Interface *
+_edbus_service_interface_add(EDBus_Service_Object *obj, const char *interface)
+{
+   EDBus_Service_Interface *iface;
+
+   iface = eina_hash_find(obj->interfaces, interface);
+   if (iface) return iface;
+
+   iface = calloc(1, sizeof(EDBus_Service_Interface));
+   EINA_SAFETY_ON_NULL_RETURN_VAL(iface, NULL);
+
+   EINA_MAGIC_SET(iface, EDBUS_SERVICE_INTERFACE_MAGIC);
+   iface->name = eina_stringshare_add(interface);
+   iface->methods = eina_hash_string_superfast_new(NULL);
+   iface->obj = obj;
+   eina_hash_add(obj->interfaces, iface->name, iface);
+   return iface;
+}
+
+static Eina_Bool
+_have_signature(const EDBus_Arg_Info *args, EDBus_Message *msg)
+{
+   const char *sig = dbus_message_get_signature(msg->dbus_msg);
+   const char *p = NULL;
+
+   for (; args && args->signature && *sig; args++)
+     {
+        p = args->signature;
+        for (; *sig && *p; sig++, p++)
+          {
+             if (*p != *sig)
+               return EINA_FALSE;
+          }
+     }
+
+   if (*sig || (p && *p) || (args && args->signature))
+     return EINA_FALSE;
+
+   return EINA_TRUE;
+}
+
+static Eina_Bool
+_edbus_service_method_add(EDBus_Service_Interface *interface, EDBus_Method *method)
+{
+   EINA_SAFETY_ON_TRUE_RETURN_VAL(!!eina_hash_find(interface->methods,
+                                  method->member), EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(method->member, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(method->cb, EINA_FALSE);
+
+   eina_hash_add(interface->methods, method->member, method);
+   return EINA_TRUE;
+}
+
+EAPI EDBus_Service_Interface *
+edbus_service_interface_register(EDBus_Connection *conn, const char *path, const EDBus_Service_Interface_Desc *desc)
+{
+   EDBus_Service_Object *obj;
+   EDBus_Service_Interface *iface;
+   EDBus_Method *method;
+   unsigned short i, z;
+   Eina_Strbuf *buf = NULL;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(conn, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(path, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(desc, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(desc->interface, EINA_FALSE);
+
+   if (!dbus_connection_get_object_path_data(conn->dbus_conn, path,
+                                             (void*)&obj))
+     {
+        ERR("Invalid object path");
+        return NULL;
+     }
+
+   if (obj == NULL)
+     obj = _edbus_service_object_add(conn, path);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(obj, EINA_FALSE);
+
+   iface = _edbus_service_interface_add(obj, desc->interface);
+   if (!iface)
+     {
+        if (eina_hash_population(obj->interfaces) < 2)
+           _object_free(obj);
+        return NULL;
+     }
+
+   for (method = (EDBus_Method *)desc->methods; method && method->member; method++)
+     _edbus_service_method_add(iface, method);
+
+   if (!iface->sign_of_signals)
+     iface->sign_of_signals = eina_array_new(1);
+   for (i = 0; &desc->signals[i] && desc->signals[i].name; i++)
+     {
+        buf = eina_strbuf_new();
+        for (z = 0;
+             &desc->signals[i].args[z] && desc->signals[i].args[z].signature;
+             z++)
+          eina_strbuf_append(buf, desc->signals[i].args[z].signature);
+
+        if (!dbus_signature_validate(eina_strbuf_string_get(buf), NULL))
+          {
+             ERR("Signal with invalid signature: interface=%s signal=%s",
+                 iface->name, desc->signals[i].name);
+             eina_strbuf_free(buf);
+             continue;
+          }
+
+       eina_array_push(iface->sign_of_signals,
+                       eina_stringshare_add(eina_strbuf_string_get(buf)));
+       eina_strbuf_free(buf);
+     }
+   iface->signals = desc->signals;
+
+   return iface;
+}
+
+static void
+_interface_free(EDBus_Service_Interface *interface)
+{
+   unsigned size, i;
+   if (interface == introspectable) return;
+
+   eina_hash_free(interface->methods);
+   eina_stringshare_del(interface->name);
+   size = eina_array_count(interface->sign_of_signals);
+   for (i = 0; i < size; i++)
+     eina_stringshare_del(eina_array_data_get(interface->sign_of_signals, i));
+   eina_array_free(interface->sign_of_signals);
+   free(interface);
+}
+
+static void
+_object_free(EDBus_Service_Object *obj)
+{
+   Eina_Iterator *iterator;
+   EDBus_Service_Interface *iface;
+
+   iterator = eina_hash_iterator_data_new(obj->interfaces);
+   EINA_ITERATOR_FOREACH(iterator, iface)
+     _interface_free(iface);
+
+   edbus_data_del_all(&obj->data);
+
+   eina_hash_free(obj->interfaces);
+   eina_iterator_free(iterator);
+   if (obj->introspection_data)
+     eina_strbuf_free(obj->introspection_data);
+   eina_stringshare_del(obj->path);
+   free(obj);
+}
+
+static void
+_on_connection_free(void *data, const void *dead_pointer)
+{
+   EDBus_Service_Object *obj = data;
+   dbus_connection_unregister_object_path(obj->conn->dbus_conn, obj->path);
+}
+
+EAPI void
+edbus_service_interface_unregister(EDBus_Service_Interface *iface)
+{
+   EDBUS_SERVICE_INTERFACE_CHECK(iface);
+   eina_hash_del(iface->obj->interfaces, NULL, iface);
+   if (eina_hash_population(iface->obj->interfaces) < 2)
+     edbus_service_object_unregister(iface);
+   _interface_free(iface);
+}
+
+EAPI void
+edbus_service_object_unregister(EDBus_Service_Interface *iface)
+{
+   EDBUS_SERVICE_INTERFACE_CHECK(iface);
+   /*
+    * It will be freed when _object_unregister() is called
+    * by libdbus.
+    */
+   edbus_connection_cb_free_del(iface->obj->conn, _on_connection_free, iface->obj);
+   dbus_connection_unregister_object_path(iface->obj->conn->dbus_conn, iface->obj->path);
+}
+
+static void
+_object_unregister(DBusConnection *conn, void *user_data)
+{
+   EDBus_Service_Object *obj = user_data;
+   _object_free(obj);
+}
+
+static DBusHandlerResult
+_object_handler(DBusConnection *conn, DBusMessage *msg, void *user_data)
+{
+   EDBus_Service_Object *obj;
+   EDBus_Service_Interface *iface;
+   EDBus_Method *method;
+   EDBus_Message *edbus_msg;
+   EDBus_Message *reply;
+
+   obj = user_data;
+   if (!obj) return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+   DBG("Connection@%p Got message:\n"
+          "  Type: %s\n"
+          "  Path: %s\n"
+          "  Interface: %s\n"
+          "  Member: %s\n"
+          "  Sender: %s", obj->conn,
+          dbus_message_type_to_string(dbus_message_get_type(msg)),
+          dbus_message_get_path(msg),
+          dbus_message_get_interface(msg),
+          dbus_message_get_member(msg),
+          dbus_message_get_sender(msg));
+
+   iface = eina_hash_find(obj->interfaces, dbus_message_get_interface(msg));
+   if (!iface) return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+   method = eina_hash_find(iface->methods, dbus_message_get_member(msg));
+   if (!method) return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+   edbus_msg = edbus_message_new(EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(edbus_msg, DBUS_HANDLER_RESULT_NEED_MEMORY);
+   edbus_msg->dbus_msg = msg;
+   dbus_message_iter_init(edbus_msg->dbus_msg, &edbus_msg->iterator->dbus_iterator);
+
+   if (!_have_signature(method->in, edbus_msg))
+     {
+        reply = edbus_message_error_new(edbus_msg,
+                                        DBUS_ERROR_INVALID_SIGNATURE,
+                                        "See introspectable to know the expected signature");
+     }
+   else
+     {
+        if (iface->obj)
+          reply = method->cb(iface, edbus_msg);
+        else
+          {
+             //if iface does have obj it is some of FreeDesktop interfaces:
+             //Introspectable, Properties...
+             EDBus_Service_Interface *cpy;
+             cpy = calloc(1, sizeof(EDBus_Service_Interface));
+             if (!cpy)
+              {
+                 dbus_message_ref(edbus_msg->dbus_msg);
+                  edbus_message_unref(edbus_msg);
+                  return DBUS_HANDLER_RESULT_NEED_MEMORY;
+               }
+             cpy->obj = obj;
+             reply = method->cb(cpy, edbus_msg);
+             free(cpy);
+          }
+     }
+
+   dbus_message_ref(edbus_msg->dbus_msg);
+   edbus_message_unref(edbus_msg);
+   if (!reply) return DBUS_HANDLER_RESULT_HANDLED;
+
+   _edbus_connection_send(obj->conn, reply, NULL, NULL, -1);
+   edbus_message_unref(reply);
+
+   return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+EAPI EDBus_Connection *
+edbus_service_connection_get(const EDBus_Service_Interface *iface)
+{
+   EDBUS_SERVICE_INTERFACE_CHECK_RETVAL(iface, NULL);
+   return iface->obj->conn;
+}
+
+EAPI const char *
+edbus_service_object_path_get(const EDBus_Service_Interface *iface)
+{
+   EDBUS_SERVICE_INTERFACE_CHECK_RETVAL(iface, NULL);
+   return iface->obj->path;
+}
+
+EAPI EDBus_Message *
+edbus_service_signal_new(EDBus_Service_Interface *iface, unsigned int signal_id)
+{
+   unsigned size;
+   EDBUS_SERVICE_INTERFACE_CHECK_RETVAL(iface, EINA_FALSE);
+   size = eina_array_count(iface->sign_of_signals);
+   EINA_SAFETY_ON_FALSE_RETURN_VAL(signal_id < size, EINA_FALSE);
+
+   return edbus_message_signal_new(iface->obj->path, iface->name,
+                                   iface->signals[signal_id].name);
+}
+
+EAPI Eina_Bool
+edbus_service_signal_emit(EDBus_Service_Interface *iface, unsigned int signal_id, ...)
+{
+   EDBus_Message *sig;
+   va_list ap;
+   Eina_Bool r;
+   const char *signature;
+   unsigned size;
+
+   EDBUS_SERVICE_INTERFACE_CHECK_RETVAL(iface, EINA_FALSE);
+   size = eina_array_count(iface->sign_of_signals);
+   EINA_SAFETY_ON_FALSE_RETURN_VAL(signal_id < size, EINA_FALSE);
+
+   sig = edbus_service_signal_new(iface, signal_id);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(sig, EINA_FALSE);
+
+   signature = eina_array_data_get(iface->sign_of_signals, signal_id);
+   va_start(ap, signal_id);
+   r = edbus_message_arguments_vset(sig, signature, ap);
+   va_end(ap);
+   EINA_SAFETY_ON_FALSE_RETURN_VAL(r, EINA_FALSE);
+
+   edbus_service_signal_send(iface, sig);
+   edbus_message_unref(sig);
+   return EINA_TRUE;
+}
+
+EAPI Eina_Bool
+edbus_service_signal_send(EDBus_Service_Interface *iface, EDBus_Message *signal_msg)
+{
+   EDBUS_SERVICE_INTERFACE_CHECK_RETVAL(iface, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(signal_msg, EINA_FALSE);
+   _edbus_connection_send(iface->obj->conn, signal_msg, NULL, NULL, -1);
+   return EINA_TRUE;
+}
+
+EAPI void
+edbus_service_object_data_set(EDBus_Service_Interface *iface, const char *key, const void *data)
+{
+   EDBUS_SERVICE_INTERFACE_CHECK(iface);
+   EINA_SAFETY_ON_NULL_RETURN(key);
+   EINA_SAFETY_ON_NULL_RETURN(data);
+   edbus_data_set(&(iface->obj->data), key, data);
+}
+
+EAPI void *
+edbus_service_object_data_get(const EDBus_Service_Interface *iface, const char *key)
+{
+   EDBUS_SERVICE_INTERFACE_CHECK_RETVAL(iface, NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(key, NULL);
+   return edbus_data_get(&(((EDBus_Service_Object *)iface->obj)->data), key);
+}
+
+EAPI void *
+edbus_service_object_data_del(EDBus_Service_Interface *iface, const char *key)
+{
+   EDBUS_SERVICE_INTERFACE_CHECK_RETVAL(iface, NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(key, NULL);
+   return edbus_data_del(&(((EDBus_Service_Object *)iface->obj)->data), key);
+}
diff --git a/src/lib/edbus_service.h b/src/lib/edbus_service.h
new file mode 100644 (file)
index 0000000..4a260cd
--- /dev/null
@@ -0,0 +1,156 @@
+#ifndef EDBUS_SERVICE_H
+#define EDBUS_SERVICE_H 1
+
+/**
+ * @defgroup EDBus_Service Service
+ *
+ * @{
+ */
+#define EDBUS_METHOD_FLAG_DEPRECATED 1
+#define EDBUS_METHOD_FLAG_NOREPLY (1 << 1)
+
+#define EDBUS_SIGNAL_FLAG_DEPRECATED 1
+
+typedef struct _EDBus_Arg_Info
+{
+   const char *signature;
+   const char *name;
+} EDBus_Arg_Info;
+
+/**
+ * @brief Used to insert complete types to signature of methods or signals.
+ *
+ * Example: EDBUS_ARGS({"s", "interface"}, {"s", "property"})
+ * The signature will be "ss" and each string will have a tag name on
+ * introspect XML with the respective name.
+ */
+#define EDBUS_ARGS(args...) (const EDBus_Arg_Info[]){ args, { NULL, NULL } }
+
+typedef struct _EDBus_Service_Interface EDBus_Service_Interface;
+typedef EDBus_Message * (*EDBus_Method_Cb)(const EDBus_Service_Interface *iface, const EDBus_Message *message);
+
+typedef Eina_Bool (*EDBus_Property_Get_Cb)(EDBus_Service_Interface *iface, const char *propname, EDBus_Message_Iter *iter, EDBus_Message **error);
+typedef EDBus_Message *(*EDBus_Property_Set_Cb)(EDBus_Service_Interface *iface, const char *propname, EDBus_Message *input_msg);
+
+typedef struct _EDBus_Method
+{
+   const char *member;
+   const EDBus_Arg_Info *in;
+   const EDBus_Arg_Info *out;
+   EDBus_Method_Cb cb;
+   unsigned int flags;
+} EDBus_Method;
+
+typedef struct _EDBus_Signal
+{
+   const char *name;
+   const EDBus_Arg_Info *args;
+   unsigned int flags;
+} EDBus_Signal;
+
+typedef struct _EDBus_Property
+{
+   const char *name;
+   const char *type;
+   unsigned int flags;
+   EDBus_Property_Set_Cb set_func;
+   EDBus_Property_Get_Cb get_func;
+} EDBus_Property;
+
+typedef struct _EDBus_Service_Interface_Desc
+{
+   const char *interface;
+   const EDBus_Method *methods;
+   const EDBus_Signal *signals;
+   const EDBus_Property *properties;
+   const EDBus_Property_Set_Cb default_set;
+   const EDBus_Property_Get_Cb default_get;
+} EDBus_Service_Interface_Desc;
+
+/**
+ * @brief Register an interface in the given path and connection.
+ *
+ * @param conn where the interface should listen
+ * @param path object path
+ * @param iface interface
+ * @param methods array of the methods that should be registered in this
+ * interface, the last item of array should be filled with NULL
+ * @param signals array of signal that this interface send, the last item
+ * of array should be filled with NULL
+ *
+ * @note methods and signals must be static variables
+ *
+ * @return Interface
+ */
+EAPI EDBus_Service_Interface *edbus_service_interface_register(EDBus_Connection *conn, const char *path, const EDBus_Service_Interface_Desc *desc);
+
+/**
+ * @brief Unregister a interface.
+ * If this is the last interface of the object path, the object path will be
+ * removed too.
+ */
+EAPI void edbus_service_interface_unregister(EDBus_Service_Interface *iface);
+/**
+ * @brief Unregister all interfaces of the object path that this interface belongs
+ * and the object path.
+ */
+EAPI void edbus_service_object_unregister(EDBus_Service_Interface *iface);
+EAPI EDBus_Connection *edbus_service_connection_get(const EDBus_Service_Interface *iface);
+EAPI const char *edbus_service_object_path_get(const EDBus_Service_Interface *iface);
+
+/**
+ * @brief Emit a signal handler of the interface with non-complex types.
+ * Each signal handler have a internal id, the first signal handler of
+ * interface is = 0 the second = 1 and go on.
+ *
+ * @param iface interface of the signal
+ * @param signal_id id of signal
+ * @param ... values that will be send on signal
+ */
+EAPI Eina_Bool edbus_service_signal_emit(EDBus_Service_Interface *iface, unsigned int signal_id, ...) EINA_ARG_NONNULL(1);
+/**
+ * @brief Create signal message.
+ * Each signal handler have a internal id, the first signal handler of
+ * interface is = 0 the second = 1 and go on.
+ * This function is used when the signal has complex types.
+ *
+ * @param iface interface of the signal
+ * @param signal_id id of signal
+ */
+EAPI EDBus_Message *edbus_service_signal_new(EDBus_Service_Interface *iface, unsigned int signal_id) EINA_ARG_NONNULL(1);
+/**
+ * @brief Send a signal message.
+ */
+EAPI Eina_Bool edbus_service_signal_send(EDBus_Service_Interface *iface, EDBus_Message *signal_msg) EINA_ARG_NONNULL(1, 2);
+/**
+ * @brief Store data at object path, this data can be obtained from all interfaces
+ * of the same object.
+ *
+ * @param iface interface that belong to the object path where data will
+ * be stored
+ * @param key to identify data
+ * @param data
+ */
+EAPI void edbus_service_object_data_set(EDBus_Service_Interface *iface, const char *key, const void *data);
+/**
+ * @brief Get data stored in object path.
+ *
+ * @param iface interface that belongs to the object path where data are stored
+ * @param key that identify data
+ *
+ * @return pointer to data if found otherwise NULL
+ */
+EAPI void *edbus_service_object_data_get(const EDBus_Service_Interface *iface, const char *key);
+/**
+ * @brief Del data stored in object path.
+ *
+ * @param iface interface that belongs to the object path where data are stored
+ * @param key that identify data
+ *
+ * @return pointer to data if found otherwise NULL
+ */
+EAPI void *edbus_service_object_data_del(EDBus_Service_Interface *iface, const char *key);
+/**
+ * @}
+ */
+#endif
diff --git a/src/lib/edbus_signal_handler.c b/src/lib/edbus_signal_handler.c
new file mode 100644 (file)
index 0000000..4ebe303
--- /dev/null
@@ -0,0 +1,352 @@
+#include "edbus_private.h"
+#include "edbus_private_types.h"
+#include <dbus/dbus.h>
+
+/* TODO: mempool of EDBus_Signal_Handler */
+
+#define SENDER_KEY "sender"
+#define PATH_KEY "path"
+#define INTERFACE_KEY "interface"
+#define MEMBER_KEY "member"
+#define ARG_X_KEY "arg%u"
+
+#define EDBUS_SIGNAL_HANDLER_CHECK(handler)                        \
+  do                                                               \
+    {                                                              \
+       EINA_SAFETY_ON_NULL_RETURN(handler);                        \
+       if (!EINA_MAGIC_CHECK(handler, EDBUS_SIGNAL_HANDLER_MAGIC)) \
+         {                                                         \
+            EINA_MAGIC_FAIL(handler, EDBUS_SIGNAL_HANDLER_MAGIC);  \
+            return;                                                \
+         }                                                         \
+    }                                                              \
+  while (0)
+
+#define EDBUS_SIGNAL_HANDLER_CHECK_RETVAL(handler, retval)         \
+  do                                                               \
+    {                                                              \
+       EINA_SAFETY_ON_NULL_RETURN_VAL(handler, retval);            \
+       if (!EINA_MAGIC_CHECK(handler, EDBUS_SIGNAL_HANDLER_MAGIC)) \
+         {                                                         \
+            EINA_MAGIC_FAIL(handler, EDBUS_SIGNAL_HANDLER_MAGIC);  \
+            return retval;                                         \
+         }                                                         \
+    }                                                              \
+  while (0)
+
+static void _edbus_signal_handler_del(EDBus_Signal_Handler *handler);
+static void _edbus_signal_handler_clean(EDBus_Signal_Handler *handler);
+
+Eina_Bool
+edbus_signal_handler_init(void)
+{
+   return EINA_TRUE;
+}
+
+void
+edbus_signal_handler_shutdown(void)
+{
+}
+
+static void
+_match_append(Eina_Strbuf *match, const char *key, const char *value)
+{
+   if (!value) return;
+
+   if ((eina_strbuf_length_get(match) + strlen(",=''") + strlen(key) + strlen(value))
+       >= DBUS_MAXIMUM_MATCH_RULE_LENGTH)
+     {
+        ERR("cannot add match %s='%s' to %s: too long!", key, value,
+            eina_strbuf_string_get(match));
+        return;
+     }
+
+   eina_strbuf_append_printf(match, ",%s='%s'", key, value);
+}
+
+#define ARGX "arg"
+
+static int
+_sort_arg(const void *d1, const void *d2)
+{
+   const Signal_Argument *arg1, *arg2;
+   arg1 = d1;
+   arg2 = d2;
+   return arg1->index - arg2->index;
+}
+
+EAPI Eina_Bool
+edbus_signal_handler_match_extra_vset(EDBus_Signal_Handler *sh, va_list ap)
+{
+   const char *key = NULL, *read;
+   DBusError err;
+
+   EDBUS_SIGNAL_HANDLER_CHECK_RETVAL(sh, EINA_FALSE);
+
+   dbus_error_init(&err);
+   dbus_bus_remove_match(sh->conn->dbus_conn,
+                         eina_strbuf_string_get(sh->match), &err);
+   EINA_SAFETY_ON_TRUE_RETURN_VAL(dbus_error_is_set(&err), EINA_FALSE);
+
+   for (read = va_arg(ap, char *); read; read = va_arg(ap, char *))
+     {
+        Signal_Argument *arg;
+
+        if (!key)
+          {
+             key = read;
+             continue;
+          }
+        arg = calloc(1, sizeof(Signal_Argument));
+        EINA_SAFETY_ON_NULL_GOTO(arg, error);
+        if (!strncmp(key, ARGX, strlen(ARGX)))
+          {
+             int id = atoi(key + strlen(ARGX));
+             arg->index = (unsigned short) id;
+             arg->value = eina_stringshare_add(read);
+             sh->args = eina_inlist_sorted_state_insert(sh->args,
+                                                        EINA_INLIST_GET(arg),
+                                                        _sort_arg,
+                                                        sh->state_args);
+             _match_append(sh->match, key, read);
+          }
+        else
+          {
+             ERR("%s not supported", key);
+             free(arg);
+          }
+        key = NULL;
+     }
+
+   dbus_error_init(&err);
+   dbus_bus_add_match(sh->conn->dbus_conn,
+                      eina_strbuf_string_get(sh->match), &err);
+   if (!dbus_error_is_set(&err))
+     return EINA_TRUE;
+
+   ERR("Error setting new match.");
+   return EINA_FALSE;
+
+error:
+   dbus_error_init(&err);
+   dbus_bus_add_match(sh->conn->dbus_conn,
+                      eina_strbuf_string_get(sh->match), &err);
+   if (dbus_error_is_set(&err))
+     ERR("Error setting partial extra arguments.");
+   return EINA_FALSE;
+}
+
+EAPI Eina_Bool
+edbus_signal_handler_match_extra_set(EDBus_Signal_Handler *sh, ...)
+{
+   Eina_Bool ret;
+   va_list ap;
+
+   va_start(ap, sh);
+   ret = edbus_signal_handler_match_extra_vset(sh, ap);
+   va_end(ap);
+   return ret;
+}
+
+EAPI EDBus_Signal_Handler *
+edbus_signal_handler_add(EDBus_Connection *conn, const char *sender, const char *path, const char *interface, const char *member, EDBus_Signal_Cb cb, const void *cb_data)
+{
+   EDBus_Signal_Handler *sh;
+   Eina_Strbuf *match;
+   DBusError err;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(conn, NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(cb, NULL);
+   DBG("conn=%p, sender=%s, path=%s, interface=%s, member=%s, cb=%p %p",
+       conn, sender, path, interface, member, cb, cb_data);
+
+   sh = calloc(1, sizeof(EDBus_Signal_Handler));
+   EINA_SAFETY_ON_NULL_RETURN_VAL(sh, NULL);
+
+   match = eina_strbuf_new();
+   EINA_SAFETY_ON_NULL_GOTO(match, cleanup_create_strbuf);
+   eina_strbuf_append(match, "type='signal'");
+   _match_append(match, SENDER_KEY, sender);
+   _match_append(match, PATH_KEY, path);
+   _match_append(match, INTERFACE_KEY, interface);
+   _match_append(match, MEMBER_KEY, member);
+
+   dbus_error_init(&err);
+   dbus_bus_add_match(conn->dbus_conn, eina_strbuf_string_get(match), &err);
+   if (dbus_error_is_set(&err)) goto cleanup;
+
+   if (sender && sender[0] != ':' && strcmp(sender, EDBUS_FDO_BUS))
+     {
+        sh->bus = edbus_connection_name_get(conn, sender);
+        if (!sh->bus) goto cleanup;
+        edbus_connection_name_owner_monitor(conn, sh->bus, EINA_TRUE);
+     }
+
+   sh->cb = cb;
+   sh->cb_data = cb_data;
+   sh->conn = conn;
+   sh->interface = eina_stringshare_add(interface);
+   sh->member = eina_stringshare_add(member);
+   sh->path = eina_stringshare_add(path);
+   sh->sender = eina_stringshare_add(sender);
+   sh->match = match;
+   sh->refcount = 1;
+   sh->dangling = EINA_FALSE;
+   sh->state_args = eina_inlist_sorted_state_new();
+   EINA_MAGIC_SET(sh, EDBUS_SIGNAL_HANDLER_MAGIC);
+
+   edbus_connection_signal_handler_add(conn, sh);
+   return sh;
+
+cleanup:
+   eina_strbuf_free(match);
+cleanup_create_strbuf:
+   free(sh);
+
+   return NULL;
+}
+
+static Eina_Bool
+signal_handler_deleter(void *data)
+{
+   EDBus_Signal_Handler *handler = data;
+   _edbus_signal_handler_del(handler);
+   return ECORE_CALLBACK_CANCEL;
+}
+
+static void
+_edbus_signal_handler_clean(EDBus_Signal_Handler *handler)
+{
+   DBusError err;
+
+   if (handler->dangling) return;
+
+   edbus_connection_signal_handler_del(handler->conn, handler);
+   if (handler->bus)
+     edbus_connection_name_owner_monitor(handler->conn, handler->bus,
+                                         EINA_FALSE);
+   dbus_error_init(&err);
+   dbus_bus_remove_match(handler->conn->dbus_conn,
+                         eina_strbuf_string_get(handler->match), &err);
+   handler->dangling = EINA_TRUE;
+}
+
+static void
+_edbus_signal_handler_del(EDBus_Signal_Handler *handler)
+{
+   Eina_Inlist *list;
+   Signal_Argument *arg;
+   DBG("handler %p, refcount=%d, conn=%p %s",
+       handler, handler->refcount, handler->conn, handler->sender);
+   edbus_cbs_free_dispatch(&(handler->cbs_free), handler);
+   EINA_MAGIC_SET(handler, EINA_MAGIC_NONE);
+
+   /* after cbs_free dispatch these shouldn't exit, error if they do */
+
+   eina_stringshare_del(handler->sender);
+   eina_stringshare_del(handler->path);
+   eina_stringshare_del(handler->interface);
+   eina_stringshare_del(handler->member);
+   eina_strbuf_free(handler->match);
+   EINA_INLIST_FOREACH_SAFE(handler->args, list, arg)
+     {
+        eina_stringshare_del(arg->value);
+        free(arg);
+     }
+   eina_inlist_sorted_state_free(handler->state_args);
+   free(handler);
+}
+
+EAPI EDBus_Signal_Handler *
+edbus_signal_handler_ref(EDBus_Signal_Handler *handler)
+{
+   EDBUS_SIGNAL_HANDLER_CHECK_RETVAL(handler, NULL);
+   DBG("handler=%p, pre-refcount=%d, match=%s",
+       handler, handler->refcount, eina_strbuf_string_get(handler->match));
+   handler->refcount++;
+   return handler;
+}
+
+EAPI void
+edbus_signal_handler_unref(EDBus_Signal_Handler *handler)
+{
+   EDBUS_SIGNAL_HANDLER_CHECK(handler);
+   DBG("handler=%p, pre-refcount=%d, match=%s",
+       handler, handler->refcount, eina_strbuf_string_get(handler->match));
+   handler->refcount--;
+   if (handler->refcount > 0) return;
+
+   _edbus_signal_handler_clean(handler);
+
+   if (handler->conn->running_signal)
+     ecore_idler_add(signal_handler_deleter, handler);
+   else
+     _edbus_signal_handler_del(handler);
+}
+
+EAPI void
+edbus_signal_handler_del(EDBus_Signal_Handler *handler)
+{
+   EDBUS_SIGNAL_HANDLER_CHECK(handler);
+   _edbus_signal_handler_clean(handler);
+   edbus_signal_handler_unref(handler);
+}
+
+EAPI void
+edbus_signal_handler_cb_free_add(EDBus_Signal_Handler *handler, EDBus_Free_Cb cb, const void *data)
+{
+   EDBUS_SIGNAL_HANDLER_CHECK(handler);
+   EINA_SAFETY_ON_NULL_RETURN(cb);
+   handler->cbs_free = edbus_cbs_free_add(handler->cbs_free, cb, data);
+}
+
+EAPI void
+edbus_signal_handler_cb_free_del(EDBus_Signal_Handler *handler, EDBus_Free_Cb cb, const void *data)
+{
+   EDBUS_SIGNAL_HANDLER_CHECK(handler);
+   EINA_SAFETY_ON_NULL_RETURN(cb);
+   handler->cbs_free = edbus_cbs_free_del(handler->cbs_free, cb, data);
+}
+
+EAPI const char *
+edbus_signal_handler_sender_get(const EDBus_Signal_Handler *handler)
+{
+   EDBUS_SIGNAL_HANDLER_CHECK_RETVAL(handler, NULL);
+   return handler->sender;
+}
+
+EAPI const char *
+edbus_signal_handler_path_get(const EDBus_Signal_Handler *handler)
+{
+   EDBUS_SIGNAL_HANDLER_CHECK_RETVAL(handler, NULL);
+   return handler->path;
+}
+
+EAPI const char *
+edbus_signal_handler_interface_get(const EDBus_Signal_Handler *handler)
+{
+   EDBUS_SIGNAL_HANDLER_CHECK_RETVAL(handler, NULL);
+   return handler->interface;
+}
+
+EAPI const char *
+edbus_signal_handler_member_get(const EDBus_Signal_Handler *handler)
+{
+   EDBUS_SIGNAL_HANDLER_CHECK_RETVAL(handler, NULL);
+   return handler->member;
+}
+
+EAPI const char *
+edbus_signal_handler_match_get(const EDBus_Signal_Handler *handler)
+{
+   EDBUS_SIGNAL_HANDLER_CHECK_RETVAL(handler, NULL);
+   return eina_strbuf_string_get(handler->match);
+}
+
+EAPI EDBus_Connection *
+edbus_signal_handler_connection_get(const EDBus_Signal_Handler *handler)
+{
+   EDBUS_SIGNAL_HANDLER_CHECK_RETVAL(handler, NULL);
+   return handler->conn;
+}
+
diff --git a/src/lib/edbus_signal_handler.h b/src/lib/edbus_signal_handler.h
new file mode 100644 (file)
index 0000000..8be91be
--- /dev/null
@@ -0,0 +1,92 @@
+#ifndef EDBUS_SIGNAL_HANDLER_H
+#define EDBUS_SIGNAL_HANDLER_H 1
+
+/**
+ * @defgroup EDBus_Signal_Handler Signal Handler
+ *
+ * @{
+ */
+/**
+ * @brief Add a signal handler.
+ *
+ * @param conn connection where the signal is emitted
+ * @param sender bus name or unique id of where the signal is emitted
+ * @param path path of remote object
+ * @param interface that signal belongs
+ * @param member name of the signal
+ * @param cb callback that will be called when this signal is received
+ * @param cb_data data that will be passed to callback
+ */
+EAPI EDBus_Signal_Handler *edbus_signal_handler_add(EDBus_Connection *conn, const char *sender, const char *path, const char *interface, const char *member, EDBus_Signal_Cb cb, const void *cb_data) EINA_ARG_NONNULL(1, 6);
+
+/**
+ * @brief Increase signal handler reference.
+ */
+EAPI EDBus_Signal_Handler *edbus_signal_handler_ref(EDBus_Signal_Handler *handler) EINA_ARG_NONNULL(1);
+/**
+ * @brief Decrease signal handler reference.
+ * If reference == 0 signal handler will be freed.
+ */
+EAPI void                  edbus_signal_handler_unref(EDBus_Signal_Handler *handler) EINA_ARG_NONNULL(1);
+/**
+ * @brief Decrease signal handler reference like edbus_signal_handler_unref()
+ * but if reference > 0 this signal handler will stop listening to signals. In other
+ * words it will be canceled but memory will not be freed.
+ */
+EAPI void                  edbus_signal_handler_del(EDBus_Signal_Handler *handler) EINA_ARG_NONNULL(1);
+/**
+ * @brief Add extra argument in match of signal handler to obtain specifics signals.
+ *
+ * Example:
+ * edbus_signal_handler_match_extra_set(sh, "arg0", "org.bansheeproject.Banshee", "arg1", "", NULL);
+ * With this extra arguments this signal handler callback only will be called
+ * when Banshee is started.
+ *
+ * @note For now only argX is supported.
+ *
+ * @param sh signal handler
+ * @param ... variadic of key and value and must be ended with a NULL
+ *
+ * @note For more information:
+ * http://dbus.freedesktop.org/doc/dbus-specification.html#message-bus-routing-match-rules
+ */
+EAPI Eina_Bool             edbus_signal_handler_match_extra_set(EDBus_Signal_Handler *sh, ...) EINA_ARG_NONNULL(1) EINA_SENTINEL;
+/**
+ * @brief Add extra argument in match of signal handler to obtain specifics signals.
+ *
+ * Example:
+ * edbus_signal_handler_match_extra_set(sh, "arg0", "org.bansheeproject.Banshee", "arg1", "", NULL);
+ * With this extra arguments this signal handler callback only will be called
+ * when Banshee is started.
+ *
+ * @note For now is only supported argX.
+ *
+ * @param sh signal handler
+ * @param ap va_list with the keys and values, must be ended with a NULL
+ *
+ * @note To information:
+ * http://dbus.freedesktop.org/doc/dbus-specification.html#message-bus-routing-match-rules
+ */
+EAPI Eina_Bool             edbus_signal_handler_match_extra_vset(EDBus_Signal_Handler *sh, va_list ap);
+
+/**
+ * @brief Add a callback function to be called when signal handler will be freed.
+ */
+EAPI void                  edbus_signal_handler_cb_free_add(EDBus_Signal_Handler *handler, EDBus_Free_Cb cb, const void *data) EINA_ARG_NONNULL(1, 2);
+/**
+ * @brief Remove callback registered in edbus_signal_handler_cb_free_add().
+ */
+EAPI void                  edbus_signal_handler_cb_free_del(EDBus_Signal_Handler *handler, EDBus_Free_Cb cb, const void *data) EINA_ARG_NONNULL(1, 2);
+
+EAPI const char           *edbus_signal_handler_sender_get(const EDBus_Signal_Handler *handler) EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT;
+EAPI const char           *edbus_signal_handler_path_get(const EDBus_Signal_Handler *handler) EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT;
+EAPI const char           *edbus_signal_handler_interface_get(const EDBus_Signal_Handler *handler) EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT;
+EAPI const char           *edbus_signal_handler_member_get(const EDBus_Signal_Handler *handler) EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT;
+EAPI const char           *edbus_signal_handler_match_get(const EDBus_Signal_Handler *handler) EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT;
+
+EAPI EDBus_Connection     *edbus_signal_handler_connection_get(const EDBus_Signal_Handler *handler) EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT;
+
+/**
+ * @}
+ */
+#endif