diff --git a/legacy/edbus/.gitignore b/legacy/edbus/.gitignore new file mode 100644 index 0000000000..9a1f4e2a60 --- /dev/null +++ b/legacy/edbus/.gitignore @@ -0,0 +1,43 @@ +*.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.* +edbus.pc +libedbus.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/client +doc/Doxyfile +doc/html/ +doc/latex/ +doc/man/ diff --git a/legacy/edbus/AUTHORS b/legacy/edbus/AUTHORS new file mode 100644 index 0000000000..0306d257ea --- /dev/null +++ b/legacy/edbus/AUTHORS @@ -0,0 +1,4 @@ +Gustavo Sverzut Barbieri +José Roberto de Souza +Leandro Pereira +Lucas De Marchi diff --git a/legacy/edbus/Makefile.am b/legacy/edbus/Makefile.am new file mode 100644 index 0000000000..6ff713c3fd --- /dev/null +++ b/legacy/edbus/Makefile.am @@ -0,0 +1,120 @@ +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 = edbus.pc +CLEANFILES += edbus.pc +EXTRA_DIST += edbus.pc.in + +EXTRA_DIST += \ + 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 = libedbus.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 + +libedbus_la_LIBADD = @ECORE_LIBS@ @DBUS_LIBS@ +libedbus_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 + +noinst_PROGRAMS = \ + 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 + +EXAMPLES_LIBS = libedbus.la @ECORE_LIBS@ + +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) + +.PHONY: doc + +# Documentation + +doc: + @echo "entering doc/" + make -C doc doc diff --git a/legacy/edbus/autogen.sh b/legacy/edbus/autogen.sh new file mode 100755 index 0000000000..b43d1715ee --- /dev/null +++ b/legacy/edbus/autogen.sh @@ -0,0 +1,7 @@ +#!/bin/sh + +autoreconf -f -i + +if [ -z "$NOCONFIGURE" ]; then + ./configure "$@" +fi diff --git a/legacy/edbus/configure.ac b/legacy/edbus/configure.ac new file mode 100644 index 0000000000..e203746353 --- /dev/null +++ b/legacy/edbus/configure.ac @@ -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/legacy/edbus/doc/Doxyfile.in b/legacy/edbus/doc/Doxyfile.in new file mode 100644 index 0000000000..a5750e324f --- /dev/null +++ b/legacy/edbus/doc/Doxyfile.in @@ -0,0 +1,227 @@ +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_DIRECTORIES = 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 = ../src/lib \ + ./examples.dox +INPUT_ENCODING = UTF-8 +FILE_PATTERNS = +RECURSIVE = YES +EXCLUDE = +EXCLUDE_SYMLINKS = NO +EXCLUDE_PATTERNS = +EXCLUDE_SYMBOLS = +EXAMPLE_PATH = ../src/examples/ +EXAMPLE_PATTERNS = +EXAMPLE_RECURSIVE = YES +IMAGE_PATH = ../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 = ./head.html +HTML_FOOTER = ./foot.html +HTML_STYLESHEET = ./e.css +HTML_COLORSTYLE_HUE = 220 +HTML_COLORSTYLE_SAT = 100 +HTML_COLORSTYLE_GAMMA = 80 +HTML_TIMESTAMP = YES +HTML_ALIGN_MEMBERS = 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 +USE_INLINE_TREES = 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 \ No newline at end of file diff --git a/legacy/edbus/doc/Makefile.am b/legacy/edbus/doc/Makefile.am new file mode 100644 index 0000000000..3c2eba92a6 --- /dev/null +++ b/legacy/edbus/doc/Makefile.am @@ -0,0 +1,32 @@ +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 = Doxyfile.in $(wildcard images/*.*) e.css head.html foot.html diff --git a/legacy/edbus/doc/e.css b/legacy/edbus/doc/e.css new file mode 100644 index 0000000000..8697a3a0be --- /dev/null +++ b/legacy/edbus/doc/e.css @@ -0,0 +1,218 @@ +/* + Author: + Andres Blanc + DaveMDS Andreoli + + 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/legacy/edbus/doc/examples.dox b/legacy/edbus/doc/examples.dox new file mode 100644 index 0000000000..14b4ba343a --- /dev/null +++ b/legacy/edbus/doc/examples.dox @@ -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/legacy/edbus/doc/foot.html b/legacy/edbus/doc/foot.html new file mode 100644 index 0000000000..78ef911c72 --- /dev/null +++ b/legacy/edbus/doc/foot.html @@ -0,0 +1,19 @@ + +
+ + + + + + + + + + + diff --git a/legacy/edbus/doc/head.html b/legacy/edbus/doc/head.html new file mode 100644 index 0000000000..2d841f12c9 --- /dev/null +++ b/legacy/edbus/doc/head.html @@ -0,0 +1,67 @@ + + + $title + + + + + + + + + + + + + + +
+ + + +
+
diff --git a/legacy/edbus/doc/images/e.png b/legacy/edbus/doc/images/e.png new file mode 100644 index 0000000000..b3884a5cbc Binary files /dev/null and b/legacy/edbus/doc/images/e.png differ diff --git a/legacy/edbus/doc/images/edoxy.css b/legacy/edbus/doc/images/edoxy.css new file mode 100644 index 0000000000..3caf7a9736 --- /dev/null +++ b/legacy/edbus/doc/images/edoxy.css @@ -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/legacy/edbus/doc/images/foot_bg.png b/legacy/edbus/doc/images/foot_bg.png new file mode 100644 index 0000000000..b24f3a48b4 Binary files /dev/null and b/legacy/edbus/doc/images/foot_bg.png differ diff --git a/legacy/edbus/doc/images/head_bg.png b/legacy/edbus/doc/images/head_bg.png new file mode 100644 index 0000000000..081dc131e4 Binary files /dev/null and b/legacy/edbus/doc/images/head_bg.png differ diff --git a/legacy/edbus/doc/images/menu_bg.png b/legacy/edbus/doc/images/menu_bg.png new file mode 100644 index 0000000000..e978743651 Binary files /dev/null and b/legacy/edbus/doc/images/menu_bg.png differ diff --git a/legacy/edbus/doc/images/menu_bg_current.png b/legacy/edbus/doc/images/menu_bg_current.png new file mode 100644 index 0000000000..de97c9268e Binary files /dev/null and b/legacy/edbus/doc/images/menu_bg_current.png differ diff --git a/legacy/edbus/doc/images/menu_bg_hover.png b/legacy/edbus/doc/images/menu_bg_hover.png new file mode 100644 index 0000000000..3fd851d075 Binary files /dev/null and b/legacy/edbus/doc/images/menu_bg_hover.png differ diff --git a/legacy/edbus/doc/images/menu_bg_last.png b/legacy/edbus/doc/images/menu_bg_last.png new file mode 100644 index 0000000000..88c116c8c8 Binary files /dev/null and b/legacy/edbus/doc/images/menu_bg_last.png differ diff --git a/legacy/edbus/doc/images/menu_bg_unsel.png b/legacy/edbus/doc/images/menu_bg_unsel.png new file mode 100644 index 0000000000..50e5fd8d3d Binary files /dev/null and b/legacy/edbus/doc/images/menu_bg_unsel.png differ diff --git a/legacy/edbus/edbus.pc.in b/legacy/edbus/edbus.pc.in new file mode 100644 index 0000000000..7842ec8969 --- /dev/null +++ b/legacy/edbus/edbus.pc.in @@ -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} -ledbus +Cflags: -I${includedir} diff --git a/legacy/edbus/m4/ac_attribute.m4 b/legacy/edbus/m4/ac_attribute.m4 new file mode 100644 index 0000000000..23479a92ac --- /dev/null +++ b/legacy/edbus/m4/ac_attribute.m4 @@ -0,0 +1,47 @@ +dnl Copyright (C) 2004-2008 Kim Woelders +dnl Copyright (C) 2008 Vincent Torri +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 + +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/legacy/edbus/m4/ac_valist.m4 b/legacy/edbus/m4/ac_valist.m4 new file mode 100644 index 0000000000..a4d6a24932 --- /dev/null +++ b/legacy/edbus/m4/ac_valist.m4 @@ -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 +#include +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/legacy/edbus/m4/efl_compiler_flag.m4 b/legacy/edbus/m4/efl_compiler_flag.m4 new file mode 100644 index 0000000000..e3fc8217b8 --- /dev/null +++ b/legacy/edbus/m4/efl_compiler_flag.m4 @@ -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/legacy/edbus/m4/efl_doxygen.m4 b/legacy/edbus/m4/efl_doxygen.m4 new file mode 100644 index 0000000000..7324af3e42 --- /dev/null +++ b/legacy/edbus/m4/efl_doxygen.m4 @@ -0,0 +1,94 @@ +dnl Copyright (C) 2008 Vincent Torri +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/legacy/edbus/src/examples/banshee.c b/legacy/edbus/src/examples/banshee.c new file mode 100644 index 0000000000..2134c26028 --- /dev/null +++ b/legacy/edbus/src/examples/banshee.c @@ -0,0 +1,293 @@ +#include "EDBus.h" +#include + +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 +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("on_name_owner_changed_by_id bus = %s older=%s new=%s\n\n", + bus, older_id, new_id); + + if (!new_id[0]) + edbus_signal_handler_unref(sh3); +} + +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); + + if (new_id[0]) + { + 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, "arg1", new_id, NULL); + } +} + +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"); + + 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); + + 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/legacy/edbus/src/examples/client.c b/legacy/edbus/src/examples/client.c new file mode 100644 index 0000000000..80ae728e72 --- /dev/null +++ b/legacy/edbus/src/examples/client.c @@ -0,0 +1,255 @@ +#include "EDBus.h" +#include + +#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); +} + +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, ""); + + ecore_main_loop_begin(); + + edbus_connection_unref(conn); + + edbus_shutdown(); + ecore_shutdown(); + return 0; +} diff --git a/legacy/edbus/src/examples/complex_types.c b/legacy/edbus/src/examples/complex_types.c new file mode 100644 index 0000000000..4cdcf211d7 --- /dev/null +++ b/legacy/edbus/src/examples/complex_types.c @@ -0,0 +1,257 @@ +#include "EDBus.h" +#include + +#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 *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_append_basic(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_append_basic(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); + + 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(5, _timer1_cb, NULL); + + ecore_main_loop_begin(); + + edbus_connection_unref(conn); + + edbus_shutdown(); + ecore_shutdown(); + return 0; +} diff --git a/legacy/edbus/src/examples/complex_types_server.c b/legacy/edbus/src/examples/complex_types_server.c new file mode 100644 index 0000000000..5acd50e52f --- /dev/null +++ b/legacy/edbus/src/examples/complex_types_server.c @@ -0,0 +1,351 @@ +#include "EDBus.h" +#include + +#define BUS "com.profusion" +#define PATH "/com/profusion/Test" +#define IFACE "com.profusion.Test" + +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; + char 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 * +_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_append_basic(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"}), + EDBUS_ARGS({"", ""}), _receive_array, 0 + }, + { + "ReceiveArrayOfStringIntWithSize", + EDBUS_ARGS({"i", "size_of_array"}, {"a(si)", "array"}), + EDBUS_ARGS({"", ""}), _receive_array_of_string_int_with_size, 0 + }, + { + "SendVariantData", EDBUS_ARGS({"v", "variant_data"}), + EDBUS_ARGS({"", ""}), _send_variant, 0 + }, + { + "SendArrayInt", EDBUS_ARGS({"", ""}), + EDBUS_ARGS({"ai", "array_of_int"}), _send_array_int, 0 + }, + { + "SendArray", EDBUS_ARGS({"", ""}), EDBUS_ARGS({"as", "array_string"}), + _send_array, 0 + }, + { + "PlusOne", EDBUS_ARGS({"i", "integer"}), + EDBUS_ARGS({"i", "integer_plus_one"}), _plus_one, 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"}), + EDBUS_ARGS({"", ""}), _properties_set, 0 + }, + { } +}; + +static void +on_name_request(void *data, const EDBus_Message *msg, EDBus_Pending *pending) +{ + EDBus_Connection *conn = data; + 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; + } + + edbus_service_interface_register(conn, PATH, IFACE, methods, NULL); + edbus_service_interface_register(conn, PATH, EDBUS_FDO_INTERFACE_PROPERTIES, properties_methods, NULL); +} + +int +main(void) +{ + EDBus_Connection *conn; + + ecore_init(); + edbus_init(); + + conn = edbus_connection_get(EDBUS_CONNECTION_TYPE_SESSION); + + edbus_name_request(conn, BUS, EDBUS_NAME_REQUEST_FLAG_DO_NOT_QUEUE, on_name_request, conn); + + ecore_main_loop_begin(); + + free(resp2); + edbus_connection_unref(conn); + + edbus_shutdown(); + ecore_shutdown(); + return 0; +} diff --git a/legacy/edbus/src/examples/connman-list-services.c b/legacy/edbus/src/examples/connman-list-services.c new file mode 100644 index 0000000000..a192d8b506 --- /dev/null +++ b/legacy/edbus/src/examples/connman-list-services.c @@ -0,0 +1,107 @@ +#include "EDBus.h" +#include + +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/legacy/edbus/src/examples/ofono-dial.c b/legacy/edbus/src/examples/ofono-dial.c new file mode 100644 index 0000000000..5e833ddc4b --- /dev/null +++ b/legacy/edbus/src/examples/ofono-dial.c @@ -0,0 +1,85 @@ +#include "EDBus.h" +#include + +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 [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/legacy/edbus/src/examples/server.c b/legacy/edbus/src/examples/server.c new file mode 100644 index 0000000000..06424b393a --- /dev/null +++ b/legacy/edbus/src/examples/server.c @@ -0,0 +1,236 @@ +#include "EDBus.h" +#include + +#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", EDBUS_ARGS({ NULL, NULL }), 0}, + [TEST_SIGNAL_HELLO] = {"Hello", EDBUS_ARGS({ "s", "message" }), 0}, + { } +}; + +static const EDBus_Method methods[] = { + { + "Hello", EDBUS_ARGS({"", ""}), EDBUS_ARGS({"s", "message"}), + _hello, 0 + }, + { + "Quit", EDBUS_ARGS({"", ""}), EDBUS_ARGS({"", ""}), + _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", EDBUS_ARGS({"", ""}), EDBUS_ARGS({"s", "text"}), + _async_test, 0 + }, + { } +}; + +static void +on_name_request(void *data, const EDBus_Message *msg, EDBus_Pending *pending) +{ + EDBus_Service_Interface *iface; + unsigned int flag; + + 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; + } + + iface = edbus_service_interface_register(conn, PATH, INTERFACE, methods, + signals); + ecore_timer_add(5, send_signal_alive, iface); + ecore_timer_add(6, send_signal_hello, iface); +} + +int +main(void) +{ + ecore_init(); + edbus_init(); + + conn = edbus_connection_get(EDBUS_CONNECTION_TYPE_SESSION); + + edbus_name_request(conn, BUS, EDBUS_NAME_REQUEST_FLAG_DO_NOT_QUEUE, + on_name_request, NULL); + + ecore_main_loop_begin(); + + edbus_connection_unref(conn); + + edbus_shutdown(); + ecore_shutdown(); + return 0; +} diff --git a/legacy/edbus/src/lib/EDBus.h b/legacy/edbus/src/lib/EDBus.h new file mode 100644 index 0000000000..66b5320390 --- /dev/null +++ b/legacy/edbus/src/lib/EDBus.h @@ -0,0 +1,141 @@ +#ifndef EDBUS_H +#define EDBUS_H + +#include +#include + +#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 a object path already attach with bus name or unique id. + */ +typedef struct _EDBus_Object EDBus_Object; +/** + * @typedef EDBus_Proxy + * + * Represents a interface of a object path. + */ +typedef struct _EDBus_Proxy EDBus_Proxy; +/** + * @typedef EDBus_Message + * + * Represents the way of how the data is send 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 was 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/legacy/edbus/src/lib/edbus_connection.h b/legacy/edbus/src/lib/edbus_connection.h new file mode 100644 index 0000000000..955ffd7f09 --- /dev/null +++ b/legacy/edbus/src/lib/edbus_connection.h @@ -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 object 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 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 are stored + * @param key that identify 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 are stored + * @param key that identify 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 occurs a event 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 send + * @param msg message that will be send + * @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 + */ +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/legacy/edbus/src/lib/edbus_core.c b/legacy/edbus/src/lib/edbus_core.c new file mode 100644 index 0000000000..4fec737dbd --- /dev/null +++ b/legacy/edbus/src/lib/edbus_core.c @@ -0,0 +1,1368 @@ +#include "edbus_private.h" +#include "edbus_private_types.h" +#include + +#include + +#define NAME_OWNER_MATCH "type='signal',sender='org.freedesktop.DBus',\ + path='/org/freedesktop/DBus',interface='org.freedesktop.DBus',\ + member='NameOwnerChanged',arg0='%s'" + +#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; +} 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"); + + 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) +{ + char *bus, *older_id, *new_id; + const char *name, *text; + EDBus_Connection_Name *cn = data; + + if (edbus_message_error_get(msg, &name, &text)) + ERR("NameOwnerChanged cn=%s name=%s text=%s", + cn->name, name, text); + if (!edbus_message_arguments_get(msg, "sss", &bus, &older_id, &new_id)) + ERR("Error getting arguments from NameOwnerChanged cn=%s", cn->name); + + 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, ""); +} + +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); + 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; + cn->event_handlers.walking++; + EINA_INLIST_FOREACH(cn->event_handlers.list, ctx) + { + if (ctx->deleted) continue; + ctx->cb((void *)ctx->cb_data, cn->name, old_id, cn->unique_id); + } + cn->event_handlers.walking--; +} + +EAPI void +edbus_name_owner_changed_callback_add(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 *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; + + cn->event_handlers.list = eina_inlist_append(cn->event_handlers.list, + EINA_INLIST_GET(ctx)); + 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)); + 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/legacy/edbus/src/lib/edbus_freedesktop.c b/legacy/edbus/src/lib/edbus_freedesktop.c new file mode 100644 index 0000000000..0247bffeef --- /dev/null +++ b/legacy/edbus/src/lib/edbus_freedesktop.c @@ -0,0 +1,80 @@ +#include "edbus_private.h" +#include "edbus_private_types.h" +#include + +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/legacy/edbus/src/lib/edbus_freedesktop.h b/legacy/edbus/src/lib/edbus_freedesktop.h new file mode 100644 index 0000000000..1bdfddd277 --- /dev/null +++ b/legacy/edbus/src/lib/edbus_freedesktop.h @@ -0,0 +1,126 @@ +#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); + +EAPI void edbus_name_owner_changed_callback_add(EDBus_Connection *conn, const char *bus, EDBus_Name_Owner_Changed_Cb cb, const void *cb_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 + * + * Whenever edbus_proxy_properties_monitor() is called on a + * proxy to an object it will automatically listen for properties + * changed on that interface, emitting events with + * edbus_object_event_type being + * #EDBUS_OBJECT_EVENT_PROPERTY_CHANGED and + * #EDBUS_OBJECT_EVENT_PROPERTY_REMOVED, as well as + * #EDBUS_PROXY_EVENT_PROPERTY_CHANGED and + * #EDBUS_PROXY_EVENT_PROPERTY_REMOVED. + * + * One may manually query the properties + * edbus_proxy_property_get() and edbus_proxy_property_get_all() + * or listen for changes with + * edbus_proxy_properties_changed_callback_add(). + * + * To set property call edbus_proxy_property_set(). + * + * @{ + */ +EAPI void edbus_proxy_properties_monitor(EDBus_Proxy *proxy); + +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_Message_Cb cb, const void *data) EINA_ARG_NONNULL(1, 2); +/** + * @} + */ + +/** + * @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/legacy/edbus/src/lib/edbus_message.c b/legacy/edbus/src/lib/edbus_message.c new file mode 100644 index 0000000000..0b77ad5f91 --- /dev/null +++ b/legacy/edbus/src/lib/edbus_message.c @@ -0,0 +1,792 @@ +#include "edbus_private.h" +#include "edbus_private_types.h" +#include +#include + +/* 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(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; + + 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)) && r) + { + 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 (!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: + case DBUS_TYPE_UNIX_FD: + { + 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 || !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)) && r) + { + if (dbus_type_is_basic(type[0])) + r = append_basic(type[0], MAKE_PTR_FROM_VA_LIST(ap), + &iter->dbus_iterator); + else + { + ERR("edbus_message_arguments_set() and \ + edbus_message_arguments_vset() only support basic types, \ + to complex types use edbus_message_iter_* functions"); + r = EINA_FALSE; + } + + dbus_free(type); + if (!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_append_basic(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_get_basic(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); +} + +EAPI char* +edbus_message_iter_signature_get(EDBus_Message_Iter *iter) +{ + 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: + case DBUS_TYPE_UNIX_FD: + { + 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); + EINA_SAFETY_ON_FALSE_RETURN_VAL(c == current_type, 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/legacy/edbus/src/lib/edbus_message.h b/legacy/edbus/src/lib/edbus_message.h new file mode 100644 index 0000000000..1aa0bacd45 --- /dev/null +++ b/legacy/edbus/src/lib/edbus_message.h @@ -0,0 +1,276 @@ +#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 your children's. + */ +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 must have + * a pointer to store his value, in case of complex type a + * EDBus_Message_Iter will 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 must have + * a pointer to store his value, in case of complex type a + * EDBus_Message_Iter will be need. + */ +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 support basic type from complex type 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 support basic type from complex type 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_append_basic(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(EDBus_Message *msg) EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT; +/** + * @brief Get a basic type from EDBus_Iterator. + */ +EAPI void edbus_message_iter_get_basic(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); +/** + * @} + */ +/** + * @} + */ +#endif diff --git a/legacy/edbus/src/lib/edbus_object.c b/legacy/edbus/src/lib/edbus_object.c new file mode 100644 index 0000000000..0297ff59a2 --- /dev/null +++ b/legacy/edbus/src/lib/edbus_object.c @@ -0,0 +1,467 @@ +#include "edbus_private.h" +#include "edbus_private_types.h" +#include + +/* 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 +_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; + 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); + } + + if (obj->signal_handlers) + { + EDBus_Signal_Handler *h; + CRITICAL("Object %p released with live signal handlers!", obj); + EINA_LIST_FREE (obj->signal_handlers, h) + 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/legacy/edbus/src/lib/edbus_object.h b/legacy/edbus/src/lib/edbus_object.h new file mode 100644 index 0000000000..d663eba165 --- /dev/null +++ b/legacy/edbus/src/lib/edbus_object.h @@ -0,0 +1,117 @@ +#ifndef EDBUS_OBJECT_H +#define EDBUS_OBJECT_H 1 + +/** + * @defgroup EDBus_Object_Mapper Object Mapper + * + * @{ + */ +/** + * @brief Get a object of the following bus and path. + * + * @param conn connection where object belongs + * @param bus name of bus or unique-id of who listen 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 your children's. + */ +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 know when it will be free + * @param cb callback that will be execute + * @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 occurs a event of the + * type passed. + */ +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 send in connection that obj belongs + * @param msg message that will be send + * @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 + */ +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/legacy/edbus/src/lib/edbus_pending.c b/legacy/edbus/src/lib/edbus_pending.c new file mode 100644 index 0000000000..6dba8103da --- /dev/null +++ b/legacy/edbus/src/lib/edbus_pending.c @@ -0,0 +1,260 @@ +#include "edbus_private.h" +#include "edbus_private_types.h" +#include + +/* 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/legacy/edbus/src/lib/edbus_pending.h b/legacy/edbus/src/lib/edbus_pending.h new file mode 100644 index 0000000000..d0071ffb29 --- /dev/null +++ b/legacy/edbus/src/lib/edbus_pending.h @@ -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/legacy/edbus/src/lib/edbus_private.h b/legacy/edbus/src/lib/edbus_private.h new file mode 100644 index 0000000000..8fef5998cb --- /dev/null +++ b/legacy/edbus/src/lib/edbus_private.h @@ -0,0 +1,81 @@ +#ifndef EDBUS_PRIVATE_H +#define EDBUS_PRIVATE_H + +#include +#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); + +#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/legacy/edbus/src/lib/edbus_private_types.h b/legacy/edbus/src/lib/edbus_private_types.h new file mode 100644 index 0000000000..74ca939412 --- /dev/null +++ b/legacy/edbus/src/lib/edbus_private_types.h @@ -0,0 +1,168 @@ +#ifndef EDBUS_PRIVATE_TYPES_H +#define EDBUS_PRIVATE_TYPES_H 1 + +#include "EDBus.h" +#include +#include +#include + +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; + +typedef struct _EDBus_Real_Method +{ + const EDBus_Method *method; + const char *in; +} EDBus_Real_Method; + +#endif diff --git a/legacy/edbus/src/lib/edbus_proxy.c b/legacy/edbus/src/lib/edbus_proxy.c new file mode 100644 index 0000000000..2f54b7dff2 --- /dev/null +++ b/legacy/edbus/src/lib/edbus_proxy.c @@ -0,0 +1,542 @@ +#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]; +}; + +#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 +_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); + proxy->refcount = 0; +} + +static void +_edbus_proxy_free(EDBus_Proxy *proxy) +{ + unsigned int i; + if (proxy->handlers) + { + EDBus_Signal_Handler *h; + CRITICAL("Proxy %p released with live signal handlers!", proxy); + EINA_LIST_FREE (proxy->handlers, h) + 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); +} + +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)); +} + +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); +} + +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_append_basic(iter, 's', proxy->interface); + edbus_message_iter_append_basic(iter, 's', name); + variant = edbus_message_iter_container_new(iter, 'v', sig); + edbus_message_iter_append_basic(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); +} diff --git a/legacy/edbus/src/lib/edbus_proxy.h b/legacy/edbus/src/lib/edbus_proxy.h new file mode 100644 index 0000000000..ff4403c714 --- /dev/null +++ b/legacy/edbus/src/lib/edbus_proxy.h @@ -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's. + */ +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_connection_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/legacy/edbus/src/lib/edbus_service.c b/legacy/edbus/src/lib/edbus_service.c new file mode 100644 index 0000000000..bbc8c0a907 --- /dev/null +++ b/legacy/edbus/src/lib/edbus_service.c @@ -0,0 +1,616 @@ +#include "edbus_private_types.h" +#include "edbus_private.h" + +#define DBUS_ANNOTATION(name, 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 +_instrospect_append_signal(Eina_Strbuf *buf, const EDBus_Signal *sig) +{ + int i; + const char *part, *name; + + eina_strbuf_append_printf(buf, "", 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, "", + part, name); + else + eina_strbuf_append_printf(buf, "", part); + } + eina_strbuf_append(buf, ""); +} + +static void +_introspect_append_method(Eina_Strbuf *buf, const EDBus_Method *method) +{ + int i; + const char *part, *name; + + eina_strbuf_append_printf(buf, "", 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, + "", + part, name); + else + eina_strbuf_append_printf(buf, "", + 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, + "", + part, name); + else + eina_strbuf_append_printf(buf, "", + part); + } + eina_strbuf_append(buf, ""); +} + +static void +_introspect_append_interface(Eina_Strbuf *buf, EDBus_Service_Interface *iface) +{ + EDBus_Real_Method *method; + Eina_Iterator *iterator; + unsigned short i; + unsigned int size; + + eina_strbuf_append_printf(buf, "", iface->name); + iterator = eina_hash_iterator_data_new(iface->methods); + EINA_ITERATOR_FOREACH(iterator, method) + _introspect_append_method(buf, method->method); + eina_iterator_free(iterator); + + size = eina_array_count(iface->sign_of_signals); + for (i = 0; i < size; i++) + _instrospect_append_signal(buf, &iface->signals[i]); + + eina_strbuf_append(buf, ""); +} + +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, ""); + eina_strbuf_append_printf(obj->introspection_data, + "", 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, ""); + + obj->introspection_dirty = EINA_FALSE; + } + + edbus_message_arguments_set(reply, "s", eina_strbuf_string_get(obj->introspection_data)); + return reply; +} + +static const EDBus_Method instrospect = { "Introspect", EDBUS_ARGS({ "", "" }), + EDBUS_ARGS({ "s", "xml" }), + cb_introspect, 0 + }; + +static void +_introspectable_create(void) +{ + EDBus_Real_Method *r_instrospect; + introspectable = calloc(1, sizeof(EDBus_Service_Interface)); + EINA_SAFETY_ON_NULL_RETURN(introspectable); + + r_instrospect = malloc(sizeof(EDBus_Real_Method)); + EINA_SAFETY_ON_NULL_RETURN(r_instrospect); + r_instrospect->in = ""; + r_instrospect->method = &instrospect; + + 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, instrospect.member, r_instrospect); +} + +static void +_instrospectable_free(void) +{ + EDBus_Real_Method *method; + method = eina_hash_find(introspectable->methods, instrospect.member); + eina_stringshare_del(method->in); + free(method); + 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) +{ + _instrospectable_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 +_edbus_service_method_add(EDBus_Service_Interface *interface, EDBus_Method *method) +{ + EDBus_Real_Method *rm; + Eina_Strbuf *buf; + int z; + 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); + + buf = eina_strbuf_new(); + for (z = 0; &method->in[z] && method->in[z].signature; z++) + eina_strbuf_append(buf, method->in[z].signature); + EINA_SAFETY_ON_FALSE_GOTO( + dbus_signature_validate(eina_strbuf_string_get(buf), NULL), + error); + + rm = malloc(sizeof(EDBus_Real_Method)); + EINA_SAFETY_ON_NULL_GOTO(rm, error); + rm->method = method; + rm->in = eina_stringshare_add(eina_strbuf_string_get(buf)); + eina_strbuf_free(buf); + + //check if out is valid + buf = eina_strbuf_new(); + for (z = 0; &method->out[z] && method->out[z].signature; z++) + eina_strbuf_append(buf, method->out[z].signature); + EINA_SAFETY_ON_FALSE_GOTO( + dbus_signature_validate(eina_strbuf_string_get(buf), NULL), + invalid_out); + + eina_strbuf_free(buf); + eina_hash_add(interface->methods, method->member, rm); + return EINA_TRUE; + +invalid_out: + eina_stringshare_del(rm->in); + free(rm); +error: + eina_strbuf_free(buf); + return EINA_FALSE; +} + +EAPI EDBus_Service_Interface * +edbus_service_interface_register(EDBus_Connection *conn, const char *path, const char *interface, const EDBus_Method methods[], const EDBus_Signal signals[]) +{ + 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(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, interface); + if (!iface) + { + if (eina_hash_population(obj->interfaces) < 2) + _object_free(obj); + return NULL; + } + + for (method = (EDBus_Method *)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; &signals[i] && signals[i].name; i++) + { + buf = eina_strbuf_new(); + for (z = 0; &signals[i].args[z] && signals[i].args[z].signature; z++) + eina_strbuf_append(buf, 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, 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 = signals; + + return iface; +} + +static void +_interface_free(EDBus_Service_Interface *interface) +{ + unsigned size, i; + Eina_Iterator *iterator; + EDBus_Real_Method *method; + if (interface == introspectable) return; + + iterator = eina_hash_iterator_data_new(interface->methods); + EINA_ITERATOR_FOREACH(iterator, method) + { + eina_stringshare_del(method->in); + free(method); + } + eina_iterator_free(iterator); + 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_Real_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 (method->in && !dbus_message_has_signature(msg, method->in)) + { + char buf[DBUS_MAXIMUM_SIGNATURE_LENGTH + + sizeof("Expected signature: ")]; + snprintf(buf, sizeof(buf), "Expected signature: %s", method->in); + reply = edbus_message_error_new(edbus_msg, + DBUS_ERROR_INVALID_SIGNATURE, buf); + } + else + { + if (iface->obj) + reply = method->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->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/legacy/edbus/src/lib/edbus_service.h b/legacy/edbus/src/lib/edbus_service.h new file mode 100644 index 0000000000..0daa7d8163 --- /dev/null +++ b/legacy/edbus/src/lib/edbus_service.h @@ -0,0 +1,133 @@ +#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, { } } + +typedef struct _EDBus_Service_Interface EDBus_Service_Interface; +typedef EDBus_Message * (*EDBus_Method_Cb)(const EDBus_Service_Interface *iface, const EDBus_Message *message); + +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; + +/** + * @brief Register a interface on the passed 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 char *interface, const EDBus_Method methods[], const EDBus_Signal signals[]); +/** + * @brief Unregister a interface. + * If this is the last interface of object path, the object path will be + * remove 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 signal have 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 get 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 belong 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 belong 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/legacy/edbus/src/lib/edbus_signal_handler.c b/legacy/edbus/src/lib/edbus_signal_handler.c new file mode 100644 index 0000000000..e852ba6569 --- /dev/null +++ b/legacy/edbus/src/lib/edbus_signal_handler.c @@ -0,0 +1,340 @@ +#include "edbus_private.h" +#include "edbus_private_types.h" +#include + +/* 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 == NULL || !value[0]) 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_set(EDBus_Signal_Handler *sh, ...) +{ + va_list ap; + char *key = NULL, *value; + Signal_Argument *arg; + 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); + + va_start(ap, sh); + do + { + if (!key) + { + key = va_arg(ap, char *); + continue; + } + value = va_arg(ap, char *); + 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)-1); + arg->index = (unsigned short)id; + arg->value = eina_stringshare_add(value); + sh->args = eina_inlist_sorted_state_insert(sh->args, + EINA_INLIST_GET(arg), + _sort_arg, + sh->state_args); + _match_append(sh->match, key, value); + } + key = NULL; + } while(key); + va_end(ap); + + 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: + va_end(ap); + 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 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/legacy/edbus/src/lib/edbus_signal_handler.h b/legacy/edbus/src/lib/edbus_signal_handler.h new file mode 100644 index 0000000000..d2c0db28a9 --- /dev/null +++ b/legacy/edbus/src/lib/edbus_signal_handler.h @@ -0,0 +1,75 @@ +#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 listen signals. In other + * words 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 is only supported argX. + * + * @param sh signal handler + * @param ... variadic of key and value and 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_set(EDBus_Signal_Handler *sh, ...) EINA_ARG_NONNULL(1) EINA_SENTINEL; + +/** + * @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