[glib/gdbus: 1/6] Initial commit of GDBus work
- From: David Zeuthen <davidz src gnome org>
- To: svn-commits-list gnome org
- Subject: [glib/gdbus: 1/6] Initial commit of GDBus work
- Date: Wed, 22 Apr 2009 11:45:04 -0400 (EDT)
commit 005257dc4e433408b2b734b630cbb5ab78f0325b
Author: David Zeuthen <davidz redhat com>
Date: Mon Apr 20 01:01:11 2009 -0400
Initial commit of GDBus work
---
Makefile.am | 2 +-
configure.in | 16 +-
docs/reference/Makefile.am | 2 +-
docs/reference/gdbus/Makefile.am | 72 ++
docs/reference/gdbus/gdbus-docs.xml | 42 +
docs/reference/gdbus/gdbus-sections.txt | 70 ++
docs/reference/gdbus/gdbus.types | 5 +
docs/reference/gdbus/version.xml.in | 1 +
gdbus-2.0-uninstalled.pc.in | 6 +
gdbus-2.0.pc.in | 11 +
gdbus/Makefile.am | 195 +++++
gdbus/abicheck.sh | 13 +
gdbus/example-gbusnameowner.c | 90 +++
gdbus/gbusnameowner.c | 1244 +++++++++++++++++++++++++++++++
gdbus/gbusnameowner.h | 114 +++
gdbus/gdbus-marshal.list | 1 +
gdbus/gdbus.h | 37 +
gdbus/gdbus.symbols | 73 ++
gdbus/gdbusconnection.c | 964 ++++++++++++++++++++++++
gdbus/gdbusconnection.h | 116 +++
gdbus/gdbusenums.h | 225 ++++++
gdbus/gdbusenumtypes.c.template | 42 +
gdbus/gdbusenumtypes.h.template | 24 +
gdbus/gdbuserror.c | 507 +++++++++++++
gdbus/gdbuserror.h | 80 ++
gdbus/gdbusmainloop.c | 782 +++++++++++++++++++
gdbus/gdbusmainloop.h | 45 ++
gdbus/gdbusprivate.c | 37 +
gdbus/gdbusprivate.h | 38 +
gdbus/gdbustypes.h | 39 +
gdbus/makegdbusalias.pl | 137 ++++
gdbus/pltcheck.sh | 19 +
gdbus/tests/Makefile.am | 30 +
gdbus/tests/connection.c | 904 ++++++++++++++++++++++
34 files changed, 5980 insertions(+), 3 deletions(-)
diff --git a/Makefile.am b/Makefile.am
index 8973778..966d5c1 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -3,7 +3,7 @@ include $(top_srcdir)/Makefile.decl
AUTOMAKE_OPTIONS = 1.7
-SUBDIRS = . m4macros glib gmodule gthread gobject gio tests po docs
+SUBDIRS = . m4macros glib gmodule gthread gobject gio gdbus tests po docs
DIST_SUBDIRS = $(SUBDIRS) build
bin_SCRIPTS = glib-gettextize
diff --git a/configure.in b/configure.in
index 514fd75..77ee58d 100644
--- a/configure.in
+++ b/configure.in
@@ -10,7 +10,7 @@ m4_define(glib_configure_in)
#
# The following version number definitions apply to GLib, GModule, GObject,
-# GThread and GIO as a whole, so if changes occurred in any of them, they are
+# GThread, GIO and GDBus as a whole, so if changes occurred in any of them, they are
# all treated with the same interface and binary age.
#
# Making releases:
@@ -2631,6 +2631,14 @@ fi
AM_CONDITIONAL(ENABLE_MAN, test x$enable_man != xno)
+dnl *************************
+dnl *** Checks for dbus-1 ***
+dnl *************************
+
+PKG_CHECK_MODULES(DBUS, dbus-1)
+AC_SUBST(DBUS_CFLAGS)
+AC_SUBST(DBUS_LIBS)
+
dnl ******************************
dnl *** output the whole stuff ***
dnl ******************************
@@ -3333,6 +3341,8 @@ gio-2.0.pc
gio-unix-2.0.pc
gio-2.0-uninstalled.pc
gio-unix-2.0-uninstalled.pc
+gdbus-2.0.pc
+gdbus-2.0-uninstalled.pc
glib-zip
glib-gettextize
Makefile
@@ -3360,6 +3370,8 @@ gio/fen/Makefile
gio/fam/Makefile
gio/win32/Makefile
gio/tests/Makefile
+gdbus/Makefile
+gdbus/tests/Makefile
po/Makefile.in
docs/Makefile
docs/reference/Makefile
@@ -3369,6 +3381,8 @@ docs/reference/gobject/Makefile
docs/reference/gobject/version.xml
docs/reference/gio/Makefile
docs/reference/gio/version.xml
+docs/reference/gdbus/Makefile
+docs/reference/gdbus/version.xml
tests/Makefile
tests/gobject/Makefile
tests/refcount/Makefile
diff --git a/docs/reference/Makefile.am b/docs/reference/Makefile.am
index 63cf90d..b815cb5 100644
--- a/docs/reference/Makefile.am
+++ b/docs/reference/Makefile.am
@@ -1,3 +1,3 @@
include $(top_srcdir)/Makefile.decl
-SUBDIRS = glib gobject gio
+SUBDIRS = glib gobject gio gdbus
diff --git a/docs/reference/gdbus/Makefile.am b/docs/reference/gdbus/Makefile.am
new file mode 100644
index 0000000..f9e3086
--- /dev/null
+++ b/docs/reference/gdbus/Makefile.am
@@ -0,0 +1,72 @@
+include $(top_srcdir)/Makefile.decl
+NULL =
+
+# The name of the module.
+DOC_MODULE=gdbus
+
+# The top-level SGML file.
+DOC_MAIN_SGML_FILE=gdbus-docs.xml
+
+# Extra options to supply to gtkdoc-scan
+SCAN_OPTIONS=--deprecated-guards="G_DISABLE_DEPRECATED"
+
+#SCAN_OPTIONS+=--rebuild-sections
+
+# The directory containing the source code. Relative to $(srcdir)
+DOC_SOURCE_DIR=$(top_srcdir)/gdbus
+
+HFILE_GLOB=$(top_srcdir)/gdbus/*.h
+CFILE_GLOB=$(top_srcdir)/gdbus/*.c
+
+# Headers to ignore
+IGNORE_HFILES= \
+ gdbus-marshal.h \
+ gdbus.h \
+ gdbusalias.h \
+ gdbusalias.h \
+ gdbusenumtypes.h \
+ giomodule-priv.h \
+ $(NULL)
+
+# CFLAGS and LDFLAGS for compiling scan program. Only needed
+# if $(DOC_MODULE).types is non-empty.
+INCLUDES = \
+ -I$(srcdir) \
+ -I$(top_srcdir) \
+ -I$(top_srcdir)/glib \
+ -I$(top_srcdir)/gobject \
+ -I$(top_builddir) \
+ -I$(top_builddir)/glib \
+ -I$(top_builddir)/gobject \
+ $(GLIB_DEBUG_FLAGS)
+
+GTKDOC_LIBS = \
+ $(top_builddir)/glib/libglib-2.0.la \
+ $(top_builddir)/gobject/libgobject-2.0.la \
+ $(top_builddir)/gmodule/libgmodule-2.0.la \
+ $(top_builddir)/gio/libgio-2.0.la \
+ $(top_builddir)/gdbus/libgdbus-2.0.la \
+ $(NULL)
+
+# Extra options to supply to gtkdoc-mkdb
+MKDB_OPTIONS = --output-format=xml --sgml-mode --name-space=g
+
+# Images to copy into HTML directory
+HTML_IMAGES = \
+ $(NULL)
+
+content_files = \
+ version.xml \
+ $(NULL)
+
+expand_content_files = \
+ $(NULL)
+
+extra_files = \
+ version.xml.in \
+ $(NULL)
+
+include $(top_srcdir)/gtk-doc.make
+
+EXTRA_DIST += \
+ version.xml.in
diff --git a/docs/reference/gdbus/gdbus-docs.xml b/docs/reference/gdbus/gdbus-docs.xml
new file mode 100644
index 0000000..3747302
--- /dev/null
+++ b/docs/reference/gdbus/gdbus-docs.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+ "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" [
+<!ENTITY version SYSTEM "version.xml">
+]>
+<book lang="en" id="gdbus" xmlns:xi="http://www.w3.org/2003/XInclude">
+<title>GDBus Reference Manual</title>
+ <bookinfo>
+ <title>GDBus Reference Manual</title>
+ <releaseinfo>
+ for GDBus &version;
+ The latest version of this documentation can be found on-line at
+ <ulink role="online-location" url="http://library.gnome.org/devel/gdbus/unstable/">http://library.gnome.org/devel/gdbus/unstable/</ulink>.
+ </releaseinfo>
+ </bookinfo>
+
+ <part>
+ <title>API Reference</title>
+ <chapter id="lowlevel">
+ <title>Low-level GDBus</title>
+ <xi:include href="xml/gdbusmainloop.xml"/>
+ <xi:include href="xml/gdbuserror.xml"/>
+ <xi:include href="xml/gdbusconnection.xml"/>
+ </chapter>
+ <chapter id="convenience">
+ <title>GDBus Convenience</title>
+ <xi:include href="xml/gbusnameowner.xml"/>
+ </chapter>
+ <chapter id="cmapping">
+ <title>C Object Mapping</title>
+ </chapter>
+ </part>
+
+ <chapter id="gdbus-hierarchy">
+ <title>Object Hierarchy</title>
+ <xi:include href="xml/tree_index.sgml"/>
+ </chapter>
+
+ <index>
+ <title id="index-all">Index</title>
+ </index>
+</book>
diff --git a/docs/reference/gdbus/gdbus-sections.txt b/docs/reference/gdbus/gdbus-sections.txt
new file mode 100644
index 0000000..2640590
--- /dev/null
+++ b/docs/reference/gdbus/gdbus-sections.txt
@@ -0,0 +1,70 @@
+<SECTION>
+<FILE>gbusnameowner</FILE>
+<TITLE>GBusNameOwner</TITLE>
+GBusNameOwnerFlags
+GBusNameOwner
+GBusNameOwnerClass
+g_bus_name_owner_new
+g_bus_name_owner_new_finish
+g_bus_name_owner_new_for_connection
+g_bus_name_owner_new_for_connection_finish
+g_bus_name_owner_get_owns_name
+g_bus_name_owner_get_name
+g_bus_name_owner_get_flags
+g_bus_name_owner_get_connection
+<SUBSECTION Standard>
+G_BUS_NAME_OWNER
+G_IS_BUS_NAME_OWNER
+G_TYPE_BUS_NAME_OWNER
+g_bus_name_owner_get_type
+G_BUS_NAME_OWNER_CLASS
+G_IS_BUS_NAME_OWNER_CLASS
+G_BUS_NAME_OWNER_GET_CLASS
+</SECTION>
+
+<SECTION>
+<FILE>gdbusconnection</FILE>
+<TITLE>GDBusConnection</TITLE>
+GMessageBusType
+GDBusConnection
+GDBusConnectionClass
+g_dbus_connection_bus_get
+g_dbus_connection_bus_get_finish
+g_dbus_connection_bus_get_private
+g_dbus_connection_bus_get_private_finish
+g_dbus_connection_get_exit_on_close
+g_dbus_connection_set_exit_on_close
+g_dbus_connection_get_unique_name
+g_dbus_connection_get_is_open
+g_dbus_connection_get_bus_type
+g_dbus_connection_get_dbus_1_connection
+<SUBSECTION Standard>
+G_DBUS_CONNECTION
+G_IS_DBUS_CONNECTION
+G_TYPE_DBUS_CONNECTION
+g_dbus_connection_get_type
+G_DBUS_CONNECTION_CLASS
+G_IS_DBUS_CONNECTION_CLASS
+G_DBUS_CONNECTION_GET_CLASS
+</SECTION>
+
+<SECTION>
+<FILE>gdbusmainloop</FILE>
+g_dbus_integrate_dbus_1_connection
+g_dbus_unintegrate_dbus_1_connection
+g_dbus_integrate_dbus_1_server
+g_dbus_unintegrate_dbus_1_server
+</SECTION>
+
+<SECTION>
+<FILE>gdbuserror</FILE>
+G_DBUS_ERROR
+GDBusError
+g_dbus_error_get_remote_exception
+g_dbus_error_new_for_dbus_error
+g_dbus_error_new_for_dbus_error_valist
+g_dbus_error_set_dbus_error
+g_dbus_error_set_dbus_error_valist
+g_dbus_error_new_for_gerror
+</SECTION>
+
diff --git a/docs/reference/gdbus/gdbus.types b/docs/reference/gdbus/gdbus.types
new file mode 100644
index 0000000..778d932
--- /dev/null
+++ b/docs/reference/gdbus/gdbus.types
@@ -0,0 +1,5 @@
+g_dbus_connection_get_type
+g_bus_name_owner_get_type
+g_message_bus_type_get_type
+g_bus_name_owner_flags_get_type
+g_dbus_error_get_type
diff --git a/docs/reference/gdbus/version.xml.in b/docs/reference/gdbus/version.xml.in
new file mode 100644
index 0000000..d78bda9
--- /dev/null
+++ b/docs/reference/gdbus/version.xml.in
@@ -0,0 +1 @@
+ VERSION@
diff --git a/gdbus-2.0-uninstalled.pc.in b/gdbus-2.0-uninstalled.pc.in
new file mode 100644
index 0000000..636a4a7
--- /dev/null
+++ b/gdbus-2.0-uninstalled.pc.in
@@ -0,0 +1,6 @@
+Name: GDBus Uninstalled
+Description: gdbus library, Not Installed
+Version: @VERSION@
+Requires: glib-2.0-uninstalled,gobject-2.0-uninstalled,gio-2.0-uninstalled,gmodule-no-export-2.0-uninstalled
+Libs: ${pc_top_builddir}/${pcfiledir}/gdbus/libgdbus-2.0.la
+Cflags: -I${pc_top_builddir}/${pcfiledir}/@srcdir@
diff --git a/gdbus-2.0.pc.in b/gdbus-2.0.pc.in
new file mode 100644
index 0000000..afd3470
--- /dev/null
+++ b/gdbus-2.0.pc.in
@@ -0,0 +1,11 @@
+prefix= prefix@
+exec_prefix= exec_prefix@
+libdir= libdir@
+includedir= includedir@
+
+Name: GDBus
+Description: glib D-Bus library
+Version: @VERSION@
+Requires: glib-2.0,gobject-2.0,gio-2.0,gmodule-no-export-2.0
+Libs: -L${libdir} -lgdbus-2.0
+Cflags:
diff --git a/gdbus/Makefile.am b/gdbus/Makefile.am
new file mode 100644
index 0000000..466e059
--- /dev/null
+++ b/gdbus/Makefile.am
@@ -0,0 +1,195 @@
+include $(top_srcdir)/Makefile.decl
+
+NULL =
+
+SUBDIRS=tests
+
+if OS_WIN32_AND_DLL_COMPILATION
+if MS_LIB_AVAILABLE
+noinst_DATA = gdbus-2.0.lib
+
+install_ms_lib_cmd = $(INSTALL) gdbus-2.0.lib $(DESTDIR)$(libdir)
+uninstall_ms_lib_cmd = -rm $(DESTDIR)$(libdir)/gdbus-2.0.lib
+endif
+endif
+
+install-ms-lib:
+ $(install_ms_lib_cmd)
+
+uninstall-ms-lib:
+ $(uninstall_ms_lib_cmd)
+
+gdbus.def: gdbus.symbols
+ (echo -e EXPORTS; $(CPP) -P -DINCLUDE_VARIABLES -DINCLUDE_INTERNAL_SYMBOLS -DG_OS_WIN32 -DALL_FILES - <$(srcdir)/gdbus.symbols | sed -e '/^$$/d' -e 's/^/ /' -e 's/G_GNUC_[^ ]*//g' | sort) > gdbus.def.tmp && \
+ mv gdbus.def.tmp gdbus.def
+
+gdbusalias.h: gdbus.symbols
+ $(PERL) $(srcdir)/makegdbusalias.pl < $(srcdir)/gdbus.symbols > gdbusalias.h.tmp && \
+ mv gdbusalias.h.tmp gdbusalias.h
+
+gdbusaliasdef.c: gdbus.symbols
+ $(PERL) $(srcdir)/makegdbusalias.pl -def < $(srcdir)/gdbus.symbols > gdbusaliasdef.c.tmp && \
+ mv gdbusaliasdef.c.tmp gdbusaliasdef.c
+
+if OS_LINUX
+if HAVE_GNUC_VISIBILITY
+TESTS = abicheck.sh pltcheck.sh
+endif
+endif
+
+AM_CPPFLAGS = \
+ -DG_LOG_DOMAIN=\"GLib-DBus\" \
+ -I$(top_builddir) \
+ -I$(top_srcdir) \
+ -I$(top_srcdir)/glib \
+ -I$(top_srcdir)/gio \
+ -I$(top_srcdir)/gobject \
+ -I$(top_srcdir)/gmodule \
+ $(GLIB_DEBUG_FLAGS) \
+ -DG_DISABLE_DEPRECATED \
+ -DG_DBUS_COMPILATION \
+ $(NULL)
+
+lib_LTLIBRARIES = libgdbus-2.0.la
+
+marshal_sources = \
+ gdbus-marshal.h \
+ gdbus-marshal.c \
+ $(NULL)
+
+if CROSS_COMPILING
+ glib_genmarshal=$(GLIB_GENMARSHAL)
+else
+ glib_genmarshal=../gobject/glib-genmarshal
+endif
+
+gdbus-marshal.h: gdbus-marshal.list
+ $(glib_genmarshal) --prefix=_gdbus_marshal $(srcdir)/gdbus-marshal.list --header --internal > $ tmp && \
+ mv $ tmp $@
+
+gdbus-marshal.c: gdbus-marshal.h gdbus-marshal.list
+ (echo "#include \"gdbus-marshal.h\""; \
+ $(glib_genmarshal) --prefix=_gdbus_marshal $(srcdir)/gdbus-marshal.list --body --internal) > $ tmp && \
+ mv $ tmp $@
+
+gdbus_headers = \
+ gdbus.h \
+ gdbusenums.h \
+ gdbustypes.h \
+ gdbuserror.h \
+ gdbusmainloop.h \
+ gdbusconnection.h \
+ gbusnameowner.h \
+ $(NULL)
+
+libgdbus_2_0_la_SOURCES = \
+ gdbus.h \
+ gdbustypes.h \
+ gdbusenumtypes.h \
+ gdbus-marshal.h gdbus-marshal.c \
+ gdbusenumtypes.h gdbusenumtypes.c \
+ gdbuserror.h gdbuserror.c \
+ gdbusmainloop.h gdbusmainloop.c \
+ gdbusconnection.h gdbusconnection.c \
+ gbusnameowner.h gbusnameowner.c \
+ gdbusprivate.h gdbusprivate.c \
+ gdbusalias.h \
+ gdbusaliasdef.c \
+ $(NULL)
+
+$(libgdbus_2_0_la_OBJECTS): $(marshal_sources)
+
+libgdbus_2_0_la_CFLAGS = \
+ $(DBUS_CFLAGS) \
+ $(NULL)
+
+libgdbus_2_0_la_LIBADD = \
+ $(top_builddir)/glib/libglib-2.0.la \
+ $(top_builddir)/gobject/libgobject-2.0.la \
+ $(top_builddir)/gio/libgio-2.0.la \
+ $(top_builddir)/gmodule/libgmodule-2.0.la \
+ $(GLIB_LIBS) \
+ $(DBUS_LIBS) \
+ $(NULL)
+
+if PLATFORM_WIN32
+no_undefined = -no-undefined
+endif
+
+if OS_WIN32_AND_DLL_COMPILATION
+export_symbols = -export-symbols gdbus.def
+gdbus_def = gdbus.def
+
+install-def-file:
+ $(INSTALL) gdbus.def $(DESTDIR)$(libdir)/gdbus-2.0.def
+
+uninstall-def-file:
+ -rm $(DESTDIR)$(libdir)/gdbus-2.0.def
+else
+install-def-file:
+uninstall-def-file:
+
+export_symbols = -export-symbols-regex '^g_.*'
+endif
+
+install-data-local: install-ms-lib install-def-file
+
+uninstall-local: uninstall-ms-lib uninstall-def-file
+
+libgdbus_2_0_la_LDFLAGS = \
+ -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) \
+ -export-dynamic $(no_undefined) $(export_symbols)
+
+libgdbus_2_0_la_DEPENDENCIES = $(gdbus_def)
+
+gdbusincludedir=$(includedir)/glib-2.0/gdbus/
+gdbusinclude_HEADERS = \
+ $(gdbus_headers) \
+ gdbusenumtypes.h
+
+# these sources (also mentioned above) are generated.
+BUILT_SOURCES = \
+ gdbus-marshal.h \
+ gdbus-marshal.c \
+ gdbusalias.h \
+ gdbusaliasdef.c \
+ gdbusenumtypes.h \
+ gdbusenumtypes.c \
+ $(NULL)
+
+EXTRA_DIST += \
+ gdbus-marshal.list \
+ gdbus.symbols \
+ gdbusenumtypes.h.template \
+ gdbusenumtypes.c.template \
+ makegdbusalias.pl \
+ abicheck.sh \
+ pltcheck.sh \
+ $(NULL)
+
+CLEANFILES = \
+ $(marshal_sources) \
+ $(NULL)
+
+gdbusenumtypes.h: $(gdbus_headers) gdbusenumtypes.h.template Makefile.am
+ ( top_builddir=`cd $(top_builddir) && pwd`; \
+ cd $(srcdir) && $$top_builddir/gobject/glib-mkenums --template gdbusenumtypes.h.template $(gdbus_headers) ) > \
+ gdbusenumtypes.h.tmp && \
+ mv gdbusenumtypes.h.tmp gdbusenumtypes.h
+
+gdbusenumtypes.c: $(gdbus_headers) gdbusenumtypes.c.template Makefile.am
+ ( top_builddir=`cd $(top_builddir) && pwd`; \
+ cd $(srcdir) && $$top_builddir/gobject/glib-mkenums --template gdbusenumtypes.c.template $(gdbus_headers) ) > \
+ gdbusenumtypes.c.tmp && mv gdbusenumtypes.c.tmp gdbusenumtypes.c
+
+gdbus-2.0.lib: libgdbus-2.0.la gdbus.def
+ lib -machine:@LIB_EXE_MACHINE_FLAG@ -name:libgdbus-2.0-$(LT_CURRENT_MINUS_AGE).dll -def:gdbus.def -out:$@
+
+noinst_PROGRAMS = example-gbusnameowner
+
+example_gbusnameowner_SOURCES = example-gbusnameowner.c
+example_gbusnameowner_CFLAGS = $(DBUS_CFLAGS)
+example_gbusnameowner_LDADD = libgdbus-2.0.la
+
+clean-local :
+ rm -f *~
diff --git a/gdbus/abicheck.sh b/gdbus/abicheck.sh
new file mode 100755
index 0000000..61bd1b5
--- /dev/null
+++ b/gdbus/abicheck.sh
@@ -0,0 +1,13 @@
+#! /bin/sh
+
+egrep '^#([^i]|if).*[^\]$' "${top_builddir:-..}/glibconfig.h" > glibconfig.cpp
+
+INCLUDES="-include ${top_builddir:-..}/config.h"
+INCLUDES="$INCLUDES -include glibconfig.cpp"
+
+cpp -DINCLUDE_VARIABLES -P $INCLUDES -DALL_FILES ${srcdir:-.}/gdbus.symbols | sed -e '/^$/d' -e 's/ G_GNUC.*$//' -e 's/ PRIVATE$//' | sort > expected-abi
+rm glibconfig.cpp
+
+nm -D -g --defined-only .libs/libgdbus-2.0.so | cut -d ' ' -f 3 | sort > actual-abi
+
+diff -u expected-abi actual-abi && rm expected-abi actual-abi
diff --git a/gdbus/example-gbusnameowner.c b/gdbus/example-gbusnameowner.c
new file mode 100644
index 0000000..05d4ee3
--- /dev/null
+++ b/gdbus/example-gbusnameowner.c
@@ -0,0 +1,90 @@
+
+#include <gdbus/gdbus.h>
+
+static void
+on_name_acquired (GBusNameOwner *owner,
+ gpointer user_data)
+{
+ g_debug ("Name acquired");
+}
+
+static void
+on_name_lost (GBusNameOwner *owner,
+ gpointer user_data)
+{
+ g_debug ("Name lost");
+}
+
+static void
+name_owner_cb (GBusNameOwner *owner,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ GError *error;
+
+ error = NULL;
+ if (!g_bus_name_owner_new_finish (owner,
+ res,
+ NULL)) {
+ g_debug ("Failed to acquire name. Waiting in line.");
+ }
+}
+
+int
+main (int argc, char *argv[])
+{
+ GBusNameOwner *owner;
+ GBusNameOwnerFlags flags;
+ GMainLoop *loop;
+ GError *error;
+ GOptionContext *option_context;
+ gboolean opt_allow_replacement;
+ gboolean opt_replace;
+ GOptionEntry option_entries[] = {
+ { "allow-replacement", 'a', 0, G_OPTION_ARG_NONE, &opt_allow_replacement, "Allow replacement", NULL},
+ { "replace", 'r', 0, G_OPTION_ARG_NONE, &opt_replace, "Replace", NULL},
+ { NULL }
+ };
+
+ g_type_init ();
+
+ error = NULL;
+ option_context = g_option_context_new ("GBusNameOwner example");
+ g_option_context_add_main_entries (option_context,
+ option_entries,
+ NULL);
+ if (!g_option_context_parse (option_context,
+ &argc,
+ &argv,
+ &error))
+ {
+ g_option_context_free (option_context);
+ g_printerr ("Failed to parse options: %s", error->message);
+ g_error_free (error);
+ return 1;
+ }
+ g_option_context_free (option_context);
+
+ loop = g_main_loop_new (NULL, FALSE);
+
+ flags = 0;
+ if (opt_allow_replacement)
+ flags |= G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT;
+ if (opt_replace)
+ flags |= G_BUS_NAME_OWNER_FLAGS_REPLACE;
+
+ owner = g_bus_name_owner_new (G_MESSAGE_BUS_TYPE_SESSION,
+ "org.gtk.GDBus.ExampleName",
+ flags,
+ NULL,
+ (GAsyncReadyCallback) name_owner_cb,
+ NULL);
+ g_signal_connect (owner, "name-acquired", G_CALLBACK (on_name_acquired), NULL);
+ g_signal_connect (owner, "name-lost", G_CALLBACK (on_name_lost), NULL);
+ g_main_loop_run (loop);
+
+ g_object_unref (owner);
+ g_main_loop_unref (loop);
+
+ return 0;
+}
diff --git a/gdbus/gbusnameowner.c b/gdbus/gbusnameowner.c
new file mode 100644
index 0000000..c90f2ca
--- /dev/null
+++ b/gdbus/gbusnameowner.c
@@ -0,0 +1,1244 @@
+/* GDBus - GLib D-Bus Library
+ *
+ * Copyright (C) 2008-2009 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: David Zeuthen <davidz redhat com>
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+
+#include <glib/gi18n.h>
+
+#include "gbusnameowner.h"
+#include "gdbusenumtypes.h"
+#include "gdbusconnection.h"
+#include "gdbuserror.h"
+#include "gdbusprivate.h"
+
+#include "gdbusalias.h"
+
+/**
+ * SECTION:gbusnameowner
+ * @short_description: Own a well-known name on a bus
+ * @include: gdbus/gdbus.h
+ *
+ * #GBusNameOwner is a utility class that makes it easy to implement
+ * D-Bus services. See g_bus_name_owner_new() for an example.
+ */
+
+struct _GBusNameOwnerPrivate
+{
+ gchar *name;
+ GBusNameOwnerFlags flags;
+
+ GDBusConnection *connection;
+
+ gboolean owns_name;
+
+ gboolean in_construction_phase;
+};
+
+enum
+{
+ PROP_0,
+ PROP_NAME,
+ PROP_FLAGS,
+ PROP_OWNS_NAME,
+ PROP_CONNECTION,
+};
+
+enum
+{
+ NAME_LOST_SIGNAL,
+ NAME_ACQUIRED_SIGNAL,
+ LAST_SIGNAL,
+};
+
+
+static DBusHandlerResult
+filter_function (DBusConnection *dbus_1_connection,
+ DBusMessage *message,
+ void *user_data);
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+static void bus_request_name (GDBusConnection *connection,
+ const gchar *name,
+ guint flags,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+static guint bus_request_name_finish (GDBusConnection *bus,
+ GAsyncResult *res,
+ GError **error);
+
+static guint bus_release_name_sync (GDBusConnection *connection,
+ const gchar *name,
+ GError **error);
+
+#if 0
+static void bus_release_name (GDBusConnection *connection,
+ const gchar *name,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+static guint bus_release_name_finish (GDBusConnection *bus,
+ GAsyncResult *res,
+ GError **error);
+#endif
+
+static void on_connection_opened (GDBusConnection *connection,
+ gpointer user_data);
+
+static void on_connection_closed (GDBusConnection *connection,
+ gpointer user_data);
+
+static guint get_request_name_flags (GBusNameOwnerFlags flags);
+
+G_DEFINE_TYPE (GBusNameOwner, g_bus_name_owner, G_TYPE_OBJECT);
+
+static void
+g_bus_name_owner_finalize (GObject *object)
+{
+ GBusNameOwner *owner = G_BUS_NAME_OWNER (object);
+
+ if (owner->priv->connection != NULL)
+ {
+ /* release the name if we own it */
+ if (owner->priv->owns_name)
+ {
+ /* Gah, even though there's a ReleaseName() method in flight,
+ * we can't use RequestName() until it is processed.. This must
+ * be a bug in the message bus daemon.
+ *
+ * So do ReleaseName() synchronously for now.
+ */
+ GError *error;
+ guint reply;
+ error = NULL;
+ reply = bus_release_name_sync (owner->priv->connection,
+ owner->priv->name,
+ &error);
+ if (error != NULL)
+ {
+ g_warning ("Error doing ReleaseName(): %s", error->message);
+ g_error_free (error);
+ }
+ else if (reply != DBUS_RELEASE_NAME_REPLY_RELEASED)
+ {
+ g_warning ("Expected DBUS_RELEASE_NAME_REPLY_RELEASED but got %d", reply);
+ }
+ }
+
+ g_signal_handlers_disconnect_by_func (owner->priv->connection, on_connection_opened, owner);
+ g_signal_handlers_disconnect_by_func (owner->priv->connection, on_connection_closed, owner);
+
+ if (g_dbus_connection_get_is_open (owner->priv->connection))
+ {
+ dbus_connection_remove_filter (g_dbus_connection_get_dbus_1_connection (owner->priv->connection),
+ filter_function,
+ owner);
+ }
+
+ g_object_unref (owner->priv->connection);
+ }
+ g_free (owner->priv->name);
+
+ if (G_OBJECT_CLASS (g_bus_name_owner_parent_class)->finalize != NULL)
+ G_OBJECT_CLASS (g_bus_name_owner_parent_class)->finalize (object);
+}
+
+static void
+g_bus_name_owner_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GBusNameOwner *owner = G_BUS_NAME_OWNER (object);
+
+ switch (prop_id)
+ {
+ case PROP_NAME:
+ g_value_set_string (value, g_bus_name_owner_get_name (owner));
+ break;
+
+ case PROP_FLAGS:
+ g_value_set_flags (value, g_bus_name_owner_get_flags (owner));
+ break;
+
+ case PROP_OWNS_NAME:
+ g_value_set_boolean (value, g_bus_name_owner_get_owns_name (owner));
+ break;
+
+ case PROP_CONNECTION:
+ g_value_set_object (value, g_bus_name_owner_get_connection (owner));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+g_bus_name_owner_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GBusNameOwner *owner = G_BUS_NAME_OWNER (object);
+
+ switch (prop_id)
+ {
+ case PROP_NAME:
+ owner->priv->name = g_value_dup_string (value);
+ break;
+
+ case PROP_FLAGS:
+ owner->priv->flags = g_value_get_flags (value);
+ break;
+
+ case PROP_CONNECTION:
+ owner->priv->connection = g_value_dup_object (value);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+#if 0
+static void
+request_name_cb (GMessageBusConnection *bus,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ GMessageBusRequestNameFlags reply;
+ GBusNameOwner *owner = G_BUS_NAME_OWNER (user_data);
+
+ reply = g_message_bus_connection_request_name_finish (bus,
+ res,
+ NULL);
+ if (reply == G_MESSAGE_BUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)
+ {
+ owner->priv->owns_name = TRUE;
+ g_object_notify (G_OBJECT (owner), "owns-name");
+ g_signal_emit (owner, signals[NAME_ACQUIRED_SIGNAL], 0);
+ }
+ else
+ {
+ //g_signal_emit (owner, signals[FAILED_TO_ACQUIRE_NAME_SIGNAL], 0);
+ }
+
+ g_object_unref (owner);
+}
+#endif
+
+#define PRINT_MESSAGE(message) \
+ do { \
+ const gchar *message_type; \
+ switch (dbus_message_get_type (message)) \
+ { \
+ case DBUS_MESSAGE_TYPE_METHOD_CALL: \
+ message_type = "method_call"; \
+ break; \
+ case DBUS_MESSAGE_TYPE_METHOD_RETURN: \
+ message_type = "method_return"; \
+ break; \
+ case DBUS_MESSAGE_TYPE_ERROR: \
+ message_type = "error"; \
+ break; \
+ case DBUS_MESSAGE_TYPE_SIGNAL: \
+ message_type = "signal"; \
+ break; \
+ case DBUS_MESSAGE_TYPE_INVALID: \
+ message_type = "invalid"; \
+ break; \
+ default: \
+ message_type = "unknown"; \
+ break; \
+ } \
+ g_print ("new message:\n" \
+ " type: %s\n" \
+ " sender: %s\n" \
+ " destination: %s\n" \
+ " path: %s\n" \
+ " interface: %s\n" \
+ " member: %s\n", \
+ message_type, \
+ dbus_message_get_sender (message), \
+ dbus_message_get_destination (message), \
+ dbus_message_get_path (message), \
+ dbus_message_get_interface (message), \
+ dbus_message_get_member (message)); \
+ } while (FALSE)
+
+static DBusHandlerResult
+filter_function (DBusConnection *dbus_1_connection,
+ DBusMessage *message,
+ void *user_data)
+{
+ GBusNameOwner *owner = G_BUS_NAME_OWNER (user_data);
+ DBusError dbus_error;
+ const gchar *name;
+ gboolean old_owns_name;
+
+ g_debug ("in bus-name-owner's filter_function for dbus_1_connection %p", dbus_1_connection);
+ PRINT_MESSAGE (message);
+
+ dbus_error_init (&dbus_error);
+
+ old_owns_name = owner->priv->owns_name;
+
+ if (dbus_message_is_signal (message,
+ DBUS_INTERFACE_DBUS,
+ "NameLost") &&
+ g_strcmp0 (dbus_message_get_sender (message), DBUS_SERVICE_DBUS) == 0 &&
+ g_strcmp0 (dbus_message_get_path (message), DBUS_PATH_DBUS) == 0)
+ {
+ if (dbus_message_get_args (message,
+ &dbus_error,
+ DBUS_TYPE_STRING, &name,
+ DBUS_TYPE_INVALID))
+ {
+ if (g_strcmp0 (name, owner->priv->name) == 0)
+ {
+ owner->priv->owns_name = FALSE;
+ if (owner->priv->owns_name != old_owns_name)
+ {
+ g_object_notify (G_OBJECT (owner), "owns-name");
+ g_signal_emit (owner, signals[NAME_LOST_SIGNAL], 0);
+ }
+ else
+ {
+ /* This is not unexpected.. it can happen when releasing a name only to claim it right again */
+ /*g_warning ("Got unexpected NameLost signal for the name %s", owner->priv->name);*/
+ }
+ }
+ }
+ else
+ {
+ g_warning ("Error extracting name for NameLost signal: %s: %s", dbus_error.name, dbus_error.message);
+ dbus_error_free (&dbus_error);
+ }
+ }
+
+ else if (dbus_message_is_signal (message,
+ DBUS_INTERFACE_DBUS,
+ "NameAcquired") &&
+ g_strcmp0 (dbus_message_get_sender (message), DBUS_SERVICE_DBUS) == 0 &&
+ g_strcmp0 (dbus_message_get_path (message), DBUS_PATH_DBUS) == 0)
+ {
+ if (dbus_message_get_args (message,
+ &dbus_error,
+ DBUS_TYPE_STRING, &name,
+ DBUS_TYPE_INVALID))
+ {
+ if (g_strcmp0 (name, owner->priv->name) == 0)
+ {
+ owner->priv->owns_name = TRUE;
+ if (owner->priv->owns_name != old_owns_name)
+ {
+ g_object_notify (G_OBJECT (owner), "owns-name");
+ g_signal_emit (owner, signals[NAME_ACQUIRED_SIGNAL], 0);
+ }
+ else
+ {
+ g_warning ("Got unexpected NameAcquired signal for the name %s",
+ owner->priv->name);
+ }
+ }
+ }
+ else
+ {
+ g_warning ("Error extracting name for NameAcquired signal: %s: %s", dbus_error.name, dbus_error.message);
+ dbus_error_free (&dbus_error);
+ }
+ }
+
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+static void
+on_connection_opened (GDBusConnection *connection,
+ gpointer user_data)
+{
+ GBusNameOwner *owner = G_BUS_NAME_OWNER (user_data);
+
+ /* set up a filter function for listening on NameLost and NameAcquired messages on the DBusConnection */
+ if (!dbus_connection_add_filter (g_dbus_connection_get_dbus_1_connection (owner->priv->connection),
+ filter_function,
+ owner,
+ NULL))
+ _g_dbus_oom ();
+
+ if (owner->priv->in_construction_phase)
+ return;
+
+ /* ok, the bus suddenly came up.. so try to claim the name ASAP */
+
+ g_assert (!owner->priv->owns_name);
+
+ /* we don't care about the reply.. we'll know soon enough, via a NameAcquired
+ * signal, if we managed to claim the name
+ */
+ bus_request_name (owner->priv->connection,
+ owner->priv->name,
+ get_request_name_flags (owner->priv->flags),
+ NULL,
+ NULL);
+}
+
+static void
+on_connection_closed (GDBusConnection *connection,
+ gpointer user_data)
+{
+ GBusNameOwner *owner = G_BUS_NAME_OWNER (user_data);
+
+ /* no need to remove filter; it is removed when the DBusConnection is destroyed */
+
+ /* if we currently own the name, well too bad, not anymore, it's up for grabs */
+ if (owner->priv->owns_name)
+ {
+ owner->priv->owns_name = FALSE;
+ g_object_notify (G_OBJECT (owner), "owns-name");
+ g_signal_emit (owner, signals[NAME_LOST_SIGNAL], 0);
+ }
+
+}
+
+static void
+g_bus_name_owner_constructed (GObject *object)
+{
+ GBusNameOwner *owner = G_BUS_NAME_OWNER (object);
+
+ g_signal_connect (owner->priv->connection, "opened", G_CALLBACK (on_connection_opened), owner);
+ g_signal_connect (owner->priv->connection, "closed", G_CALLBACK (on_connection_closed), owner);
+ if (g_dbus_connection_get_is_open (owner->priv->connection))
+ on_connection_opened (owner->priv->connection, owner);
+
+ if (G_OBJECT_CLASS (g_bus_name_owner_parent_class)->constructed != NULL)
+ G_OBJECT_CLASS (g_bus_name_owner_parent_class)->constructed (object);
+}
+
+static void
+g_bus_name_owner_class_init (GBusNameOwnerClass *klass)
+{
+ GObjectClass *gobject_class;
+
+ g_type_class_add_private (klass, sizeof (GBusNameOwnerPrivate));
+
+ gobject_class = G_OBJECT_CLASS (klass);
+ gobject_class->finalize = g_bus_name_owner_finalize;
+ gobject_class->constructed = g_bus_name_owner_constructed;
+ gobject_class->get_property = g_bus_name_owner_get_property;
+ gobject_class->set_property = g_bus_name_owner_set_property;
+
+ /**
+ * GBusNameOwner:name:
+ *
+ * The well-known name to own.
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_NAME,
+ g_param_spec_string ("name",
+ _("name"),
+ _("The name to own"),
+ NULL,
+ G_PARAM_READABLE |
+ G_PARAM_WRITABLE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_NAME |
+ G_PARAM_STATIC_BLURB |
+ G_PARAM_STATIC_NICK));
+
+ /**
+ * GBusNameOwner:flags:
+ *
+ * A set of flags from the #GBusNameOwnerFlags flag enumeration
+ * detailing behavior on how to own the name.
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_FLAGS,
+ g_param_spec_flags ("flags",
+ _("flags"),
+ _("Flags detailing how to own the name"),
+ G_TYPE_BUS_NAME_OWNER_FLAGS,
+ G_BUS_NAME_OWNER_FLAGS_NONE,
+ G_PARAM_READABLE |
+ G_PARAM_WRITABLE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_NAME |
+ G_PARAM_STATIC_BLURB |
+ G_PARAM_STATIC_NICK));
+
+ /**
+ * GBusNameOwner:owns-name:
+ *
+ * Whether the name is currently owned.
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_OWNS_NAME,
+ g_param_spec_boolean ("owns-name",
+ _("owns-name"),
+ _("Whether the name is currently owned"),
+ FALSE,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_NAME |
+ G_PARAM_STATIC_BLURB |
+ G_PARAM_STATIC_NICK));
+
+ /**
+ * GBusNameOwner:connection:
+ *
+ * The #GMessageBusConnection that the name will be owned on.
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_CONNECTION,
+ g_param_spec_object ("connection",
+ _("connection"),
+ _("The connection that the name will be owned on"),
+ G_TYPE_DBUS_CONNECTION,
+ G_PARAM_READABLE |
+ G_PARAM_WRITABLE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_NAME |
+ G_PARAM_STATIC_BLURB |
+ G_PARAM_STATIC_NICK));
+
+ /**
+ * GBusNameOwner::name-lost:
+ * @owner: The #GBusNameOwner emitting the signal.
+ *
+ * Emitted when @owner loses ownership of #GBusNameOwner:name.
+ **/
+ signals[NAME_LOST_SIGNAL] = g_signal_new ("name-lost",
+ G_TYPE_BUS_NAME_OWNER,
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GBusNameOwnerClass, name_lost),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+
+ /**
+ * GBusNameOwner::name-acquired:
+ * @owner: The #GBusNameOwner emitting the signal.
+ *
+ * Emitted when @owner acquires ownership of #GBusNameOwner:name.
+ **/
+ signals[NAME_ACQUIRED_SIGNAL] = g_signal_new ("name-acquired",
+ G_TYPE_BUS_NAME_OWNER,
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GBusNameOwnerClass, name_acquired),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+}
+
+static void
+g_bus_name_owner_init (GBusNameOwner *connection)
+{
+ connection->priv = G_TYPE_INSTANCE_GET_PRIVATE (connection, G_TYPE_BUS_NAME_OWNER, GBusNameOwnerPrivate);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+#if 0
+
+static void
+bus_release_name_cb (DBusPendingCall *pending,
+ void *user_data)
+{
+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (user_data);
+ DBusMessage *reply;
+ DBusError dbus_error;
+ GError *error;
+ dbus_uint32_t release_name_reply;
+
+ reply = dbus_pending_call_steal_reply (pending);
+ g_assert (reply != NULL);
+
+ dbus_error_init (&dbus_error);
+ if (dbus_message_get_args (reply,
+ &dbus_error,
+ DBUS_TYPE_UINT32, &release_name_reply,
+ DBUS_TYPE_INVALID))
+ {
+ g_simple_async_result_set_op_res_gpointer (simple, GINT_TO_POINTER (release_name_reply), NULL);
+ goto done;
+ }
+
+ error = g_dbus_error_new_for_dbus_error (&dbus_error,
+ NULL,
+ NULL);
+ g_simple_async_result_set_from_error (simple, error);
+ g_error_free (error);
+ dbus_error_free (&dbus_error);
+
+ done:
+ g_simple_async_result_complete (simple);
+ g_object_unref (simple);
+ dbus_message_unref (reply);
+}
+
+static void
+bus_release_name (GDBusConnection *connection,
+ const gchar *name,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *simple;
+ DBusMessage *message;
+ DBusPendingCall *pending_call;
+
+ g_return_if_fail (G_IS_DBUS_CONNECTION (connection));
+ g_return_if_fail (name != NULL);
+
+ simple = g_simple_async_result_new (G_OBJECT (connection),
+ callback,
+ user_data,
+ bus_release_name);
+
+ if (g_dbus_connection_get_dbus_1_connection (connection) == NULL)
+ {
+ g_simple_async_result_set_error (simple,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_FAILED,
+ _("Not connected to message bus"));
+ g_simple_async_result_complete (simple);
+ g_object_unref (simple);
+ goto out;
+ }
+
+ if ((message = dbus_message_new_method_call (DBUS_SERVICE_DBUS,
+ DBUS_PATH_DBUS,
+ DBUS_INTERFACE_DBUS,
+ "ReleaseName")) == NULL)
+ _g_dbus_oom ();
+ if (!dbus_message_append_args (message,
+ DBUS_TYPE_STRING, &name,
+ DBUS_TYPE_INVALID))
+ _g_dbus_oom ();
+
+ if (!dbus_connection_send_with_reply (g_dbus_connection_get_dbus_1_connection (connection),
+ message,
+ &pending_call,
+ -1))
+ _g_dbus_oom ();
+
+ dbus_message_unref (message);
+
+ dbus_pending_call_set_notify (pending_call,
+ bus_release_name_cb,
+ simple,
+ NULL);
+
+ out:
+ ;
+}
+
+static guint
+bus_release_name_finish (GDBusConnection *bus,
+ GAsyncResult *res,
+ GError **error)
+{
+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res);
+ guint ret;
+
+ ret = 0;
+
+ g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == bus_release_name);
+
+ if (g_simple_async_result_propagate_error (simple, error))
+ goto out;
+
+ ret = GPOINTER_TO_INT (g_simple_async_result_get_op_res_gpointer (simple));
+
+ out:
+ return ret;
+}
+#endif
+
+static guint
+bus_release_name_sync (GDBusConnection *connection,
+ const gchar *name,
+ GError **error)
+{
+ DBusMessage *message;
+ DBusMessage *reply;
+ dbus_uint32_t release_name_reply;
+ DBusError dbus_error;
+
+ g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), 0);
+ g_return_val_if_fail (name != NULL, 0);
+
+ message = NULL;
+ reply = NULL;
+ release_name_reply = 0;
+
+ if (g_dbus_connection_get_dbus_1_connection (connection) == NULL)
+ {
+ g_set_error (error,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_FAILED,
+ _("Not connected to message bus"));
+ goto out;
+ }
+
+ if ((message = dbus_message_new_method_call (DBUS_SERVICE_DBUS,
+ DBUS_PATH_DBUS,
+ DBUS_INTERFACE_DBUS,
+ "ReleaseName")) == NULL)
+ _g_dbus_oom ();
+ if (!dbus_message_append_args (message,
+ DBUS_TYPE_STRING, &name,
+ DBUS_TYPE_INVALID))
+ _g_dbus_oom ();
+
+ dbus_error_init (&dbus_error);
+ reply = dbus_connection_send_with_reply_and_block (g_dbus_connection_get_dbus_1_connection (connection),
+ message,
+ -1,
+ &dbus_error);
+ if (reply == NULL)
+ {
+ g_dbus_error_set_dbus_error (error,
+ &dbus_error,
+ NULL,
+ NULL);
+ dbus_error_free (&dbus_error);
+ goto out;
+ }
+
+ if (!dbus_message_get_args (reply,
+ &dbus_error,
+ DBUS_TYPE_UINT32, &release_name_reply,
+ DBUS_TYPE_INVALID))
+ {
+ g_dbus_error_set_dbus_error (error,
+ &dbus_error,
+ NULL,
+ NULL);
+ dbus_error_free (&dbus_error);
+ goto out;
+ }
+
+ out:
+ if (message != NULL)
+ dbus_message_unref (message);
+ if (reply != NULL)
+ dbus_message_unref (reply);
+
+ return release_name_reply;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static guint
+get_request_name_flags (GBusNameOwnerFlags flags)
+{
+ guint request_name_flags;
+
+ request_name_flags = 0;
+ if (flags & G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT)
+ request_name_flags |= DBUS_NAME_FLAG_ALLOW_REPLACEMENT;
+ if (flags & G_BUS_NAME_OWNER_FLAGS_REPLACE)
+ request_name_flags |= DBUS_NAME_FLAG_REPLACE_EXISTING;
+
+ return request_name_flags;
+}
+
+static void
+bus_request_name_cb (DBusPendingCall *pending,
+ void *user_data)
+{
+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (user_data);
+ DBusMessage *reply;
+ DBusError dbus_error;
+ GError *error;
+ dbus_uint32_t request_name_reply;
+
+ reply = dbus_pending_call_steal_reply (pending);
+ g_assert (reply != NULL);
+
+ dbus_error_init (&dbus_error);
+ if (dbus_message_get_args (reply,
+ &dbus_error,
+ DBUS_TYPE_UINT32, &request_name_reply,
+ DBUS_TYPE_INVALID))
+ {
+ g_simple_async_result_set_op_res_gpointer (simple, GINT_TO_POINTER (request_name_reply), NULL);
+ goto done;
+ }
+
+ error = g_dbus_error_new_for_dbus_error (&dbus_error,
+ NULL,
+ NULL);
+ g_simple_async_result_set_from_error (simple, error);
+ g_error_free (error);
+ dbus_error_free (&dbus_error);
+
+ done:
+ g_simple_async_result_complete (simple);
+ g_object_unref (simple);
+ dbus_message_unref (reply);
+}
+
+static void
+bus_request_name (GDBusConnection *connection,
+ const gchar *name,
+ guint flags,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *simple;
+ DBusMessage *message;
+ DBusPendingCall *pending_call;
+
+ g_return_if_fail (G_IS_DBUS_CONNECTION (connection));
+ g_return_if_fail (name != NULL);
+
+ simple = g_simple_async_result_new (G_OBJECT (connection),
+ callback,
+ user_data,
+ bus_request_name);
+
+ if (g_dbus_connection_get_dbus_1_connection (connection) == NULL)
+ {
+ g_simple_async_result_set_error (simple,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_FAILED,
+ _("Not connected to message bus"));
+ g_simple_async_result_complete (simple);
+ g_object_unref (simple);
+ goto out;
+ }
+
+ if ((message = dbus_message_new_method_call (DBUS_SERVICE_DBUS,
+ DBUS_PATH_DBUS,
+ DBUS_INTERFACE_DBUS,
+ "RequestName")) == NULL)
+ _g_dbus_oom ();
+ if (!dbus_message_append_args (message,
+ DBUS_TYPE_STRING, &name,
+ DBUS_TYPE_UINT32, &flags,
+ DBUS_TYPE_INVALID))
+ _g_dbus_oom ();
+
+ if (!dbus_connection_send_with_reply (g_dbus_connection_get_dbus_1_connection (connection),
+ message,
+ &pending_call,
+ -1))
+ _g_dbus_oom ();
+
+ dbus_message_unref (message);
+
+ dbus_pending_call_set_notify (pending_call,
+ bus_request_name_cb,
+ simple,
+ NULL);
+
+ out:
+ ;
+}
+
+static guint
+bus_request_name_finish (GDBusConnection *bus,
+ GAsyncResult *res,
+ GError **error)
+{
+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res);
+ guint ret;
+
+ ret = 0;
+
+ g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == bus_request_name);
+
+ if (g_simple_async_result_propagate_error (simple, error))
+ goto out;
+
+ ret = GPOINTER_TO_INT (g_simple_async_result_get_op_res_gpointer (simple));
+
+ out:
+ return ret;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+typedef struct
+{
+ GAsyncReadyCallback callback;
+ gpointer user_data;
+ GBusNameOwner *owner;
+ gboolean is_for_connection;
+} ConstructData;
+
+static void
+construct_data_free (ConstructData *data)
+{
+ g_free (data);
+}
+
+static void
+request_name_cb (GDBusConnection *connection,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ ConstructData *data = user_data;
+ GSimpleAsyncResult *simple;
+ GError *error;
+ guint reply;
+
+ simple = g_simple_async_result_new (G_OBJECT (data->owner),
+ data->callback,
+ data->user_data,
+ data->is_for_connection ? g_bus_name_owner_new_for_connection_finish : g_bus_name_owner_new_finish);
+
+ error = NULL;
+ reply = bus_request_name_finish (connection,
+ result,
+ &error);
+ if (error != NULL)
+ {
+ g_simple_async_result_set_from_error (simple,
+ error);
+ g_error_free (error);
+ }
+ else
+ {
+ if (reply != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)
+ {
+ g_simple_async_result_set_error (simple,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_FAILED,
+ _("Error acquiring name, RequestName() returned %d"),
+ reply);
+ }
+ else
+ {
+ data->owner->priv->owns_name = TRUE;
+ g_signal_emit (data->owner, signals[NAME_ACQUIRED_SIGNAL], 0);
+ }
+ }
+
+ data->owner->priv->in_construction_phase = FALSE;
+ g_simple_async_result_complete_in_idle (simple);
+ g_object_unref (simple);
+ construct_data_free (data);
+}
+
+static void
+get_connection_cb (GDBusConnection *connection,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ ConstructData *data = user_data;
+ GError *error;
+
+ error = NULL;
+ if (!g_dbus_connection_bus_get_finish (connection,
+ result,
+ &error))
+ {
+ GSimpleAsyncResult *simple;
+
+ /* connection is not open.. report back */
+ simple = g_simple_async_result_new (G_OBJECT (data->owner),
+ data->callback,
+ data->user_data,
+ g_bus_name_owner_new_finish);
+ g_simple_async_result_set_from_error (simple,
+ error);
+ g_error_free (error);
+
+ data->owner->priv->in_construction_phase = FALSE;
+ g_simple_async_result_complete_in_idle (simple);
+ g_object_unref (simple);
+ construct_data_free (data);
+ }
+ else
+ {
+ /* connection is open.. try to claim the name */
+
+ bus_request_name (data->owner->priv->connection,
+ data->owner->priv->name,
+ get_request_name_flags (data->owner->priv->flags),
+ (GAsyncReadyCallback) request_name_cb,
+ data);
+ }
+
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+/**
+ * g_bus_name_owner_new:
+ * @bus_type: A #GMessageBusType specifying what message bus to connect to.
+ * @name: A well-known name to acquire.
+ * @flags: A set of flags from the #GBusNameOwnerFlags enumeration.
+ * @cancellable: %NULL or a #GCancellable.
+ * @callback: The callback function to invoke when finished acquiring the name.
+ * @user_data: User data to pass to @callback.
+ *
+ * Creates a new #GBusNameOwner and then attempts to own @name on the
+ * bus specified by @bus_type. When the attempt to own the name is
+ * finished, @callback will be invoked (on the main thread) and you
+ * can use g_bus_name_owner_new_finish() to get the result.
+ *
+ * This class is the preferred way to implement D-Bus
+ * services. The canonical example follows.
+ * <example><title>Using g_bus_name_owner_new()</title><programlisting><xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="../../../../gdbus/example-gbusnameowner.c"><xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting></example>
+ *
+ * Returns: A #GBusNameOwner object. Free with g_object_unref().
+ **/
+GBusNameOwner *
+g_bus_name_owner_new (GMessageBusType bus_type,
+ const gchar *name,
+ GBusNameOwnerFlags flags,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GBusNameOwner *owner;
+ GDBusConnection *connection;
+ ConstructData *data;
+
+ data = g_new0 (ConstructData, 1);
+ data->callback = callback;
+ data->user_data = user_data;
+
+ connection = g_dbus_connection_bus_get (bus_type,
+ cancellable,
+ (GAsyncReadyCallback) get_connection_cb,
+ data);
+
+ owner = G_BUS_NAME_OWNER (g_object_new (G_TYPE_BUS_NAME_OWNER,
+ "name", name,
+ "connection", connection,
+ "flags", flags,
+ NULL));
+
+ data->owner = owner;
+ owner->priv->in_construction_phase = TRUE;
+
+ g_object_unref (connection);
+
+ return owner;
+}
+
+/**
+ * g_bus_name_owner_new_finish:
+ * @owner: A #GBusNameOwner.
+ * @res: A #GAsyncResult obtained from the #GAsyncReadyCallback function passed to g_bus_name_owner_get().
+ * @error: Return location for error or %NULL.
+ *
+ * Finishes attempting to acquire a name.
+ *
+ * Returns: %TRUE if the name was acquired, otherwise %FALSE with @error set.
+ **/
+gboolean
+g_bus_name_owner_new_finish (GBusNameOwner *owner,
+ GAsyncResult *res,
+ GError **error)
+{
+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res);
+
+ g_return_val_if_fail (G_IS_BUS_NAME_OWNER (owner), FALSE);
+
+ g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == g_bus_name_owner_new_finish);
+
+ return !g_simple_async_result_propagate_error (simple, error);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+/**
+ * g_bus_name_owner_new_for_connection:
+ * @connection: A #GDBusConnection.
+ * @name: A well-known name to acquire.
+ * @flags: A set of flags from the #GBusNameOwnerFlags enumeration.
+ * @cancellable: %NULL or a #GCancellable.
+ * @callback: The callback function to invoke when finished acquiring the name.
+ * @user_data: User data to pass to @callback.
+ *
+ * Like g_bus_name_owner_new() but allows you to pass in a
+ * #GDBusConnection.
+ *
+ * Returns: A #GBusNameOwner object. Free with g_object_unref().
+ **/
+GBusNameOwner *
+g_bus_name_owner_new_for_connection (GDBusConnection *connection,
+ const gchar *name,
+ GBusNameOwnerFlags flags,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GBusNameOwner *owner;
+
+ owner = G_BUS_NAME_OWNER (g_object_new (G_TYPE_BUS_NAME_OWNER,
+ "name", name,
+ "connection", connection,
+ "flags", flags,
+ NULL));
+
+ if (g_dbus_connection_get_is_open (connection))
+ {
+ ConstructData *data;
+ data = g_new0 (ConstructData, 1);
+ data->callback = callback;
+ data->user_data = user_data;
+ data->is_for_connection = TRUE;
+ data->owner = owner;
+ owner->priv->in_construction_phase = TRUE;
+
+ /* connection is open.. try to claim the name */
+ bus_request_name (data->owner->priv->connection,
+ data->owner->priv->name,
+ get_request_name_flags (data->owner->priv->flags),
+ (GAsyncReadyCallback) request_name_cb,
+ data);
+ }
+ else
+ {
+ GSimpleAsyncResult *simple;
+
+ /* connection is not open.. report back in idle
+ *
+ * TODO: maybe handle g_dbus_connection_is_connecting() or something...
+ */
+ simple = g_simple_async_result_new (G_OBJECT (owner),
+ callback,
+ user_data,
+ g_bus_name_owner_new_for_connection_finish);
+ g_simple_async_result_set_error (simple,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_FAILED,
+ _("Connection is not open"));
+
+ g_simple_async_result_complete_in_idle (simple);
+ g_object_unref (simple);
+ }
+
+ return owner;
+}
+
+/**
+ * g_bus_name_owner_new_for_connection_finish:
+ * @owner: A #GBusNameOwner.
+ * @res: A #GAsyncResult obtained from the #GAsyncReadyCallback
+ * function passed to g_bus_name_owner_get_for_connection().
+ * @error: Return location for error or %NULL.
+ *
+ * Finishes attempting to acquire a name.
+ *
+ * Returns: %TRUE if the name was acquired, otherwise %FALSE with @error set.
+ **/
+gboolean
+g_bus_name_owner_new_for_connection_finish (GBusNameOwner *owner,
+ GAsyncResult *res,
+ GError **error)
+{
+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res);
+
+ g_return_val_if_fail (G_IS_BUS_NAME_OWNER (owner), FALSE);
+
+ g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == g_bus_name_owner_new_for_connection_finish);
+
+ return !g_simple_async_result_propagate_error (simple, error);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+/**
+ * g_bus_name_owner_get_owns_name:
+ * @owner: A #GBusNameOwner.
+ *
+ * Gets whether @owner currently owns the name it was constructed with.
+ *
+ * You can track changes to this value by listening to the
+ * #GBusNameOwner::name-acquired and #GBusNameOwner::name-lost signals
+ * or by listning to changes on the #GBusNameOwner:owns-name property.
+ *
+ * Returns: %TRUE if @owner owns the name it was constructed with,
+ * %FALSE otherwise.
+ **/
+gboolean
+g_bus_name_owner_get_owns_name (GBusNameOwner *owner)
+{
+ g_return_val_if_fail (G_IS_BUS_NAME_OWNER (owner), FALSE);
+
+ return owner->priv->owns_name;
+}
+
+/**
+ * g_bus_name_owner_get_name:
+ * @owner: A #GBusNameOwner.
+ *
+ * Gets the well-known name that @owner was constructed with.
+ *
+ * Returns: The well-known name for @owner. Do not free this string,
+ * it is owned by @owner.
+ **/
+const gchar *
+g_bus_name_owner_get_name (GBusNameOwner *owner)
+{
+ g_return_val_if_fail (G_IS_BUS_NAME_OWNER (owner), NULL);
+
+ return owner->priv->name;
+}
+
+/**
+ * g_bus_name_owner_get_flags:
+ * @owner: A #GBusNameOwner.
+ *
+ * Gets the flags that @owner was constructed with.
+ *
+ * Returns: Flags from the #GBusNameOwnerFlags enumeration.
+ **/
+GBusNameOwnerFlags
+g_bus_name_owner_get_flags (GBusNameOwner *owner)
+{
+ g_return_val_if_fail (G_IS_BUS_NAME_OWNER (owner), 0);
+
+ return owner->priv->flags;
+}
+
+/**
+ * g_bus_name_owner_get_connection:
+ * @owner: A #GBusNameOwner.
+ *
+ * Gets the #GDBusConnection used for @owner.
+ *
+ * Returns: A #GDBusConnection object owned by @owner. Do not unref.
+ **/
+GDBusConnection *
+g_bus_name_owner_get_connection (GBusNameOwner *owner)
+{
+ g_return_val_if_fail (G_IS_BUS_NAME_OWNER (owner), NULL);
+
+ return owner->priv->connection;
+}
+
+#define __G_BUS_NAME_OWNER_C__
+#include "gdbusaliasdef.c"
diff --git a/gdbus/gbusnameowner.h b/gdbus/gbusnameowner.h
new file mode 100644
index 0000000..1927b49
--- /dev/null
+++ b/gdbus/gbusnameowner.h
@@ -0,0 +1,114 @@
+/* GDBus - GLib D-Bus Library
+ *
+ * Copyright (C) 2008-2009 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: David Zeuthen <davidz redhat com>
+ */
+
+#if !defined (__G_DBUS_G_DBUS_H_INSIDE__) && !defined (G_DBUS_COMPILATION)
+#error "Only <gdbus/gdbus.h> can be included directly."
+#endif
+
+#ifndef __G_BUS_NAME_OWNER_H__
+#define __G_BUS_NAME_OWNER_H__
+
+#include <gdbus/gdbustypes.h>
+#include <dbus/dbus.h>
+
+G_BEGIN_DECLS
+
+#define G_TYPE_BUS_NAME_OWNER (g_bus_name_owner_get_type ())
+#define G_BUS_NAME_OWNER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_BUS_NAME_OWNER, GBusNameOwner))
+#define G_BUS_NAME_OWNER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_BUS_NAME_OWNER, GBusNameOwnerClass))
+#define G_BUS_NAME_OWNER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_BUS_NAME_OWNER, GBusNameOwnerClass))
+#define G_IS_BUS_NAME_OWNER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_BUS_NAME_OWNER))
+#define G_IS_BUS_NAME_OWNER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_BUS_NAME_OWNER))
+
+typedef struct _GBusNameOwnerClass GBusNameOwnerClass;
+typedef struct _GBusNameOwnerPrivate GBusNameOwnerPrivate;
+
+/**
+ * GBusNameOwner:
+ *
+ * The #GBusNameOwner structure contains only private data and
+ * should only be accessed using the provided API.
+ */
+struct _GBusNameOwner
+{
+ /*< private >*/
+ GObject parent_instance;
+ GBusNameOwnerPrivate *priv;
+};
+
+/**
+ * GBusNameOwnerClass:
+ * @name_acquired: Signal class handler for the #GBusNameOwner::name-acquired signal.
+ * @name_lost: Signal class handler for the #GBusNameOwner::name-lost signal.
+ *
+ * Class structure for #GBusNameOwner.
+ */
+struct _GBusNameOwnerClass
+{
+ /*< private >*/
+ GObjectClass parent_class;
+
+ /*< public >*/
+
+ /* Signals */
+ void (*name_acquired) (GBusNameOwner *owner);
+ void (*name_lost) (GBusNameOwner *owner);
+
+ /*< private >*/
+ /* Padding for future expansion */
+ void (*_g_reserved1) (void);
+ void (*_g_reserved2) (void);
+ void (*_g_reserved3) (void);
+ void (*_g_reserved4) (void);
+ void (*_g_reserved5) (void);
+ void (*_g_reserved6) (void);
+ void (*_g_reserved7) (void);
+ void (*_g_reserved8) (void);
+};
+
+GType g_bus_name_owner_get_type (void) G_GNUC_CONST;
+GBusNameOwner *g_bus_name_owner_new (GMessageBusType bus_type,
+ const gchar *name,
+ GBusNameOwnerFlags flags,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean g_bus_name_owner_new_finish (GBusNameOwner *owner,
+ GAsyncResult *res,
+ GError **error);
+GBusNameOwner *g_bus_name_owner_new_for_connection (GDBusConnection *connection,
+ const gchar *name,
+ GBusNameOwnerFlags flags,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean g_bus_name_owner_new_for_connection_finish (GBusNameOwner *owner,
+ GAsyncResult *res,
+ GError **error);
+gboolean g_bus_name_owner_get_owns_name (GBusNameOwner *owner);
+const gchar *g_bus_name_owner_get_name (GBusNameOwner *owner);
+GBusNameOwnerFlags g_bus_name_owner_get_flags (GBusNameOwner *owner);
+GDBusConnection *g_bus_name_owner_get_connection (GBusNameOwner *owner);
+
+G_END_DECLS
+
+#endif /* __G_BUS_NAME_OWNER_H__ */
diff --git a/gdbus/gdbus-marshal.list b/gdbus/gdbus-marshal.list
new file mode 100644
index 0000000..02fd6ad
--- /dev/null
+++ b/gdbus/gdbus-marshal.list
@@ -0,0 +1 @@
+VOID:OBJECT,OBJECT,ENUM
diff --git a/gdbus/gdbus.h b/gdbus/gdbus.h
new file mode 100644
index 0000000..6abebc3
--- /dev/null
+++ b/gdbus/gdbus.h
@@ -0,0 +1,37 @@
+/* GDBus - GLib D-Bus Library
+ *
+ * Copyright (C) 2008-2009 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: David Zeuthen <davidz redhat com>
+ */
+
+#ifndef __G_DBUS_H__
+#define __G_DBUS_H__
+
+#define __G_DBUS_G_DBUS_H_INSIDE__
+
+#include <gdbus/gdbustypes.h>
+#include <gdbus/gdbusenumtypes.h>
+#include <gdbus/gdbusmainloop.h>
+#include <gdbus/gdbusconnection.h>
+#include <gdbus/gdbuserror.h>
+#include <gdbus/gbusnameowner.h>
+
+#undef __G_DBUS_D_DBUS_H_INSIDE__
+
+#endif /* __G_DBUS_H__ */
diff --git a/gdbus/gdbus.symbols b/gdbus/gdbus.symbols
new file mode 100644
index 0000000..cf10bc3
--- /dev/null
+++ b/gdbus/gdbus.symbols
@@ -0,0 +1,73 @@
+/* This file lists all exported symbols. It is used to generate
+ * the gio.def file used to control exports on Windows and the
+ * gioalias.h/gioaliasdef.c files used to avoid PLT entries for
+ * internal uses of exported functions (see makegioalias.pl).
+ *
+ * Every symbol must be included in the right
+ * #ifdef IN_HEADER(sym) #endif and
+ * #ifdef IN_FILE(sym) #endif sections.
+ */
+
+#ifdef ALL_FILES
+#define IN_FILE(x) 1
+#define IN_HEADER(x) 1
+#endif
+
+#if IN_HEADER(__G_DBUS_CONNECTION_H__)
+#if IN_FILE(__G_DBUS_CONNECTION_C__)
+g_dbus_connection_get_type G_GNUC_CONST
+g_dbus_connection_bus_get
+g_dbus_connection_bus_get_finish
+g_dbus_connection_bus_get_private
+g_dbus_connection_bus_get_private_finish
+g_dbus_connection_get_unique_name
+g_dbus_connection_get_is_open
+g_dbus_connection_get_bus_type
+g_dbus_connection_get_dbus_1_connection
+g_dbus_connection_get_exit_on_close
+g_dbus_connection_set_exit_on_close
+#endif
+#endif
+
+#if IN_HEADER(__G_BUS_NAME_OWNER_H__)
+#if IN_FILE(__G_BUS_NAME_OWNER_C__)
+g_bus_name_owner_new
+g_bus_name_owner_new_finish
+g_bus_name_owner_new_for_connection
+g_bus_name_owner_new_for_connection_finish
+g_bus_name_owner_get_connection
+g_bus_name_owner_get_flags
+g_bus_name_owner_get_name
+g_bus_name_owner_get_owns_name
+g_bus_name_owner_get_type
+#endif
+#endif
+
+#if IN_HEADER(__G_DBUS_MAINLOOP_H__)
+#if IN_FILE(__G_DBUS_MAINLOOP_C__)
+g_dbus_integrate_dbus_1_connection
+g_dbus_unintegrate_dbus_1_connection
+g_dbus_integrate_dbus_1_server
+g_dbus_unintegrate_dbus_1_server
+#endif
+#endif
+
+#if IN_HEADER(__G_DBUS_ENUM_TYPES_H__)
+#if IN_FILE(__G_DBUS_ENUM_TYPES_C__)
+g_dbus_error_get_type G_GNUC_CONST
+g_message_bus_type_get_type G_GNUC_CONST
+g_bus_name_owner_flags_get_type
+#endif
+#endif
+
+#if IN_HEADER(__G_DBUS_ERROR_H__)
+#if IN_FILE(__G_DBUS_ERROR_C__)
+g_dbus_error_quark
+g_dbus_error_get_remote_exception
+g_dbus_error_new_for_dbus_error
+g_dbus_error_new_for_dbus_error_valist
+g_dbus_error_new_for_gerror
+g_dbus_error_set_dbus_error
+g_dbus_error_set_dbus_error_valist
+#endif
+#endif
diff --git a/gdbus/gdbusconnection.c b/gdbus/gdbusconnection.c
new file mode 100644
index 0000000..a461862
--- /dev/null
+++ b/gdbus/gdbusconnection.c
@@ -0,0 +1,964 @@
+/* GDBus - GLib D-Bus Library
+ *
+ * Copyright (C) 2008-2009 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: David Zeuthen <davidz redhat com>
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+
+#include <glib/gi18n.h>
+
+#include "gdbusconnection.h"
+#include "gdbusmainloop.h"
+#include "gdbuserror.h"
+#include "gdbusprivate.h"
+#include "gdbusenumtypes.h"
+
+#include "gdbusalias.h"
+
+/**
+ * SECTION:gdbusconnection
+ * @short_description: D-Bus Connections
+ * @include: gdbus/gdbus.h
+ *
+ * #GDBusConnection is a thin wrapper class for the #DBusConnection
+ * type that integrates with the GLib type system. The connection
+ * state of the underlying connection is tracked and upon
+ * disconnection, #GDBusConnection instances will attempt to reconnect
+ * to the remote end.
+ *
+ * TODO: stuff about caching unix_process_id etc. when we add that.
+ */
+
+struct _GDBusConnectionPrivate
+{
+ DBusConnection *dbus_1_connection;
+
+ GMessageBusType bus_type;
+
+ guint reconnect_timer_id;
+
+ /* unfortunately there is no dbus_connection_get_exit_on_disconnect() so we need to track this ourselves */
+ gboolean exit_on_close;
+
+ gboolean is_private;
+};
+
+enum
+{
+ OPENED_SIGNAL,
+ CLOSED_SIGNAL,
+ LAST_SIGNAL,
+};
+
+enum
+{
+ PROP_0,
+ PROP_BUS_TYPE,
+ PROP_UNIQUE_NAME,
+ PROP_IS_OPEN,
+ PROP_EXIT_ON_CLOSE,
+ PROP_DBUS_1_CONNECTION,
+};
+
+G_LOCK_DEFINE_STATIC (connection_lock);
+static GDBusConnection *the_session_bus = NULL;
+static GDBusConnection *the_system_bus = NULL;
+
+static DBusHandlerResult
+filter_function (DBusConnection *dbus_1_connection,
+ DBusMessage *message,
+ void *user_data);
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+static void g_dbus_connection_set_dbus_1_connection (GDBusConnection *connection,
+ DBusConnection *dbus_1_connection);
+
+G_DEFINE_TYPE (GDBusConnection, g_dbus_connection, G_TYPE_OBJECT);
+
+static void
+g_dbus_connection_dispose (GObject *object)
+{
+ GDBusConnection *connection = G_DBUS_CONNECTION (object);
+
+ G_LOCK (connection_lock);
+ if (connection == the_session_bus)
+ {
+ the_session_bus = NULL;
+ }
+ else if (connection == the_system_bus)
+ {
+ the_system_bus = NULL;
+ }
+ G_UNLOCK (connection_lock);
+
+ if (G_OBJECT_CLASS (g_dbus_connection_parent_class)->dispose != NULL)
+ G_OBJECT_CLASS (g_dbus_connection_parent_class)->dispose (object);
+}
+
+static void
+g_dbus_connection_finalize (GObject *object)
+{
+ GDBusConnection *connection = G_DBUS_CONNECTION (object);
+
+ if (connection->priv->reconnect_timer_id > 0)
+ g_source_remove (connection->priv->reconnect_timer_id);
+
+ g_dbus_connection_set_dbus_1_connection (connection, NULL);
+
+ if (G_OBJECT_CLASS (g_dbus_connection_parent_class)->finalize != NULL)
+ G_OBJECT_CLASS (g_dbus_connection_parent_class)->finalize (object);
+}
+
+static void
+g_dbus_connection_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GDBusConnection *connection = G_DBUS_CONNECTION (object);
+
+ switch (prop_id)
+ {
+ case PROP_DBUS_1_CONNECTION:
+ g_value_set_pointer (value, g_dbus_connection_get_dbus_1_connection (connection));
+ break;
+
+ case PROP_BUS_TYPE:
+ g_value_set_enum (value, g_dbus_connection_get_bus_type (connection));
+ break;
+
+ case PROP_UNIQUE_NAME:
+ g_value_set_string (value, g_dbus_connection_get_unique_name (connection));
+ break;
+
+ case PROP_IS_OPEN:
+ g_value_set_boolean (value, g_dbus_connection_get_is_open (connection));
+ break;
+
+ case PROP_EXIT_ON_CLOSE:
+ g_value_set_boolean (value, g_dbus_connection_get_exit_on_close (connection));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+g_dbus_connection_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GDBusConnection *connection = G_DBUS_CONNECTION (object);
+
+ switch (prop_id)
+ {
+ case PROP_DBUS_1_CONNECTION:
+ g_dbus_connection_set_dbus_1_connection (connection, g_value_get_pointer (value));
+ break;
+
+ case PROP_BUS_TYPE:
+ connection->priv->bus_type = g_value_get_enum (value);
+ break;
+
+ case PROP_EXIT_ON_CLOSE:
+ g_dbus_connection_set_exit_on_close (connection, g_value_get_boolean (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+g_dbus_connection_class_init (GDBusConnectionClass *klass)
+{
+ GObjectClass *gobject_class;
+
+ g_type_class_add_private (klass, sizeof (GDBusConnectionPrivate));
+
+ gobject_class = G_OBJECT_CLASS (klass);
+
+ gobject_class->finalize = g_dbus_connection_finalize;
+ gobject_class->dispose = g_dbus_connection_dispose;
+ gobject_class->set_property = g_dbus_connection_set_property;
+ gobject_class->get_property = g_dbus_connection_get_property;
+
+ /**
+ * GDBusConnection:dbus-1-connection:
+ *
+ * The underlying #DBusConnection object for the connection or %NULL
+ * if the connection is not open.
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_DBUS_1_CONNECTION,
+ g_param_spec_pointer ("dbus-1-connection",
+ _("dbus-1-connection"),
+ _("The underlying DBusConnection object for the connection"),
+ G_PARAM_WRITABLE |
+ G_PARAM_READABLE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_NAME |
+ G_PARAM_STATIC_BLURB |
+ G_PARAM_STATIC_NICK));
+
+ /**
+ * GDBusConnection:bus-type:
+ *
+ * Type type of the message bus the connection is for or
+ * #G_MESSAGE_BUS_TYPE_NONE if the connection is not to a message
+ * bus.
+ *
+ * This property is never #G_MESSAGE_BUS_TYPE_STARTER. If
+ * #G_MESSAGE_BUS_TYPE_STARTER was passed to g_dbus_connection_get()
+ * then this property will be either #G_MESSAGE_BUS_TYPE_SESSION or
+ * #G_MESSAGE_BUS_TYPE_SYSTEM depending on what bus started the
+ * process.
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_BUS_TYPE,
+ g_param_spec_enum ("bus-type",
+ _("bus-type"),
+ _("The type of message bus the connection is for"),
+ G_TYPE_MESSAGE_BUS_TYPE,
+ G_MESSAGE_BUS_TYPE_NONE,
+ G_PARAM_READABLE |
+ G_PARAM_WRITABLE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_NAME |
+ G_PARAM_STATIC_BLURB |
+ G_PARAM_STATIC_NICK));
+
+ /**
+ * GDBusConnection:unique-name:
+ *
+ * The unique name as assigned by the message bus or %NULL if the
+ * connection is closed or not a message bus connection.
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_IS_OPEN,
+ g_param_spec_string ("unique-name",
+ _("unique-name"),
+ _("Unique name of bus connection"),
+ NULL,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_NAME |
+ G_PARAM_STATIC_BLURB |
+ G_PARAM_STATIC_NICK));
+
+ /**
+ * GDBusConnection:is-open:
+ *
+ * A boolean specifying whether a connection the is open.
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_IS_OPEN,
+ g_param_spec_boolean ("is-open",
+ _("is-open"),
+ _("Whether the connection is open"),
+ FALSE,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_NAME |
+ G_PARAM_STATIC_BLURB |
+ G_PARAM_STATIC_NICK));
+
+ /**
+ * GDBusConnection:exit-on-close:
+ *
+ * A boolean specifying whether _exit() should be called when the
+ * connection is closed.
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_EXIT_ON_CLOSE,
+ g_param_spec_boolean ("exit-on-close",
+ _("exit-on-close"),
+ _("Whether _exit() is called when the connection is closed"),
+ TRUE,
+ G_PARAM_READABLE |
+ G_PARAM_WRITABLE |
+ G_PARAM_CONSTRUCT |
+ G_PARAM_STATIC_NAME |
+ G_PARAM_STATIC_BLURB |
+ G_PARAM_STATIC_NICK));
+
+ /**
+ * GDBusConnection::opened:
+ * @connection: The #GDBusConnection emitting the signal.
+ *
+ * Emitted when the connection is established.
+ **/
+ signals[OPENED_SIGNAL] = g_signal_new ("opened",
+ G_TYPE_DBUS_CONNECTION,
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GDBusConnectionClass, opened),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+
+ /**
+ * GDBusConnection::closed:
+ * @connection: The #GDBusConnection emitting the signal.
+ *
+ * Emitted when the connection is closed.
+ **/
+ signals[CLOSED_SIGNAL] = g_signal_new ("closed",
+ G_TYPE_DBUS_CONNECTION,
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GDBusConnectionClass, closed),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+}
+
+static void
+g_dbus_connection_init (GDBusConnection *connection)
+{
+ connection->priv = G_TYPE_INSTANCE_GET_PRIVATE (connection, G_TYPE_DBUS_CONNECTION, GDBusConnectionPrivate);
+}
+
+/**
+ * g_dbus_connection_get_bus_type:
+ * @connection: A #GDBusConnection.
+ *
+ * Gets the type of message bus connection, if any.
+ *
+ * This will never return #G_MESSAGE_BUS_TYPE_STARTER. If
+ * #G_MESSAGE_BUS_TYPE_STARTER was passed to g_dbus_connection_get()
+ * then the return value will be either #G_MESSAGE_BUS_TYPE_SESSION or
+ * #G_MESSAGE_BUS_TYPE_SYSTEM depending on what bus started the
+ * process.
+ *
+ * Returns: Type type of the message bus the connection is for or
+ * #G_MESSAGE_BUS_TYPE_NONE if the connection is not to a message
+ * bus.
+ **/
+GMessageBusType
+g_dbus_connection_get_bus_type (GDBusConnection *connection)
+{
+ g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), G_MESSAGE_BUS_TYPE_NONE);
+
+ return connection->priv->bus_type;
+}
+
+
+/**
+ * g_dbus_connection_get_is_open:
+ * @connection: A #GDBusConnection.
+ *
+ * Gets whether a connection is open.
+ *
+ * To listen for changes connect to the #GDBusConnection::opened and
+ * #GDBusConnection::closed signals or listen for notifications on the
+ * #GDBusConnection:is-open property.
+ *
+ * Returns: %TRUE if the connection is open, %FALSE otherwise.
+ **/
+gboolean
+g_dbus_connection_get_is_open (GDBusConnection *connection)
+{
+ g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), FALSE);
+
+ return connection->priv->dbus_1_connection != NULL &&
+ dbus_connection_get_is_connected (connection->priv->dbus_1_connection);
+}
+
+/**
+ * g_dbus_connection_get_dbus_1_connection:
+ * @connection: A #GDBusConnection.
+ *
+ * Gets the underlying #DBusConnection object for @connection.
+ *
+ * Returns: %NULL if the connection is not open, otherwise a
+ * #DBusConnection object owned by @connection.
+ **/
+DBusConnection *
+g_dbus_connection_get_dbus_1_connection (GDBusConnection *connection)
+{
+ g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL);
+
+ return connection->priv->dbus_1_connection;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static gboolean
+attempt_connect (GDBusConnection *connection,
+ GError **error)
+{
+ DBusError dbus_error;
+ gboolean ret;
+ DBusConnection *dbus_1_connection;
+
+ ret = FALSE;
+
+ g_assert (connection->priv->dbus_1_connection == NULL);
+
+ dbus_error_init (&dbus_error);
+ g_assert (connection->priv->bus_type != G_MESSAGE_BUS_TYPE_NONE); // until we have constructors with @address
+ if (connection->priv->is_private)
+ {
+ dbus_1_connection = dbus_bus_get_private (connection->priv->bus_type,
+ &dbus_error);
+ }
+ else
+ {
+ dbus_1_connection = dbus_bus_get (connection->priv->bus_type,
+ &dbus_error);
+ }
+
+ if (dbus_1_connection != NULL)
+ {
+ g_dbus_connection_set_dbus_1_connection (connection, dbus_1_connection);
+ dbus_connection_unref (dbus_1_connection);
+ g_signal_emit (connection, signals[OPENED_SIGNAL], 0);
+ g_object_notify (G_OBJECT (connection), "is-open");
+ ret = TRUE;
+ }
+ else
+ {
+ g_dbus_error_set_dbus_error (error,
+ &dbus_error,
+ NULL,
+ NULL);
+ dbus_error_free (&dbus_error);
+ }
+
+ return ret;
+}
+
+static gboolean
+reconnect_timeout (gpointer user_data)
+{
+ GDBusConnection *connection = G_DBUS_CONNECTION (user_data);
+ gboolean keep_timeout;
+
+ keep_timeout = TRUE;
+ if (attempt_connect (connection, NULL))
+ {
+ keep_timeout = FALSE;
+ connection->priv->reconnect_timer_id = 0;
+ }
+
+ return keep_timeout;
+}
+
+static void
+setup_reconnect_timer (GDBusConnection *connection)
+{
+ g_assert (connection->priv->reconnect_timer_id == 0);
+
+ connection->priv->reconnect_timer_id = g_timeout_add_seconds (1,
+ reconnect_timeout,
+ connection);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+#define PRINT_MESSAGE(message) \
+ do { \
+ const gchar *message_type; \
+ switch (dbus_message_get_type (message)) \
+ { \
+ case DBUS_MESSAGE_TYPE_METHOD_CALL: \
+ message_type = "method_call"; \
+ break; \
+ case DBUS_MESSAGE_TYPE_METHOD_RETURN: \
+ message_type = "method_return"; \
+ break; \
+ case DBUS_MESSAGE_TYPE_ERROR: \
+ message_type = "error"; \
+ break; \
+ case DBUS_MESSAGE_TYPE_SIGNAL: \
+ message_type = "signal"; \
+ break; \
+ case DBUS_MESSAGE_TYPE_INVALID: \
+ message_type = "invalid"; \
+ break; \
+ default: \
+ message_type = "unknown"; \
+ break; \
+ } \
+ g_print ("new message:\n" \
+ " type: %s\n" \
+ " sender: %s\n" \
+ " destination: %s\n" \
+ " path: %s\n" \
+ " interface: %s\n" \
+ " member: %s\n", \
+ message_type, \
+ dbus_message_get_sender (message), \
+ dbus_message_get_destination (message), \
+ dbus_message_get_path (message), \
+ dbus_message_get_interface (message), \
+ dbus_message_get_member (message)); \
+ } while (FALSE)
+
+static DBusHandlerResult
+filter_function (DBusConnection *dbus_1_connection,
+ DBusMessage *message,
+ void *user_data)
+{
+ GDBusConnection *connection = G_DBUS_CONNECTION (user_data);
+ DBusError dbus_error;
+
+ g_debug ("in filter_function for dbus_1_connection %p", dbus_1_connection);
+ PRINT_MESSAGE (message);
+
+ dbus_error_init (&dbus_error);
+
+ /* check if we are disconnected from the bus */
+ if (dbus_message_is_signal (message,
+ DBUS_INTERFACE_LOCAL,
+ "Disconnected") &&
+ dbus_message_get_sender (message) == NULL &&
+ dbus_message_get_destination (message) == NULL &&
+ g_strcmp0 (dbus_message_get_path (message), DBUS_PATH_LOCAL) == 0)
+ {
+ if (connection->priv->dbus_1_connection != NULL)
+ {
+ g_dbus_connection_set_dbus_1_connection (connection, NULL);
+
+ //g_object_notify (G_OBJECT (bus), "unique-name");
+ g_object_notify (G_OBJECT (connection), "is-open");
+ g_signal_emit (connection, signals[CLOSED_SIGNAL], 0);
+
+ /* set up timer for attempting to reconnect */
+ setup_reconnect_timer (connection);
+ }
+ }
+
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+static void
+g_dbus_connection_set_dbus_1_connection (GDBusConnection *connection,
+ DBusConnection *dbus_1_connection)
+{
+ g_return_if_fail (G_IS_DBUS_CONNECTION (connection));
+
+ if (connection->priv->dbus_1_connection != NULL)
+ {
+ dbus_connection_remove_filter (connection->priv->dbus_1_connection,
+ filter_function,
+ connection);
+ g_dbus_unintegrate_dbus_1_connection (connection->priv->dbus_1_connection);
+ if (connection->priv->is_private)
+ {
+ dbus_connection_close (connection->priv->dbus_1_connection);
+ }
+ dbus_connection_unref (connection->priv->dbus_1_connection);
+ }
+
+ if (dbus_1_connection != NULL)
+ {
+ connection->priv->dbus_1_connection = dbus_connection_ref (dbus_1_connection);
+ g_dbus_integrate_dbus_1_connection (connection->priv->dbus_1_connection, NULL);
+ if (!dbus_connection_add_filter (connection->priv->dbus_1_connection,
+ filter_function,
+ connection,
+ NULL))
+ _g_dbus_oom ();
+ dbus_connection_set_exit_on_disconnect (connection->priv->dbus_1_connection,
+ connection->priv->exit_on_close);
+ }
+ else
+ {
+ connection->priv->dbus_1_connection = NULL;
+ }
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+
+static gboolean
+open_bus_connection (gpointer user_data)
+{
+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (user_data);
+ GDBusConnection *connection;
+ GError *error;
+
+ connection = G_DBUS_CONNECTION (g_simple_async_result_get_op_res_gpointer (simple));
+
+ error = NULL;
+ if (!attempt_connect (connection, &error))
+ {
+ g_simple_async_result_set_from_error (simple, error);
+ g_error_free (error);
+
+ /* set up timer for attempting to reconnect */
+ setup_reconnect_timer (connection);
+ }
+
+ g_simple_async_result_complete (simple);
+ g_object_unref (simple);
+
+ return FALSE;
+}
+
+static GDBusConnection *
+g_dbus_connection_bus_get_internal (GMessageBusType bus_type,
+ gboolean private,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GDBusConnection *connection;
+ GSimpleAsyncResult *simple;
+
+ g_return_val_if_fail (bus_type != G_MESSAGE_BUS_TYPE_NONE, NULL);
+
+ connection = NULL;
+
+ /* TODO: use cancellable */
+
+ /* handle starter bus */
+ if (bus_type == G_MESSAGE_BUS_TYPE_STARTER)
+ {
+ const gchar *starter_bus;
+
+ starter_bus = g_getenv ("DBUS_STARTER_BUS_TYPE");
+ if (g_strcmp0 (starter_bus, "session") == 0)
+ {
+ bus_type = G_MESSAGE_BUS_TYPE_SESSION;
+ }
+ else if (g_strcmp0 (starter_bus, "system") == 0)
+ {
+ bus_type = G_MESSAGE_BUS_TYPE_SYSTEM;
+ }
+ else
+ {
+ g_critical ("Cannot construct a GDBusConnection object with bus_type G_MESSAGE_BUS_TYPE_STARTER "
+ "because the DBUS_STARTER_BUS_TYPE environment variable is not set. "
+ "This is an error in the application.");
+ goto out;
+ }
+ }
+
+ /* singleton handling */
+ if (!private)
+ {
+ G_LOCK (connection_lock);
+ if (bus_type == G_MESSAGE_BUS_TYPE_SESSION && the_session_bus != NULL)
+ {
+ connection = g_object_ref (the_session_bus);
+ simple = g_simple_async_result_new (G_OBJECT (connection),
+ callback,
+ user_data,
+ g_dbus_connection_bus_get_finish);
+ g_simple_async_result_complete_in_idle (simple);
+ g_object_unref (simple);
+ G_UNLOCK (connection_lock);
+ goto out;
+ }
+ else if (bus_type == G_MESSAGE_BUS_TYPE_SYSTEM && the_system_bus != NULL)
+ {
+ connection = g_object_ref (the_system_bus);
+ simple = g_simple_async_result_new (G_OBJECT (connection),
+ callback,
+ user_data,
+ g_dbus_connection_bus_get_finish);
+ g_simple_async_result_complete_in_idle (simple);
+ g_object_unref (simple);
+ G_UNLOCK (connection_lock);
+ goto out;
+ }
+ }
+
+ connection = G_DBUS_CONNECTION (g_object_new (G_TYPE_DBUS_CONNECTION,
+ "bus-type", bus_type,
+ NULL));
+ connection->priv->is_private = private;
+
+ if (!private)
+ {
+ /* singleton handling, part 2 */
+ if (bus_type == G_MESSAGE_BUS_TYPE_SESSION && the_session_bus == NULL)
+ {
+ the_session_bus = connection;
+ }
+ else if (bus_type == G_MESSAGE_BUS_TYPE_SYSTEM && the_system_bus == NULL)
+ {
+ the_system_bus = connection;
+ }
+ G_UNLOCK (connection_lock);
+ }
+
+ simple = g_simple_async_result_new (G_OBJECT (connection),
+ callback,
+ user_data,
+ private ? g_dbus_connection_bus_get_private_finish : g_dbus_connection_bus_get_finish);
+ g_simple_async_result_set_op_res_gpointer (simple,
+ connection,
+ NULL);
+ g_idle_add (open_bus_connection,
+ simple);
+
+ out:
+ return connection;
+}
+
+
+/**
+ * g_dbus_connection_bus_get:
+ * @bus_type: The bus type (can't be #G_MESSAGE_BUS_TYPE_NONE).
+ * @cancellable: A #GCancellable or %NULL.
+ * @callback: The callback function to invoke when finished attempting opening a connection.
+ * @user_data: User data to pass to @callback.
+ *
+ * <note><para>This class is rarely used directly; f you are
+ * implementing a D-Bus service, it's often easier to use
+ * g_bus_name_owner_new() and if you are implementing a
+ * D-Bus client it's often easier to use TODO().
+ * </para></note>
+ * Creates a new #GDBusConnection object and then attempts to open a
+ * connection to the message bus specified by @bus_type. When the
+ * attempt to connect to the message bus is finished, @callback will
+ * be invoked (on the main thread) and you can use
+ * g_dbus_connection_bus_get_finish() to see if the connection could be
+ * opened.
+ *
+ * Note that the returned object is a singleton - i.e. it is shared
+ * among all callers of g_dbus_connection_bus_get() for the same message
+ * bus type. As such, the connection may already be open when using
+ * g_dbus_connection_bus_get(). In this case @callback will still be
+ * invoked and calls to g_dbus_connection_bus_get_finish() will not return
+ * error. Another observation is that you cannot rely on the
+ * #GDBusConnection::opened signal to fire if the connection is
+ * already open. You can however use g_dbus_connection_get_is_open()
+ * right after g_dbus_connection_bus_get() and just call the function you
+ * would normally use for the #GDBusConnection::opened signal handler.
+ *
+ * If the message bus that @connection is connected to vanishes, the
+ * #GDBusConnection::closed signal is emitted and the connection is
+ * closed. When (and if) the message bus reappears the
+ * #GDBusConnection::opened signal is emitted and the connection is
+ * open.
+ *
+ * Note that connections to message buses are created with the
+ * #GDBusConnection:exit-on-close set to %TRUE so if you intend to
+ * handle the case where the message bus is vanishing and appearing
+ * you need to change this property via
+ * e.g. g_dbus_connection_set_exit_on_close().
+ *
+ * An example of how this function typically is used can be seen in
+ * the following example.
+ * <example><title>Using g_dbus_connection_bus_get()</title><programlisting>
+ * static void
+ * on_connection_opened (GDBusConnection *connection,
+ * gpointer user_data)
+ * {
+ * /<!-- -->* the connection to the bus is now open, do something with connection *<!-- -->/
+ * }
+ *
+ * static void
+ * on_connection_closed (GDBusConnection *connection,
+ * gpointer user_data)
+ * {
+ * /<!-- -->* the connection to the message bus closed, clean up *<!-- -->/
+ * }
+ *
+ * static void
+ * get_bus_cb (GDBusConnection *connection,
+ * GAsyncResult *result,
+ * gpointer user_data)
+ * {
+ * GError *error;
+ *
+ * error = NULL;
+ * if (!g_dbus_connection_bus_get_finish (connection, result, &error))
+ * {
+ * /<!-- -->* failed to connect to the message bus - typically apps
+ * * want to complain on stderr and exit.
+ * *<!-- -->/
+ * }
+ * }
+ *
+ * void
+ * some_routine (SomeObject *data)
+ * {
+ * data->priv->session_bus = g_dbus_connection_bus_get (G_MESSAGE_BUS_TYPE_SESSION,
+ * NULL,
+ * (GAsyncReadyCallback) get_bus_cb,
+ * data);
+ * g_signal_connect (data->priv->session_bus, "opened", G_CALLBACK (on_connection_opened), data);
+ * g_signal_connect (data->priv->session_bus, "closed", G_CALLBACK (on_connection_closed), data);
+ * /<!-- -->* handle the case where the connection is already open *<!-- -->/
+ * if (g_dbus_connection_get_is_open (data->priv->session_bus))
+ * on_connection_opened (data->priv->session_bus, data);
+ * }
+ * </programlisting></example>
+ * If you need a private bus connection, use
+ * g_dbus_connection_bus_get_private() instead.
+ *
+ * Returns: A #GDBusConnection object. Free with g_object_unref().
+ */
+GDBusConnection *
+g_dbus_connection_bus_get (GMessageBusType bus_type,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ return g_dbus_connection_bus_get_internal (bus_type,
+ FALSE,
+ cancellable,
+ callback,
+ user_data);
+}
+
+/**
+ * g_dbus_connection_bus_get_private:
+ * @bus_type: The bus type (can't be #G_MESSAGE_BUS_TYPE_NONE).
+ * @cancellable: A #GCancellable or %NULL.
+ * @callback: The callback function to invoke when finished attempting opening a connection.
+ * @user_data: User data to pass to @callback.
+ *
+ * Like g_dbus_connection_bus_get() but opens a #GDBusConnection that
+ * is not shared with anyone else.
+ *
+ * Returns: A #GDBusConnection object. Free with g_object_unref().
+ */
+GDBusConnection *
+g_dbus_connection_bus_get_private (GMessageBusType bus_type,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ return g_dbus_connection_bus_get_internal (bus_type,
+ TRUE,
+ cancellable,
+ callback,
+ user_data);
+}
+
+/**
+ * g_dbus_connection_bus_get_finish:
+ * @connection: A #GDBusConnection.
+ * @res: A #GAsyncResult obtained from the #GAsyncReadyCallback function passed to g_dbus_connection_bus_get().
+ * @error: Return location for error or %NULL.
+ *
+ * Finishes opening a connection to a message bus.
+ *
+ * Returns: %TRUE if the @connection is open, otherwise %FALSE with @error set.
+ **/
+gboolean
+g_dbus_connection_bus_get_finish (GDBusConnection *connection,
+ GAsyncResult *res,
+ GError **error)
+{
+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res);
+ g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), FALSE);
+ g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == g_dbus_connection_bus_get_finish);
+ return !g_simple_async_result_propagate_error (simple, error);
+}
+
+/**
+ * g_dbus_connection_bus_get_private_finish:
+ * @connection: A #GDBusConnection.
+ * @res: A #GAsyncResult obtained from the #GAsyncReadyCallback function passed to g_dbus_connection_bus_get_private().
+ * @error: Return location for error or %NULL.
+ *
+ * Finishes opening a private connection to a message bus.
+ *
+ * Returns: %TRUE if the @connection is open, otherwise %FALSE with @error set.
+ **/
+gboolean
+g_dbus_connection_bus_get_private_finish (GDBusConnection *connection,
+ GAsyncResult *res,
+ GError **error)
+{
+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res);
+ g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), FALSE);
+ g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == g_dbus_connection_bus_get_private_finish);
+ return !g_simple_async_result_propagate_error (simple, error);
+}
+
+/**
+ * g_dbus_connection_get_exit_on_close:
+ * @connection: A #GDBusConnection.
+ *
+ * Gets whether _exit() is called when @connection is closed.
+ *
+ * Returns: %TRUE if _exit() is called when @connection is closed.
+ **/
+gboolean
+g_dbus_connection_get_exit_on_close (GDBusConnection *connection)
+{
+ g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), FALSE);
+
+ return connection->priv->exit_on_close;
+}
+
+/**
+ * g_dbus_connection_set_exit_on_close:
+ * @connection: A #GDBusConnection.
+ * @exit_on_close: Whether _exit() should be called when @connection is
+ * closed.
+ *
+ * Sets whether _exit() should be called when @connection is closed.
+ **/
+void
+g_dbus_connection_set_exit_on_close (GDBusConnection *connection,
+ gboolean exit_on_close)
+{
+ g_return_if_fail (G_IS_DBUS_CONNECTION (connection));
+
+ connection->priv->exit_on_close = exit_on_close;
+ if (connection->priv->dbus_1_connection != NULL)
+ dbus_connection_set_exit_on_disconnect (connection->priv->dbus_1_connection,
+ connection->priv->exit_on_close);
+}
+
+/**
+ * g_dbus_connection_get_unique_name:
+ * @connection: A #GDBusConnection.
+ *
+ * Gets the unique name of @connection as assigned by the message bus.
+ *
+ * Returns: The unique name or %NULL if the connection is closed or
+ * @connection is not a message bus connection. Do not free this
+ * string, it is owned by @connection.
+ **/
+const gchar *
+g_dbus_connection_get_unique_name (GDBusConnection *connection)
+{
+ g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL);
+
+ if (connection->priv->bus_type == G_MESSAGE_BUS_TYPE_NONE)
+ return NULL;
+
+ if (connection->priv->dbus_1_connection != NULL)
+ return dbus_bus_get_unique_name (connection->priv->dbus_1_connection);
+ else
+ return NULL;
+}
+
+
+#define __G_DBUS_CONNECTION_C__
+#include "gdbusaliasdef.c"
diff --git a/gdbus/gdbusconnection.h b/gdbus/gdbusconnection.h
new file mode 100644
index 0000000..a1688f1
--- /dev/null
+++ b/gdbus/gdbusconnection.h
@@ -0,0 +1,116 @@
+/* GDBus - GLib D-Bus Library
+ *
+ * Copyright (C) 2008-2009 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: David Zeuthen <davidz redhat com>
+ */
+
+#if !defined (__G_DBUS_G_DBUS_H_INSIDE__) && !defined (G_DBUS_COMPILATION)
+#error "Only <gdbus/gdbus.h> can be included directly."
+#endif
+
+#ifndef __G_DBUS_CONNECTION_H__
+#define __G_DBUS_CONNECTION_H__
+
+#include <gdbus/gdbustypes.h>
+#include <dbus/dbus.h>
+
+G_BEGIN_DECLS
+
+#define G_TYPE_DBUS_CONNECTION (g_dbus_connection_get_type ())
+#define G_DBUS_CONNECTION(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_DBUS_CONNECTION, GDBusConnection))
+#define G_DBUS_CONNECTION_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_DBUS_CONNECTION, GDBusConnectionClass))
+#define G_DBUS_CONNECTION_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_DBUS_CONNECTION, GDBusConnectionClass))
+#define G_IS_DBUS_CONNECTION(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_DBUS_CONNECTION))
+#define G_IS_DBUS_CONNECTION_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_DBUS_CONNECTION))
+
+typedef struct _GDBusConnectionClass GDBusConnectionClass;
+typedef struct _GDBusConnectionPrivate GDBusConnectionPrivate;
+
+/**
+ * GDBusConnection:
+ *
+ * The #GDBusConnection structure contains only private data and
+ * should only be accessed using the provided API.
+ */
+struct _GDBusConnection
+{
+ /*< private >*/
+ GObject parent_instance;
+ GDBusConnectionPrivate *priv;
+};
+
+/**
+ * GDBusConnectionClass:
+ * @opened: Signal class handler for the #GDBusConnection::opened signal.
+ * @closed: Signal class handler for the #GDBusConnection::closed signal.
+ *
+ * Class structure for #GDBusConnection.
+ */
+struct _GDBusConnectionClass
+{
+ /*< private >*/
+ GObjectClass parent_class;
+
+ /*< public >*/
+
+ /* Signals */
+ void (*opened) (GDBusConnection *connection);
+ void (*closed) (GDBusConnection *connection);
+
+ /*< private >*/
+ /* Padding for future expansion */
+ void (*_g_reserved1) (void);
+ void (*_g_reserved2) (void);
+ void (*_g_reserved3) (void);
+ void (*_g_reserved4) (void);
+ void (*_g_reserved5) (void);
+ void (*_g_reserved6) (void);
+ void (*_g_reserved7) (void);
+ void (*_g_reserved8) (void);
+};
+
+GType g_dbus_connection_get_type (void) G_GNUC_CONST;
+
+GDBusConnection *g_dbus_connection_bus_get (GMessageBusType bus_type,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean g_dbus_connection_bus_get_finish (GDBusConnection *connection,
+ GAsyncResult *res,
+ GError **error);
+
+GDBusConnection *g_dbus_connection_bus_get_private (GMessageBusType bus_type,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean g_dbus_connection_bus_get_private_finish (GDBusConnection *connection,
+ GAsyncResult *res,
+ GError **error);
+
+GMessageBusType g_dbus_connection_get_bus_type (GDBusConnection *connection);
+gboolean g_dbus_connection_get_is_open (GDBusConnection *connection);
+DBusConnection *g_dbus_connection_get_dbus_1_connection (GDBusConnection *connection);
+const gchar *g_dbus_connection_get_unique_name (GDBusConnection *connection);
+gboolean g_dbus_connection_get_exit_on_close (GDBusConnection *connection);
+void g_dbus_connection_set_exit_on_close (GDBusConnection *connection,
+ gboolean exit_on_close);
+
+G_END_DECLS
+
+#endif /* __G_DBUS_CONNECTION_H__ */
diff --git a/gdbus/gdbusenums.h b/gdbus/gdbusenums.h
new file mode 100644
index 0000000..05af006
--- /dev/null
+++ b/gdbus/gdbusenums.h
@@ -0,0 +1,225 @@
+/* GDBus - GLib D-Bus Library
+ *
+ * Copyright (C) 2008-2009 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: David Zeuthen <davidz redhat com>
+ */
+
+#if !defined (__G_DBUS_G_DBUS_H_INSIDE__) && !defined (G_DBUS_COMPILATION)
+#error "Only <gdbus/gdbus.h> can be included directly."
+#endif
+
+#ifndef __G_DBUS_ENUMS_H__
+#define __G_DBUS_ENUMS_H__
+
+#include <glib-object.h>
+#include <gio/gio.h>
+#include <dbus/dbus.h>
+
+G_BEGIN_DECLS
+
+/**
+ * GMessageBusType:
+ * @G_MESSAGE_BUS_TYPE_NONE: Not a message bus connection.
+ * @G_MESSAGE_BUS_TYPE_SESSION: The login session message bus.
+ * @G_MESSAGE_BUS_TYPE_SYSTEM: The system-wide message bus.
+ * @G_MESSAGE_BUS_TYPE_STARTER: Connect to the bus that activated the program.
+ *
+ * An enumeration to specify the type of a #GDBusConnection.
+ */
+typedef enum
+{
+ G_MESSAGE_BUS_TYPE_NONE = -1,
+ G_MESSAGE_BUS_TYPE_SESSION = DBUS_BUS_SESSION,
+ G_MESSAGE_BUS_TYPE_SYSTEM = DBUS_BUS_SYSTEM,
+ G_MESSAGE_BUS_TYPE_STARTER = DBUS_BUS_STARTER,
+} GMessageBusType;
+
+/**
+ * GBusNameOwnerFlags:
+ * @G_BUS_NAME_OWNER_FLAGS_NONE: No flags set.
+ * @G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT: Allow another message connection to take the name.
+ * @G_BUS_NAME_OWNER_FLAGS_REPLACE: If another message bus connection
+ * owns the name and have specified #G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT, then
+ * take the name from the other connection.
+ *
+ * Flags used when constructing a #GBusNameOwner.
+ */
+typedef enum
+{
+ G_BUS_NAME_OWNER_FLAGS_NONE = 0, /*< nick=none >*/
+ G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT = (1<<0), /*< nick=allow-replacement >*/
+ G_BUS_NAME_OWNER_FLAGS_REPLACE = (1<<1), /*< nick=replace >*/
+} GBusNameOwnerFlags;
+
+/**
+ * GDBusError:
+ * @G_DBUS_ERROR_FAILED: The operation failed.
+ * @G_DBUS_ERROR_CANCELLED: The operation was cancelled.
+ * @G_DBUS_ERROR_REMOTE_EXCEPTION: A remote exception that couldn't be
+ * mapped to a #GError. Use g_dbus_error_get_remote_exception()
+ * to extract the D-Bus error name.
+ * @G_DBUS_ERROR_DBUS_FAILED:
+ * A generic error; "something went wrong" - see the error message for
+ * more.
+ * @G_DBUS_ERROR_NO_MEMORY:
+ * There was not enough memory to complete an operation.
+ * @G_DBUS_ERROR_SERVICE_UNKNOWN:
+ * The bus doesn't know how to launch a service to supply the bus name
+ * you wanted.
+ * @G_DBUS_ERROR_NAME_HAS_NO_OWNER:
+ * The bus name you referenced doesn't exist (i.e. no application owns
+ * it).
+ * @G_DBUS_ERROR_NO_REPLY:
+ * No reply to a message expecting one, usually means a timeout occurred.
+ * @G_DBUS_ERROR_IO_ERROR:
+ * Something went wrong reading or writing to a socket, for example.
+ * @G_DBUS_ERROR_BAD_ADDRESS:
+ * A D-Bus bus address was malformed.
+ * @G_DBUS_ERROR_NOT_SUPPORTED:
+ * Requested operation isn't supported (like ENOSYS on UNIX).
+ * @G_DBUS_ERROR_LIMITS_EXCEEDED:
+ * Some limited resource is exhausted.
+ * @G_DBUS_ERROR_ACCESS_DENIED:
+ * Security restrictions don't allow doing what you're trying to do.
+ * @G_DBUS_ERROR_AUTH_FAILED:
+ * Authentication didn't work.
+ * @G_DBUS_ERROR_NO_SERVER:
+ * Unable to connect to server (probably caused by ECONNREFUSED on a
+ * socket).
+ * @G_DBUS_ERROR_TIMEOUT:
+ * Certain timeout errors, possibly ETIMEDOUT on a socket. Note that
+ * #G_DBUS_ERROR_NO_REPLY is used for message reply timeouts. Warning:
+ * this is confusingly-named given that #G_DBUS_ERROR_TIMED_OUT also
+ * exists. We can't fix it for compatibility reasons so just be
+ * careful.
+ * @G_DBUS_ERROR_NO_NETWORK:
+ * No network access (probably ENETUNREACH on a socket).
+ * @G_DBUS_ERROR_ADDRESS_IN_USE:
+ * Can't bind a socket since its address is in use (i.e. EADDRINUSE).
+ * @G_DBUS_ERROR_DISCONNECTED:
+ * The connection is disconnected and you're trying to use it.
+ * @G_DBUS_ERROR_INVALID_ARGS:
+ * Invalid arguments passed to a method call.
+ * @G_DBUS_ERROR_FILE_NOT_FOUND:
+ * Missing file.
+ * @G_DBUS_ERROR_FILE_EXISTS:
+ * Existing file and the operation you're using does not silently overwrite.
+ * @G_DBUS_ERROR_UNKNOWN_METHOD:
+ * Method name you invoked isn't known by the object you invoked it on.
+ * @G_DBUS_ERROR_TIMED_OUT:
+ * Certain timeout errors, e.g. while starting a service. Warning: this is
+ * confusingly-named given that #G_DBUS_ERROR_TIMEOUT also exists. We
+ * can't fix it for compatibility reasons so just be careful.
+ * @G_DBUS_ERROR_MATCH_RULE_NOT_FOUND:
+ * Tried to remove or modify a match rule that didn't exist.
+ * @G_DBUS_ERROR_MATCH_RULE_INVALID:
+ * The match rule isn't syntactically valid.
+ * @G_DBUS_ERROR_SPAWN_EXEC_FAILED:
+ * While starting a new process, the exec() call failed.
+ * @G_DBUS_ERROR_SPAWN_FORK_FAILED:
+ * While starting a new process, the fork() call failed.
+ * @G_DBUS_ERROR_SPAWN_CHILD_EXITED:
+ * While starting a new process, the child exited with a status code.
+ * @G_DBUS_ERROR_SPAWN_CHILD_SIGNALED:
+ * While starting a new process, the child exited on a signal.
+ * @G_DBUS_ERROR_SPAWN_FAILED:
+ * While starting a new process, something went wrong.
+ * @G_DBUS_ERROR_SPAWN_SETUP_FAILED:
+ * We failed to setup the environment correctly.
+ * @G_DBUS_ERROR_SPAWN_CONFIG_INVALID:
+ * We failed to setup the config parser correctly.
+ * @G_DBUS_ERROR_SPAWN_SERVICE_INVALID:
+ * Bus name was not valid.
+ * @G_DBUS_ERROR_SPAWN_SERVICE_NOT_FOUND:
+ * Service file not found in system-services directory.
+ * @G_DBUS_ERROR_SPAWN_PERMISSIONS_INVALID:
+ * Permissions are incorrect on the setuid helper.
+ * @G_DBUS_ERROR_SPAWN_FILE_INVALID:
+ * Service file invalid (Name, User or Exec missing).
+ * @G_DBUS_ERROR_SPAWN_NO_MEMORY:
+ * Tried to get a UNIX process ID and it wasn't available.
+ * @G_DBUS_ERROR_UNIX_PROCESS_ID_UNKNOWN:
+ * Tried to get a UNIX process ID and it wasn't available.
+ * @G_DBUS_ERROR_INVALID_SIGNATURE:
+ * A type signature is not valid.
+ * @G_DBUS_ERROR_INVALID_FILE_CONTENT:
+ * A file contains invalid syntax or is otherwise broken.
+ * @G_DBUS_ERROR_SELINUX_SECURITY_CONTEXT_UNKNOWN:
+ * Asked for SELinux security context and it wasn't available.
+ * @G_DBUS_ERROR_ADT_AUDIT_DATA_UNKNOWN:
+ * Asked for ADT audit data and it wasn't available.
+ * @G_DBUS_ERROR_OBJECT_PATH_IN_USE:
+ * There's already an object with the requested object path.
+ *
+ * Error codes.
+ */
+typedef enum
+{
+ G_DBUS_ERROR_FAILED, /*< nick=org.gtk.GDBus.Error.Failed >*/
+ G_DBUS_ERROR_CANCELLED, /*< nick=org.gtk.GDBus.Error.Cancelled >*/
+ G_DBUS_ERROR_REMOTE_EXCEPTION, /*< nick=org.gtk.GDBus.Error.RemoteException >*/
+
+ /* Well-known errors in the org.freedesktop.DBus.Error namespace */
+ G_DBUS_ERROR_DBUS_FAILED = 1000, /*< nick=org.freedesktop.DBus.Error.Failed >*/
+ G_DBUS_ERROR_NO_MEMORY, /*< nick=org.freedesktop.DBus.Error.NoMemory >*/
+ G_DBUS_ERROR_SERVICE_UNKNOWN, /*< nick=org.freedesktop.DBus.Error.ServiceUnknown >*/
+ G_DBUS_ERROR_NAME_HAS_NO_OWNER, /*< nick=org.freedesktop.DBus.Error.NameHasNoOwner >*/
+ G_DBUS_ERROR_NO_REPLY, /*< nick=org.freedesktop.DBus.Error.NoReply >*/
+ G_DBUS_ERROR_IO_ERROR, /*< nick=org.freedesktop.DBus.Error.IOError >*/
+ G_DBUS_ERROR_BAD_ADDRESS, /*< nick=org.freedesktop.DBus.Error.BadAddress >*/
+ G_DBUS_ERROR_NOT_SUPPORTED, /*< nick=org.freedesktop.DBus.Error.NotSupported >*/
+ G_DBUS_ERROR_LIMITS_EXCEEDED, /*< nick=org.freedesktop.DBus.Error.LimitsExceeded >*/
+ G_DBUS_ERROR_ACCESS_DENIED, /*< nick=org.freedesktop.DBus.Error.AccessDenied >*/
+ G_DBUS_ERROR_AUTH_FAILED, /*< nick=org.freedesktop.DBus.Error.AuthFailed >*/
+ G_DBUS_ERROR_NO_SERVER, /*< nick=org.freedesktop.DBus.Error.NoServer >*/
+ G_DBUS_ERROR_TIMEOUT, /*< nick=org.freedesktop.DBus.Error.Timeout >*/
+ G_DBUS_ERROR_NO_NETWORK, /*< nick=org.freedesktop.DBus.Error.NoNetwork >*/
+ G_DBUS_ERROR_ADDRESS_IN_USE, /*< nick=org.freedesktop.DBus.Error.AddressInUse >*/
+ G_DBUS_ERROR_DISCONNECTED, /*< nick=org.freedesktop.DBus.Error.Disconnected >*/
+ G_DBUS_ERROR_INVALID_ARGS, /*< nick=org.freedesktop.DBus.Error.InvalidArgs >*/
+ G_DBUS_ERROR_FILE_NOT_FOUND, /*< nick=org.freedesktop.DBus.Error.FileNotFound >*/
+ G_DBUS_ERROR_FILE_EXISTS, /*< nick=org.freedesktop.DBus.Error.FileExists >*/
+ G_DBUS_ERROR_UNKNOWN_METHOD, /*< nick=org.freedesktop.DBus.Error.UnknownMethod >*/
+ G_DBUS_ERROR_TIMED_OUT, /*< nick=org.freedesktop.DBus.Error.TimedOut >*/
+ G_DBUS_ERROR_MATCH_RULE_NOT_FOUND, /*< nick=org.freedesktop.DBus.Error.MatchRuleNotFound >*/
+ G_DBUS_ERROR_MATCH_RULE_INVALID, /*< nick=org.freedesktop.DBus.Error.MatchRuleInvalid >*/
+ G_DBUS_ERROR_SPAWN_EXEC_FAILED, /*< nick=org.freedesktop.DBus.Error.Spawn.ExecFailed >*/
+ G_DBUS_ERROR_SPAWN_FORK_FAILED, /*< nick=org.freedesktop.DBus.Error.Spawn.ForkFailed >*/
+ G_DBUS_ERROR_SPAWN_CHILD_EXITED, /*< nick=org.freedesktop.DBus.Error.Spawn.ChildExited >*/
+ G_DBUS_ERROR_SPAWN_CHILD_SIGNALED, /*< nick=org.freedesktop.DBus.Error.Spawn.ChildSignaled >*/
+ G_DBUS_ERROR_SPAWN_FAILED, /*< nick=org.freedesktop.DBus.Error.Spawn.Failed >*/
+ G_DBUS_ERROR_SPAWN_SETUP_FAILED, /*< nick=org.freedesktop.DBus.Error.Spawn.FailedToSetup >*/
+ G_DBUS_ERROR_SPAWN_CONFIG_INVALID, /*< nick=org.freedesktop.DBus.Error.Spawn.ConfigInvalid >*/
+ G_DBUS_ERROR_SPAWN_SERVICE_INVALID, /*< nick=org.freedesktop.DBus.Error.Spawn.ServiceNotValid >*/
+ G_DBUS_ERROR_SPAWN_SERVICE_NOT_FOUND, /*< nick=org.freedesktop.DBus.Error.Spawn.ServiceNotFound >*/
+ G_DBUS_ERROR_SPAWN_PERMISSIONS_INVALID, /*< nick=org.freedesktop.DBus.Error.Spawn.PermissionsInvalid >*/
+ G_DBUS_ERROR_SPAWN_FILE_INVALID, /*< nick=org.freedesktop.DBus.Error.Spawn.FileInvalid >*/
+ G_DBUS_ERROR_SPAWN_NO_MEMORY, /*< nick=org.freedesktop.DBus.Error.Spawn.NoMemory >*/
+ G_DBUS_ERROR_UNIX_PROCESS_ID_UNKNOWN, /*< nick=org.freedesktop.DBus.Error.UnixProcessIdUnknown >*/
+ G_DBUS_ERROR_INVALID_SIGNATURE, /*< nick=org.freedesktop.DBus.Error.InvalidSignature >*/
+ G_DBUS_ERROR_INVALID_FILE_CONTENT, /*< nick=org.freedesktop.DBus.Error.InvalidFileContent >*/
+ G_DBUS_ERROR_SELINUX_SECURITY_CONTEXT_UNKNOWN, /*< nick=org.freedesktop.DBus.Error.SELinuxSecurityContextUnknown >*/
+ G_DBUS_ERROR_ADT_AUDIT_DATA_UNKNOWN, /*< nick=org.freedesktop.DBus.Error.AdtAuditDataUnknown >*/
+ G_DBUS_ERROR_OBJECT_PATH_IN_USE, /*< nick=org.freedesktop.DBus.Error.ObjectPathInUse >*/
+} GDBusError;
+
+
+G_END_DECLS
+
+#endif /* __G_DBUS_ENUMS_H__ */
diff --git a/gdbus/gdbusenumtypes.c.template b/gdbus/gdbusenumtypes.c.template
new file mode 100644
index 0000000..f4aff8a
--- /dev/null
+++ b/gdbus/gdbusenumtypes.c.template
@@ -0,0 +1,42 @@
+/*** BEGIN file-header ***/
+#include <gdbus.h>
+#include "gdbusalias.h"
+
+/*** END file-header ***/
+
+/*** BEGIN file-production ***/
+/* enumerations from "@filename@" */
+/*** END file-production ***/
+
+/*** BEGIN value-header ***/
+GType
+ enum_name@_get_type (void)
+{
+ static volatile gsize g_define_type_id__volatile = 0;
+
+ if (g_once_init_enter (&g_define_type_id__volatile))
+ {
+ static const G Type@Value values[] = {
+/*** END value-header ***/
+
+/*** BEGIN value-production ***/
+ { @VALUENAME@, "@VALUENAME@", "@valuenick@" },
+/*** END value-production ***/
+
+/*** BEGIN value-tail ***/
+ { 0, NULL, NULL }
+ };
+ GType g_define_type_id =
+ g_ type@_register_static (g_intern_static_string ("@EnumName@"), values);
+ g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
+ }
+
+ return g_define_type_id__volatile;
+}
+
+/*** END value-tail ***/
+
+/*** BEGIN file-tail ***/
+#define __G_DBUS_ENUM_TYPES_C__
+#include "gdbusaliasdef.c"
+/*** END file-tail ***/
diff --git a/gdbus/gdbusenumtypes.h.template b/gdbus/gdbusenumtypes.h.template
new file mode 100644
index 0000000..b905a8f
--- /dev/null
+++ b/gdbus/gdbusenumtypes.h.template
@@ -0,0 +1,24 @@
+/*** BEGIN file-header ***/
+#ifndef __G_DBUS_ENUM_TYPES_H__
+#define __G_DBUS_ENUM_TYPES_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+/*** END file-header ***/
+
+/*** BEGIN file-production ***/
+
+/* enumerations from "@filename@" */
+/*** END file-production ***/
+
+/*** BEGIN value-header ***/
+GType @enum_name _get_type (void) G_GNUC_CONST;
+#define @ENUMPREFIX _TYPE_@ENUMSHORT@ (@enum_name _get_type ())
+/*** END value-header ***/
+
+/*** BEGIN file-tail ***/
+G_END_DECLS
+
+#endif /* __G_DBUS_ENUM_TYPES_H__ */
+/*** END file-tail ***/
diff --git a/gdbus/gdbuserror.c b/gdbus/gdbuserror.c
new file mode 100644
index 0000000..a76b375
--- /dev/null
+++ b/gdbus/gdbuserror.c
@@ -0,0 +1,507 @@
+/* GDBus - GLib D-Bus Library
+ *
+ * Copyright (C) 2008-2009 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: David Zeuthen <davidz redhat com>
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+
+#include <glib/gi18n.h>
+
+#include "gdbuserror.h"
+#include "gdbusenumtypes.h"
+
+#include "gdbusalias.h"
+
+/**
+ * SECTION:gdbuserror
+ * @title: GDBusError
+ * @short_description: Error helper functions
+ * @include: gdbus/gdbus.h
+ *
+ * Contains error helper functions for GDBus.
+ */
+
+/**
+ * g_dbus_error_quark:
+ *
+ * Gets the GDBus Error Quark.
+ *
+ * Return value: a #GQuark.
+ **/
+GQuark
+g_dbus_error_quark (void)
+{
+ return g_quark_from_static_string ("g-dbus-error-quark");
+}
+
+/**
+ * g_dbus_error_get_remote_exception:
+ * @error: A #GError.
+ * @out_name: Return location for D-Bus error name or %NULL.
+ * @out_message: Return location for D-Bus error message or %NULL.
+ *
+ * Analyzes @error and if the error domain is #G_DBUS_ERROR and
+ * error code is #G_DBUS_ERROR_REMOTE_EXCEPTION, extracts the D-Bus
+ * error name (e.g. <literal>com.example.Acme.Error.Failed</literal>)
+ * in @out_name and the D-Bus error message in @out_message and
+ * returns %TRUE.
+ *
+ * Note that this function will not warn if @error isn't a
+ * #G_DBUS_ERROR_REMOTE_EXCEPTION (it will just return %FALSE) so it
+ * can be used to test if @error is really a
+ * #G_DBUS_ERROR_REMOTE_EXCEPTION.
+ *
+ * Returns: %TRUE if @out_name and @out_message is set (caller must
+ * free these using g_free()), %FALSE if error is not a
+ * #G_DBUS_ERROR_REMOTE_EXCEPTION.
+ **/
+gboolean
+g_dbus_error_get_remote_exception (GError *error,
+ gchar **out_name,
+ gchar **out_message)
+{
+ gchar *s;
+ gchar *p;
+
+ g_return_val_if_fail (error != NULL, FALSE);
+
+ if (error->domain != G_DBUS_ERROR ||
+ error->code != G_DBUS_ERROR_REMOTE_EXCEPTION)
+ return FALSE;
+
+ if (out_name != NULL)
+ *out_name = NULL;
+ if (out_message != NULL)
+ *out_message = NULL;
+
+ s = strrchr (error->message, ' ');
+ if (s == NULL || s == error->message)
+ {
+ g_warning ("message '%s' is malformed", error->message);
+ goto out;
+ }
+ if (out_message != NULL)
+ *out_message = g_uri_unescape_string (s + 1, NULL);
+
+ p = s;
+ s--;
+ while (*s != ' ')
+ {
+ if (s < error->message)
+ {
+ g_warning ("message '%s' is malformed.", error->message);
+ goto out;
+ }
+ s--;
+ }
+ if (out_name != NULL)
+ *out_name = g_uri_unescape_segment (s + 1, p, NULL);
+
+ out:
+
+ return TRUE;
+}
+
+/**
+ * g_dbus_error_new_for_gerror:
+ * @error: A #GError.
+ * @dbus_error: Return location for #DBusError.
+ *
+ * Utility function to map a #GError to a #DBusError by getting the
+ * D-Bus error name from the nick of the element of the registered
+ * enumeration type for the error domain for @error.
+ *
+ * If the nick is not a valid D-Bus error name or the enumeration for
+ * the error domain for @error is not registered with the type system,
+ * the returned #DBusError will be of the form
+ * org.gtk.GDBus.UnmappedGError.Quark_HEXENCODED_QUARK_NAME_.Code_ERROR_CODE. This
+ * allows other GDBus applications to map the #DBusError back to the
+ * #GError using g_dbus_error_new_for_dbus_error().
+ *
+ * This function is intended for use by object mappings only.
+ */
+void
+g_dbus_error_new_for_gerror (GError *error,
+ DBusError *dbus_error)
+{
+ const gchar *domain_as_string;
+ gchar *error_name;
+ GString *s;
+ guint n;
+ GType enum_type;
+
+ error_name = NULL;
+
+ /* We can't assume that two different processes use the same Quark integer
+ * value for a given string. So send the string across the wire.
+ */
+ domain_as_string = g_quark_to_string (error->domain);
+
+ /* Also use the nick-name to produce error names compatible with
+ * non-GLib applications; note that GDBusError may not have
+ * been initialized so special case that.
+ */
+ if (strcmp (domain_as_string, "GDBusError") == 0)
+ enum_type = G_TYPE_DBUS_ERROR;
+ else
+ enum_type = g_type_from_name (domain_as_string);
+ if (enum_type != 0)
+ {
+ GEnumClass *enum_klass;
+ GEnumValue *enum_value;
+
+ enum_klass = g_type_class_ref (enum_type);
+ enum_value = g_enum_get_value (enum_klass, error->code);
+ g_type_class_unref (enum_klass);
+ if (enum_value != NULL)
+ {
+ /* TODO: it's the users own problem if value_nick isn't a proper D-Bus
+ * error name. Or is it? We should probably validate it...
+ */
+ error_name = g_strdup (enum_value->value_nick);
+ goto out;
+ }
+ }
+
+ /* We can't make a lot of assumptions about what domain_as_string
+ * looks like and D-Bus is extremely picky about error names so
+ * hex-encode it for transport across the wire.
+ */
+
+ s = g_string_new ("org.gtk.GDBus.UnmappedGError.Quark0x");
+ for (n = 0; domain_as_string[n] != 0; n++)
+ {
+ guint nibble_top;
+ guint nibble_bottom;
+
+ nibble_top = ((int) domain_as_string[n]) >> 4;
+ nibble_bottom = ((int) domain_as_string[n]) & 0x0f;
+
+ if (nibble_top < 10)
+ nibble_top += '0';
+ else
+ nibble_top += 'a' - 10;
+
+ if (nibble_bottom < 10)
+ nibble_bottom += '0';
+ else
+ nibble_bottom += 'a' - 10;
+
+ g_string_append_c (s, nibble_top);
+ g_string_append_c (s, nibble_bottom);
+ }
+ g_string_append_printf (s, ".Code%d", error->code);
+
+ error_name = g_string_free (s, FALSE);
+
+ out:
+ dbus_error_init (dbus_error);
+ dbus_set_error (dbus_error,
+ error_name,
+ "%s",
+ error->message);
+}
+
+static gboolean
+_g_dbus_error_decode_gerror (const gchar *dbus_name,
+ GQuark *out_error_domain,
+ gint *out_error_code)
+{
+ gboolean ret;
+ guint n;
+ GString *s;
+ gchar *domain_quark_string;
+
+ ret = FALSE;
+ s = NULL;
+
+ if (g_str_has_prefix (dbus_name, "org.gtk.GDBus.UnmappedGError.Quark0x"))
+ {
+ s = g_string_new (NULL);
+
+ for (n = sizeof "org.gtk.GDBus.UnmappedGError.Quark0x" - 1;
+ dbus_name[n] != '.' && dbus_name[n] != '\0';
+ n++)
+ {
+ guint nibble_top;
+ guint nibble_bottom;
+
+ nibble_top = dbus_name[n];
+ if (nibble_top >= '0' && nibble_top <= '9')
+ nibble_top -= '0';
+ else if (nibble_top >= 'a' && nibble_top <= 'f')
+ nibble_top -= ('a' - 10);
+ else
+ goto not_mapped;
+
+ n++;
+
+ nibble_bottom = dbus_name[n];
+ if (nibble_bottom >= '0' && nibble_bottom <= '9')
+ nibble_bottom -= '0';
+ else if (nibble_bottom >= 'a' && nibble_bottom <= 'f')
+ nibble_bottom -= ('a' - 10);
+ else
+ goto not_mapped;
+
+ g_string_append_c (s, (nibble_top<<4) | nibble_bottom);
+
+ }
+
+ if (!g_str_has_prefix (dbus_name + n, ".Code"))
+ goto not_mapped;
+
+ domain_quark_string = g_string_free (s, FALSE);
+ s = NULL;
+
+ if (out_error_domain != NULL)
+ *out_error_domain = g_quark_from_string (domain_quark_string);
+ g_free (domain_quark_string);
+
+ if (out_error_code != NULL)
+ *out_error_code = atoi (dbus_name + n + sizeof ".Code" - 1);
+
+ ret = TRUE;
+ }
+
+ not_mapped:
+
+ if (s != NULL)
+ g_string_free (s, TRUE);
+
+ return ret;
+}
+
+/**
+ * g_dbus_error_new_for_dbus_error_valist:
+ * @dbus_error: A #DBusError.
+ * @error_types: %NULL or a #G_TYPE_INVALID terminated array of #GType<!-- -->s for error domains to consider.
+ * @prepend_format: %NULL or format for message to prepend to the D-Bus error message.
+ * @va_args: Arguments for @prepend_format.
+ *
+ * Like g_dbus_error_new_for_dbus_error() but intended for language
+ * bindings.
+ *
+ * This function is intended for use by object mappings only.
+ *
+ * Returns: A newly allocated #GError. Free with g_error_free().
+ **/
+GError *
+g_dbus_error_new_for_dbus_error_valist (DBusError *dbus_error,
+ GType *error_types,
+ const gchar *prepend_format,
+ va_list va_args)
+{
+ GString *literal_error;
+ gchar *name_escaped;
+ gchar *message_escaped;
+ GError *error;
+ GQuark error_domain;
+ gint error_code;
+ GEnumClass *enum_klass;
+ GEnumValue *enum_value;
+ guint n;
+
+ g_return_val_if_fail (dbus_error != NULL, NULL);
+
+ literal_error = g_string_new (NULL);
+ if (prepend_format != NULL)
+ g_string_append_vprintf (literal_error, prepend_format, va_args);
+ g_string_append (literal_error, dbus_error->message);
+
+ /* Unmapped GError's from GLib peers are encoded in a special format can be mapped
+ * back to the right domain and code; see _g_dbus_error_encode_gerror()
+ */
+ if (_g_dbus_error_decode_gerror (dbus_error->name, &error_domain, &error_code))
+ goto mapped;
+
+ error_domain = G_DBUS_ERROR;
+
+ /* Otherwise lookup our registered error types
+ *
+ * TODO: reading the GObject sources, g_enum_get_value_by_nick is O(n); maybe cache in a hash
+ * table if performance is a concern? It probably isn't; errors should be rare...
+ *
+ * First check our built-in error type...
+ */
+ enum_klass = g_type_class_ref (G_TYPE_DBUS_ERROR);
+ enum_value = g_enum_get_value_by_nick (enum_klass, dbus_error->name);
+ g_type_class_unref (enum_klass);
+ if (enum_value != NULL)
+ {
+ error_code = enum_value->value;
+ goto mapped;
+ }
+ /* then check all error domains the user passed in (via e.g. g_dbus_connection_send_message_with_reply()) */
+ for (n = 0; error_types != NULL && error_types[n] != G_TYPE_INVALID; n++)
+ {
+ enum_klass = g_type_class_ref (error_types[n]);
+ enum_value = g_enum_get_value_by_nick (enum_klass, dbus_error->name);
+ g_type_class_unref (enum_klass);
+ if (enum_value != NULL)
+ {
+ error_domain = g_quark_from_static_string (g_type_name (error_types[n]));
+ error_code = enum_value->value;
+ goto mapped;
+ }
+ }
+
+ /* Otherwise we fall back to returning a G_DBUS_ERROR_REMOTE_EXCEPTION error with enough
+ * detail such that the D-Bus error name and error message can be decoded using the
+ * g_dbus_error_get_remote_exception() function.
+ */
+ error_code = G_DBUS_ERROR_REMOTE_EXCEPTION;
+
+ name_escaped = g_uri_escape_string (dbus_error->name, NULL, TRUE);
+ message_escaped = g_uri_escape_string (dbus_error->message, NULL, TRUE);
+
+ g_string_append_c (literal_error, ' ');
+ g_string_append (literal_error, name_escaped);
+ g_string_append_c (literal_error, ' ');
+ g_string_append (literal_error, message_escaped);
+
+ mapped:
+
+ error = g_error_new_literal (error_domain,
+ error_code,
+ literal_error->str);
+
+ g_string_free (literal_error, TRUE);
+
+ return error;
+}
+
+/**
+ * g_dbus_error_new_for_dbus_error:
+ * @dbus_error: A #DBusError.
+ * @error_types: %NULL or a #G_TYPE_INVALID terminated array of #GType<!-- -->s for error domains to consider.
+ * @prepend_format: %NULL or format for message to prepend to the D-Bus error message.
+ * @...: Arguments for @prepend_format.
+ *
+ * Utility function to map a #DBusError to a #GError by matching the
+ * name of @dbus_error with the nick names in the enumerations
+ * specified by the @error_types array.
+ *
+ * This function also handles unmapped #GError<!-- -->'s as described
+ * in g_dbus_error_new_for_gerror().
+ *
+ * If no suitable error code is found, then
+ * #G_DBUS_ERROR_REMOTE_EXCEPTION in the #G_DBUS_ERROR domain is used
+ * and an encoded form of the name and message from @dbus_error is
+ * appended to the message text such that the user can get this back
+ * via g_dbus_error_get_remote_exception().
+ *
+ * This function is intended for use by object mappings only.
+ *
+ * Returns: A newly allocated #GError. Free with g_error_free().
+ */
+GError *
+g_dbus_error_new_for_dbus_error (DBusError *dbus_error,
+ GType *error_types,
+ const gchar *prepend_format,
+ ...)
+{
+ va_list va_args;
+ GError *new_error;
+
+ va_start (va_args, prepend_format);
+ new_error = g_dbus_error_new_for_dbus_error_valist (dbus_error,
+ error_types,
+ prepend_format,
+ va_args);
+ va_end (va_args);
+
+ return new_error;
+}
+
+/**
+ * g_dbus_error_set_dbus_error:
+ * @error: %NULL or a #GError to set.
+ * @dbus_error: A #DBusError.
+ * @error_types: %NULL or a #G_TYPE_INVALID terminated array of #GType<!-- -->s for error domains to consider.
+ * @prepend_format: %NULL or format for message to prepend to the D-Bus error message.
+ * @...: Arguments for @prepend_format.
+ *
+ * Does nothing if @error is %NULL; if @error is non-%NULL, then
+ * * error must be NULL. A new #GError is created and assigned to
+ * * error using g_dbus_error_new_for_dbus_error().
+ *
+ * This function is intended for use by object mappings only.
+ */
+void
+g_dbus_error_set_dbus_error (GError **error,
+ DBusError *dbus_error,
+ GType *error_types,
+ const gchar *prepend_format,
+ ...)
+{
+ va_list va_args;
+ GError *new_error;
+
+ if (error == NULL)
+ return;
+
+ va_start (va_args, prepend_format);
+ new_error = g_dbus_error_new_for_dbus_error_valist (dbus_error,
+ error_types,
+ prepend_format,
+ va_args);
+ *error = new_error;
+ va_end (va_args);
+}
+
+/**
+ * g_dbus_error_set_dbus_error_valist:
+ * @error: %NULL or a #GError to set.
+ * @dbus_error: A #DBusError.
+ * @error_types: %NULL or a #G_TYPE_INVALID terminated array of #GType<!-- -->s for error domains to consider.
+ * @prepend_format: %NULL or format for message to prepend to the D-Bus error message.
+ * @va_args: Arguments for @prepend_format.
+ *
+ * Like g_dbus_error_set_dbus_error() but intended for language
+ * bindings.
+ *
+ * This function is intended for use by object mappings only.
+ */
+void
+g_dbus_error_set_dbus_error_valist (GError **error,
+ DBusError *dbus_error,
+ GType *error_types,
+ const gchar *prepend_format,
+ va_list va_args)
+{
+ GError *new_error;
+
+ if (error == NULL)
+ return;
+
+ new_error = g_dbus_error_new_for_dbus_error_valist (dbus_error,
+ error_types,
+ prepend_format,
+ va_args);
+ *error = new_error;
+}
+
+
+
+#define __G_DBUS_ERROR_C__
+#include "gdbusaliasdef.c"
diff --git a/gdbus/gdbuserror.h b/gdbus/gdbuserror.h
new file mode 100644
index 0000000..3922ad6
--- /dev/null
+++ b/gdbus/gdbuserror.h
@@ -0,0 +1,80 @@
+/* GDBus - GLib D-Bus Library
+ *
+ * Copyright (C) 2008-2009 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: David Zeuthen <davidz redhat com>
+ */
+
+#if !defined (__G_DBUS_G_DBUS_H_INSIDE__) && !defined (G_DBUS_COMPILATION)
+#error "Only <gdbus/gdbus.h> can be included directly."
+#endif
+
+#ifndef __G_DBUS_ERROR_H__
+#define __G_DBUS_ERROR_H__
+
+#include <gdbus/gdbustypes.h>
+#include <dbus/dbus.h>
+
+G_BEGIN_DECLS
+
+/**
+ * G_DBUS_ERROR:
+ *
+ * Error domain for GDBus. Errors in this domain will be from the #GDBusError enumeration.
+ * See #GError for more information on error domains.
+ **/
+#define G_DBUS_ERROR g_dbus_error_quark()
+
+GQuark g_dbus_error_quark (void);
+
+gboolean g_dbus_error_get_remote_exception (GError *error,
+ gchar **out_name,
+ gchar **out_message);
+
+/* Map DBusError to GError (only intended for object mappings) */
+
+GError *g_dbus_error_new_for_dbus_error_valist (DBusError *dbus_error,
+ GType *error_types,
+ const gchar *prepend_format,
+ va_list va_args);
+
+GError *g_dbus_error_new_for_dbus_error (DBusError *dbus_error,
+ GType *error_types,
+ const gchar *prepend_format,
+ ...);
+
+void g_dbus_error_set_dbus_error (GError **error,
+ DBusError *dbus_error,
+ GType *error_types,
+ const gchar *prepend_format,
+ ...);
+
+void g_dbus_error_set_dbus_error_valist (GError **error,
+ DBusError *dbus_error,
+ GType *error_types,
+ const gchar *prepend_format,
+ va_list va_args);
+
+/* Map GError to DBusError (only intended for object mappings) */
+
+void g_dbus_error_new_for_gerror (GError *error,
+ DBusError *dbus_error);
+
+G_END_DECLS
+
+#endif /* __G_DBUS_ERROR_H__ */
diff --git a/gdbus/gdbusmainloop.c b/gdbus/gdbusmainloop.c
new file mode 100644
index 0000000..5347585
--- /dev/null
+++ b/gdbus/gdbusmainloop.c
@@ -0,0 +1,782 @@
+/* GDBus - GLib D-Bus Library
+ *
+ * Copyright (C) 2008-2009 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+
+#include <glib/gi18n.h>
+
+#include "gdbusmainloop.h"
+#include "gdbusprivate.h"
+
+#include "gdbusalias.h"
+
+/**
+ * SECTION:gdbusmainloop
+ * @title: Main-loop integration
+ * @short_description: Main-loop integration routines
+ * @include: gdbus/gdbus.h
+ *
+ * Routines for integration #DBusConnection and #DBusServer objects
+ * with the GLib main loop.
+ */
+
+/* ---------------------------------------------------------------------------------------------------- */
+/* The following code is adopted from dbus/dbus-gmain.c in dbus-glib. Copright notices
+ * and license:
+ *
+ * Copyright (C) 2002, 2003 CodeFactory AB
+ * Copyright (C) 2005 Red Hat, Inc.
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+typedef struct
+{
+ GSource source; /**< the parent GSource */
+ DBusConnection *connection; /**< the connection to dispatch */
+} DBusGMessageQueue;
+
+static gboolean message_queue_prepare (GSource *source,
+ gint *timeout);
+static gboolean message_queue_check (GSource *source);
+static gboolean message_queue_dispatch (GSource *source,
+ GSourceFunc callback,
+ gpointer user_data);
+
+static const GSourceFuncs message_queue_funcs = {
+ message_queue_prepare,
+ message_queue_check,
+ message_queue_dispatch,
+ NULL
+};
+
+static gboolean
+message_queue_prepare (GSource *source,
+ gint *timeout)
+{
+ DBusConnection *connection = ((DBusGMessageQueue *)source)->connection;
+
+ *timeout = -1;
+
+ return (dbus_connection_get_dispatch_status (connection) == DBUS_DISPATCH_DATA_REMAINS);
+}
+
+static gboolean
+message_queue_check (GSource *source)
+{
+ return FALSE;
+}
+
+static gboolean
+message_queue_dispatch (GSource *source,
+ GSourceFunc callback,
+ gpointer user_data)
+{
+ DBusConnection *connection = ((DBusGMessageQueue *)source)->connection;
+
+ dbus_connection_ref (connection);
+
+ /* Only dispatch once - we don't want to starve other GSource */
+ dbus_connection_dispatch (connection);
+
+ dbus_connection_unref (connection);
+
+ return TRUE;
+}
+
+typedef struct
+{
+ GMainContext *context; /**< the main context */
+ GSList *ios; /**< all IOHandler */
+ GSList *timeouts; /**< all TimeoutHandler */
+ DBusConnection *connection; /**< NULL if this is really for a server not a connection */
+ GSource *message_queue_source; /**< DBusGMessageQueue */
+} ConnectionSetup;
+
+
+typedef struct
+{
+ ConnectionSetup *cs;
+ GSource *source;
+ DBusWatch *watch;
+} IOHandler;
+
+typedef struct
+{
+ ConnectionSetup *cs;
+ GSource *source;
+ DBusTimeout *timeout;
+} TimeoutHandler;
+
+G_LOCK_DEFINE_STATIC (main_loop_lock);
+
+dbus_int32_t _dbus_gmain_connection_slot = -1;
+static dbus_int32_t server_slot = -1;
+
+static ConnectionSetup*
+connection_setup_new (GMainContext *context,
+ DBusConnection *connection)
+{
+ ConnectionSetup *cs;
+
+ cs = g_new0 (ConnectionSetup, 1);
+
+ g_assert (context != NULL);
+
+ cs->context = context;
+ g_main_context_ref (cs->context);
+
+ if (connection)
+ {
+ cs->connection = connection;
+
+ cs->message_queue_source = g_source_new ((GSourceFuncs *) &message_queue_funcs,
+ sizeof (DBusGMessageQueue));
+ ((DBusGMessageQueue*)cs->message_queue_source)->connection = connection;
+ g_source_attach (cs->message_queue_source, cs->context);
+ }
+
+ return cs;
+}
+
+static void
+io_handler_source_finalized (gpointer data)
+{
+ IOHandler *handler;
+
+ handler = data;
+
+ if (handler->watch)
+ dbus_watch_set_data (handler->watch, NULL, NULL);
+
+ g_free (handler);
+}
+
+static void
+io_handler_destroy_source (void *data)
+{
+ IOHandler *handler;
+
+ handler = data;
+
+ if (handler->source)
+ {
+ GSource *source = handler->source;
+ handler->source = NULL;
+ handler->cs->ios = g_slist_remove (handler->cs->ios, handler);
+ g_source_destroy (source);
+ g_source_unref (source);
+ }
+}
+
+static void
+io_handler_watch_freed (void *data)
+{
+ IOHandler *handler;
+
+ handler = data;
+
+ handler->watch = NULL;
+
+ io_handler_destroy_source (handler);
+}
+
+static gboolean
+io_handler_dispatch (GIOChannel *source,
+ GIOCondition condition,
+ gpointer data)
+{
+ IOHandler *handler;
+ guint dbus_condition = 0;
+ DBusConnection *connection;
+
+ handler = data;
+
+ connection = handler->cs->connection;
+
+ if (connection)
+ dbus_connection_ref (connection);
+
+ if (condition & G_IO_IN)
+ dbus_condition |= DBUS_WATCH_READABLE;
+ if (condition & G_IO_OUT)
+ dbus_condition |= DBUS_WATCH_WRITABLE;
+ if (condition & G_IO_ERR)
+ dbus_condition |= DBUS_WATCH_ERROR;
+ if (condition & G_IO_HUP)
+ dbus_condition |= DBUS_WATCH_HANGUP;
+
+ /* Note that we don't touch the handler after this, because
+ * dbus may have disabled the watch and thus killed the
+ * handler.
+ */
+ dbus_watch_handle (handler->watch, dbus_condition);
+ handler = NULL;
+
+ if (connection)
+ dbus_connection_unref (connection);
+
+ return TRUE;
+}
+
+static void
+connection_setup_add_watch (ConnectionSetup *cs,
+ DBusWatch *watch)
+{
+ guint flags;
+ GIOCondition condition;
+ GIOChannel *channel;
+ IOHandler *handler;
+
+ if (!dbus_watch_get_enabled (watch))
+ return;
+
+ g_assert (dbus_watch_get_data (watch) == NULL);
+
+ flags = dbus_watch_get_flags (watch);
+
+ condition = G_IO_ERR | G_IO_HUP;
+ if (flags & DBUS_WATCH_READABLE)
+ condition |= G_IO_IN;
+ if (flags & DBUS_WATCH_WRITABLE)
+ condition |= G_IO_OUT;
+
+ handler = g_new0 (IOHandler, 1);
+ handler->cs = cs;
+ handler->watch = watch;
+
+ channel = g_io_channel_unix_new (dbus_watch_get_unix_fd (watch));
+
+ handler->source = g_io_create_watch (channel, condition);
+ g_source_set_callback (handler->source, (GSourceFunc) io_handler_dispatch, handler,
+ io_handler_source_finalized);
+ g_source_attach (handler->source, cs->context);
+
+ cs->ios = g_slist_prepend (cs->ios, handler);
+
+ dbus_watch_set_data (watch, handler, io_handler_watch_freed);
+ g_io_channel_unref (channel);
+}
+
+static void
+connection_setup_remove_watch (ConnectionSetup *cs,
+ DBusWatch *watch)
+{
+ IOHandler *handler;
+
+ handler = dbus_watch_get_data (watch);
+
+ if (handler == NULL)
+ return;
+
+ io_handler_destroy_source (handler);
+}
+
+static void
+timeout_handler_source_finalized (gpointer data)
+{
+ TimeoutHandler *handler;
+
+ handler = data;
+
+ if (handler->timeout)
+ dbus_timeout_set_data (handler->timeout, NULL, NULL);
+
+ g_free (handler);
+}
+
+static void
+timeout_handler_destroy_source (void *data)
+{
+ TimeoutHandler *handler;
+
+ handler = data;
+
+ if (handler->source)
+ {
+ GSource *source = handler->source;
+ handler->source = NULL;
+ handler->cs->timeouts = g_slist_remove (handler->cs->timeouts, handler);
+ g_source_destroy (source);
+ g_source_unref (source);
+ }
+}
+
+static void
+timeout_handler_timeout_freed (void *data)
+{
+ TimeoutHandler *handler;
+
+ handler = data;
+
+ handler->timeout = NULL;
+
+ timeout_handler_destroy_source (handler);
+}
+
+static gboolean
+timeout_handler_dispatch (gpointer data)
+{
+ TimeoutHandler *handler;
+
+ handler = data;
+
+ dbus_timeout_handle (handler->timeout);
+
+ return TRUE;
+}
+
+static void
+connection_setup_add_timeout (ConnectionSetup *cs,
+ DBusTimeout *timeout)
+{
+ TimeoutHandler *handler;
+
+ if (!dbus_timeout_get_enabled (timeout))
+ return;
+
+ g_assert (dbus_timeout_get_data (timeout) == NULL);
+
+ handler = g_new0 (TimeoutHandler, 1);
+ handler->cs = cs;
+ handler->timeout = timeout;
+
+ handler->source = g_timeout_source_new (dbus_timeout_get_interval (timeout));
+ g_source_set_callback (handler->source, timeout_handler_dispatch, handler,
+ timeout_handler_source_finalized);
+ g_source_attach (handler->source, handler->cs->context);
+
+ cs->timeouts = g_slist_prepend (cs->timeouts, handler);
+
+ dbus_timeout_set_data (timeout, handler, timeout_handler_timeout_freed);
+}
+
+static void
+connection_setup_remove_timeout (ConnectionSetup *cs,
+ DBusTimeout *timeout)
+{
+ TimeoutHandler *handler;
+
+ handler = dbus_timeout_get_data (timeout);
+
+ if (handler == NULL)
+ return;
+
+ timeout_handler_destroy_source (handler);
+}
+
+static void
+connection_setup_free (ConnectionSetup *cs)
+{
+ while (cs->ios)
+ io_handler_destroy_source (cs->ios->data);
+
+ while (cs->timeouts)
+ timeout_handler_destroy_source (cs->timeouts->data);
+
+ if (cs->message_queue_source)
+ {
+ GSource *source;
+
+ source = cs->message_queue_source;
+ cs->message_queue_source = NULL;
+
+ g_source_destroy (source);
+ g_source_unref (source);
+ }
+
+ g_main_context_unref (cs->context);
+ g_free (cs);
+}
+
+static dbus_bool_t
+add_watch (DBusWatch *watch,
+ gpointer data)
+{
+ ConnectionSetup *cs;
+
+ cs = data;
+
+ connection_setup_add_watch (cs, watch);
+
+ return TRUE;
+}
+
+static void
+remove_watch (DBusWatch *watch,
+ gpointer data)
+{
+ ConnectionSetup *cs;
+
+ cs = data;
+
+ connection_setup_remove_watch (cs, watch);
+}
+
+static void
+watch_toggled (DBusWatch *watch,
+ void *data)
+{
+ /* Because we just exit on OOM, enable/disable is
+ * no different from add/remove
+ */
+ if (dbus_watch_get_enabled (watch))
+ add_watch (watch, data);
+ else
+ remove_watch (watch, data);
+}
+
+static dbus_bool_t
+add_timeout (DBusTimeout *timeout,
+ void *data)
+{
+ ConnectionSetup *cs;
+
+ cs = data;
+
+ if (!dbus_timeout_get_enabled (timeout))
+ return TRUE;
+
+ connection_setup_add_timeout (cs, timeout);
+
+ return TRUE;
+}
+
+static void
+remove_timeout (DBusTimeout *timeout,
+ void *data)
+{
+ ConnectionSetup *cs;
+
+ cs = data;
+
+ connection_setup_remove_timeout (cs, timeout);
+}
+
+static void
+timeout_toggled (DBusTimeout *timeout,
+ void *data)
+{
+ /* Because we just exit on OOM, enable/disable is
+ * no different from add/remove
+ */
+ if (dbus_timeout_get_enabled (timeout))
+ add_timeout (timeout, data);
+ else
+ remove_timeout (timeout, data);
+}
+
+static void
+wakeup_main (void *data)
+{
+ ConnectionSetup *cs = data;
+
+ g_main_context_wakeup (cs->context);
+}
+
+
+/* Move to a new context */
+static ConnectionSetup*
+connection_setup_new_from_old (GMainContext *context,
+ ConnectionSetup *old)
+{
+ GSList *tmp;
+ ConnectionSetup *cs;
+
+ g_assert (old->context != context);
+
+ cs = connection_setup_new (context, old->connection);
+
+ tmp = old->ios;
+ while (tmp != NULL)
+ {
+ IOHandler *handler = tmp->data;
+
+ connection_setup_add_watch (cs, handler->watch);
+
+ tmp = tmp->next;
+ }
+
+ tmp = old->timeouts;
+ while (tmp != NULL)
+ {
+ TimeoutHandler *handler = tmp->data;
+
+ connection_setup_add_timeout (cs, handler->timeout);
+
+ tmp = tmp->next;
+ }
+
+ return cs;
+}
+
+static void
+ensure_slots (void)
+{
+ G_LOCK (main_loop_lock);
+ if (_dbus_gmain_connection_slot < 0)
+ {
+ dbus_connection_allocate_data_slot (&_dbus_gmain_connection_slot);
+ if (_dbus_gmain_connection_slot < 0)
+ {
+ G_UNLOCK (main_loop_lock);
+ _g_dbus_oom ();
+ }
+ }
+ if (server_slot < 0)
+ {
+ dbus_server_allocate_data_slot (&server_slot);
+ if (server_slot < 0)
+ {
+ G_UNLOCK (main_loop_lock);
+ _g_dbus_oom ();
+ }
+ }
+ G_UNLOCK (main_loop_lock);
+}
+
+/**
+ * g_dbus_integrate_dbus_1_connection:
+ * @connection: A #DBusConnection.
+ * @context: the #GMainContext or #NULL for default context
+ *
+ * Sets the watch and timeout functions of @connection to integrate
+ * the connection with the GLib main loop. Pass in #NULL for the
+ * #GMainContext unless you're doing something specialized.
+ *
+ * If called twice for the same context, does nothing the second
+ * time. If called once with context A and once with context B,
+ * context B replaces context A as the context monitoring the
+ * connection.
+ */
+void
+g_dbus_integrate_dbus_1_connection (DBusConnection *connection,
+ GMainContext *context)
+{
+ ConnectionSetup *old_setup;
+ ConnectionSetup *cs;
+
+ ensure_slots ();
+
+ if (context == NULL)
+ context = g_main_context_default ();
+
+ cs = NULL;
+
+ old_setup = dbus_connection_get_data (connection, _dbus_gmain_connection_slot);
+ if (old_setup != NULL)
+ {
+ if (old_setup->context == context)
+ return; /* nothing to do */
+
+ cs = connection_setup_new_from_old (context, old_setup);
+
+ /* Nuke the old setup */
+ dbus_connection_set_data (connection, _dbus_gmain_connection_slot, NULL, NULL);
+ old_setup = NULL;
+ }
+
+ if (cs == NULL)
+ cs = connection_setup_new (context, connection);
+
+ if (!dbus_connection_set_data (connection, _dbus_gmain_connection_slot, cs,
+ (DBusFreeFunction)connection_setup_free))
+ goto nomem;
+
+ if (!dbus_connection_set_watch_functions (connection,
+ add_watch,
+ remove_watch,
+ watch_toggled,
+ cs, NULL))
+ goto nomem;
+
+ if (!dbus_connection_set_timeout_functions (connection,
+ add_timeout,
+ remove_timeout,
+ timeout_toggled,
+ cs, NULL))
+ goto nomem;
+
+ dbus_connection_set_wakeup_main_function (connection,
+ wakeup_main,
+ cs, NULL);
+
+ return;
+
+ nomem:
+ _g_dbus_oom ();
+}
+
+/**
+ * g_dbus_unintegrate_dbus_1_connection:
+ * @connection: A #DBusConnection.
+ *
+ * Removes mainloop integration for @connection.
+ **/
+void
+g_dbus_unintegrate_dbus_1_connection (DBusConnection *connection)
+{
+ ensure_slots ();
+
+ if (!dbus_connection_set_data (connection, _dbus_gmain_connection_slot, NULL,
+ NULL))
+ goto nomem;
+
+ if (!dbus_connection_set_watch_functions (connection,
+ NULL,
+ NULL,
+ NULL,
+ NULL, NULL))
+ goto nomem;
+
+ if (!dbus_connection_set_timeout_functions (connection,
+ NULL,
+ NULL,
+ NULL,
+ NULL, NULL))
+ goto nomem;
+
+ dbus_connection_set_wakeup_main_function (connection,
+ NULL,
+ NULL, NULL);
+
+ return;
+
+ nomem:
+ _g_dbus_oom ();
+}
+
+/**
+ * g_dbus_integrate_dbus_1_server:
+ * @server: A #DBusServer.
+ * @context: the #GMainContext or #NULL for default
+ *
+ * Sets the watch and timeout functions of a #DBusServer
+ * to integrate the server with the GLib main loop.
+ * In most cases the context argument should be #NULL.
+ *
+ * If called twice for the same context, does nothing the second
+ * time. If called once with context A and once with context B,
+ * context B replaces context A as the context monitoring the
+ * connection.
+ */
+void
+g_dbus_integrate_dbus_1_server (DBusServer *server,
+ GMainContext *context)
+{
+ ConnectionSetup *old_setup;
+ ConnectionSetup *cs;
+
+ ensure_slots ();
+
+ dbus_server_allocate_data_slot (&server_slot);
+ if (server_slot < 0)
+ goto nomem;
+
+ if (context == NULL)
+ context = g_main_context_default ();
+
+ cs = NULL;
+
+ old_setup = dbus_server_get_data (server, server_slot);
+ if (old_setup != NULL)
+ {
+ if (old_setup->context == context)
+ return; /* nothing to do */
+
+ cs = connection_setup_new_from_old (context, old_setup);
+
+ /* Nuke the old setup */
+ dbus_server_set_data (server, server_slot, NULL, NULL);
+ old_setup = NULL;
+ }
+
+ if (cs == NULL)
+ cs = connection_setup_new (context, NULL);
+
+ if (!dbus_server_set_data (server, server_slot, cs,
+ (DBusFreeFunction)connection_setup_free))
+ goto nomem;
+
+ if (!dbus_server_set_watch_functions (server,
+ add_watch,
+ remove_watch,
+ watch_toggled,
+ cs, NULL))
+ goto nomem;
+
+ if (!dbus_server_set_timeout_functions (server,
+ add_timeout,
+ remove_timeout,
+ timeout_toggled,
+ cs, NULL))
+ goto nomem;
+
+ return;
+
+ nomem:
+ _g_dbus_oom ();
+}
+
+/**
+ * g_dbus_unintegrate_dbus_1_server:
+ * @server: A #DBusServer.
+ *
+ * Removes mainloop integration for @server.
+ **/
+void
+g_dbus_unintegrate_dbus_1_server (DBusServer *server)
+{
+ ensure_slots ();
+
+ if (!dbus_server_set_data (server, server_slot, NULL,
+ NULL))
+ goto nomem;
+
+ if (!dbus_server_set_watch_functions (server,
+ NULL,
+ NULL,
+ NULL,
+ NULL, NULL))
+ goto nomem;
+
+ if (!dbus_server_set_timeout_functions (server,
+ NULL,
+ NULL,
+ NULL,
+ NULL, NULL))
+ goto nomem;
+
+ return;
+
+ nomem:
+ _g_dbus_oom ();
+}
+
+
+#define __G_DBUS_MAINLOOP_C__
+#include "gdbusaliasdef.c"
diff --git a/gdbus/gdbusmainloop.h b/gdbus/gdbusmainloop.h
new file mode 100644
index 0000000..77bb0f0
--- /dev/null
+++ b/gdbus/gdbusmainloop.h
@@ -0,0 +1,45 @@
+/* GDBus - GLib D-Bus Library
+ *
+ * Copyright (C) 2008-2009 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: David Zeuthen <davidz redhat com>
+ */
+
+#if !defined (__G_DBUS_G_DBUS_H_INSIDE__) && !defined (G_DBUS_COMPILATION)
+#error "Only <gdbus/gdbus.h> can be included directly."
+#endif
+
+#ifndef __G_DBUS_MAINLOOP_H__
+#define __G_DBUS_MAINLOOP_H__
+
+#include <gdbus/gdbustypes.h>
+#include <dbus/dbus.h>
+
+G_BEGIN_DECLS
+
+void g_dbus_integrate_dbus_1_connection (DBusConnection *connection,
+ GMainContext *context);
+void g_dbus_unintegrate_dbus_1_connection (DBusConnection *connection);
+
+void g_dbus_integrate_dbus_1_server (DBusServer *server,
+ GMainContext *context);
+void g_dbus_unintegrate_dbus_1_server (DBusServer *server);
+
+G_END_DECLS
+
+#endif /* __G_DBUS_CONNECTION_H__ */
diff --git a/gdbus/gdbusprivate.c b/gdbus/gdbusprivate.c
new file mode 100644
index 0000000..f6e7d75
--- /dev/null
+++ b/gdbus/gdbusprivate.c
@@ -0,0 +1,37 @@
+/* GDBus - GLib D-Bus Library
+ *
+ * Copyright (C) 2008-2009 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: David Zeuthen <davidz redhat com>
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+
+#include <glib/gi18n.h>
+
+#include "gdbustypes.h"
+
+void
+_g_dbus_oom (void)
+{
+ /* TODO: print stack trace etc. */
+ g_error ("OOM from libdbus");
+ abort ();
+}
diff --git a/gdbus/gdbusprivate.h b/gdbus/gdbusprivate.h
new file mode 100644
index 0000000..90d1278
--- /dev/null
+++ b/gdbus/gdbusprivate.h
@@ -0,0 +1,38 @@
+/* GDBus - GLib D-Bus Library
+ *
+ * Copyright (C) 2008-2009 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: David Zeuthen <davidz redhat com>
+ */
+
+#if !defined (G_DBUS_COMPILATION)
+#error "gdbusprivate.h is a private header file."
+#endif
+
+#ifndef __G_DBUS_PRIVATE_H__
+#define __G_DBUS_PRIVATE_H__
+
+#include <gdbus/gdbustypes.h>
+
+G_BEGIN_DECLS
+
+void _g_dbus_oom (void);
+
+G_END_DECLS
+
+#endif /* __G_DBUS_TYPES_H__ */
diff --git a/gdbus/gdbustypes.h b/gdbus/gdbustypes.h
new file mode 100644
index 0000000..21dacb2
--- /dev/null
+++ b/gdbus/gdbustypes.h
@@ -0,0 +1,39 @@
+/* GDBus - GLib D-Bus Library
+ *
+ * Copyright (C) 2008-2009 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: David Zeuthen <davidz redhat com>
+ */
+
+#if !defined (__G_DBUS_G_DBUS_H_INSIDE__) && !defined (G_DBUS_COMPILATION)
+#error "Only <gdbus/gdbus.h> can be included directly."
+#endif
+
+#ifndef __G_DBUS_TYPES_H__
+#define __G_DBUS_TYPES_H__
+
+#include <gdbus/gdbusenums.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GDBusConnection GDBusConnection;
+typedef struct _GBusNameOwner GBusNameOwner;
+
+G_END_DECLS
+
+#endif /* __G_DBUS_TYPES_H__ */
diff --git a/gdbus/makegdbusalias.pl b/gdbus/makegdbusalias.pl
new file mode 100755
index 0000000..a46bb8e
--- /dev/null
+++ b/gdbus/makegdbusalias.pl
@@ -0,0 +1,137 @@
+#!/usr/bin/perl -w
+
+my $do_def = 0;
+
+if (($#ARGV >= 0) && ($ARGV[0] eq "-def")) {
+ shift;
+ $do_def = 1;
+}
+
+print <<EOF;
+/* Generated by makegdbusalias.pl */
+
+#ifndef DISABLE_VISIBILITY
+
+#include "glib.h"
+
+#ifdef G_HAVE_GNUC_VISIBILITY
+
+EOF
+
+if ($do_def) {
+ print <<EOF
+#undef IN_FILE
+#define IN_FILE defined
+
+#undef IN_HEADER
+#define IN_HEADER(x) 1
+
+EOF
+}
+else {
+ print <<EOF
+#define IN_FILE(x) 1
+#define IN_HEADER defined
+
+EOF
+}
+
+my $in_comment = 0;
+my $in_skipped_section = 0;
+
+while (<>) {
+
+ # ignore empty lines
+ next if /^\s*$/;
+
+ # skip comments
+ if ($_ =~ /^\s*\/\*/)
+ {
+ $in_comment = 1;
+ }
+
+ if ($in_comment)
+ {
+ if ($_ =~ /\*\/\s$/)
+ {
+ $in_comment = 0;
+ }
+
+ next;
+ }
+
+ # handle ifdefs
+ if ($_ =~ /^\#endif/)
+ {
+ if (!$in_skipped_section)
+ {
+ print $_;
+ }
+
+ $in_skipped_section = 0;
+
+ next;
+ }
+
+ if ($_ =~ /^\#ifdef\s+(INCLUDE_VARIABLES|INCLUDE_INTERNAL_SYMBOLS|ALL_FILES)/)
+ {
+ $in_skipped_section = 1;
+ }
+
+ if ($in_skipped_section)
+ {
+ next;
+ }
+
+ if ($_ =~ /^\#ifn?def\s+G/)
+ {
+ print $_;
+
+ next;
+ }
+
+ if ($_ =~ /^\#if.*(IN_FILE|IN_HEADER)/)
+ {
+ print $_;
+
+ next;
+ }
+
+ chop;
+ my $str = $_;
+ my @words;
+ my $attributes = "";
+
+ @words = split(/ /, $str);
+ $str = shift(@words);
+ chomp($str);
+ my $alias = "IA__".$str;
+
+ # Drop any Win32 specific .def file syntax, but keep attributes
+ foreach $word (@words) {
+ $attributes = "$attributes $word" unless $word eq "PRIVATE";
+ }
+
+ if (!$do_def) {
+ print <<EOF
+extern __typeof ($str) $alias __attribute((visibility("hidden")))$attributes;
+\#define $str $alias
+
+EOF
+ }
+ else {
+ print <<EOF
+\#undef $str
+extern __typeof ($str) $str __attribute((alias("$alias"), visibility("default")));
+
+EOF
+ }
+}
+
+print <<EOF;
+
+#endif /* G_HAVE_GNUC_VISIBILITY */
+#endif /* DISABLE_VISIBILITY */
+EOF
+
+
diff --git a/gdbus/pltcheck.sh b/gdbus/pltcheck.sh
new file mode 100755
index 0000000..4461304
--- /dev/null
+++ b/gdbus/pltcheck.sh
@@ -0,0 +1,19 @@
+#!/bin/sh
+
+LANG=C
+
+status=0
+
+if ! which readelf 2>/dev/null >/dev/null; then
+ echo "'readelf' not found; skipping test"
+ exit 0
+fi
+
+SKIP='\<g_'
+
+for so in .libs/lib*.so; do
+ echo Checking $so for local PLT entries
+ readelf -r $so | grep 'JU\?MP_SLOT\?' | grep '\<g_' | grep -v $SKIP && status=1
+done
+
+exit $status
diff --git a/gdbus/tests/Makefile.am b/gdbus/tests/Makefile.am
new file mode 100644
index 0000000..1a6d855
--- /dev/null
+++ b/gdbus/tests/Makefile.am
@@ -0,0 +1,30 @@
+include $(top_srcdir)/Makefile.decl
+
+NULL =
+
+INCLUDES = \
+ -g \
+ -I$(top_srcdir) \
+ -I$(top_srcdir)/glib \
+ -I$(top_srcdir)/gmodule \
+ -I$(top_srcdir)/gobject \
+ -I$(top_srcdir)/gio \
+ -I$(top_srcdir)/gdbus \
+ $(GLIB_DEBUG_FLAGS) \
+ $(DBUS_CFLAGS) \
+ $(NULL)
+
+check_PROGRAMS = $(TEST_PROGS)
+progs_ldadd = \
+ $(top_builddir)/glib/libglib-2.0.la \
+ $(top_builddir)/gobject/libgobject-2.0.la \
+ $(top_builddir)/gio/libgio-2.0.la \
+ $(top_builddir)/gdbus/libgdbus-2.0.la \
+ $(NULL)
+
+TEST_PROGS += \
+ connection \
+ $(NULL)
+
+connection_SOURCES = connection.c
+connection_LDADD = $(progs_ldadd)
diff --git a/gdbus/tests/connection.c b/gdbus/tests/connection.c
new file mode 100644
index 0000000..58f08c2
--- /dev/null
+++ b/gdbus/tests/connection.c
@@ -0,0 +1,904 @@
+/* GLib testing framework examples and tests
+ *
+ * Copyright (C) 2008-2009 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: David Zeuthen <davidz redhat com>
+ */
+
+#include <gdbus/gdbus.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <signal.h>
+#include <stdio.h>
+
+/* all tests rely on a shared mainloop */
+static GMainLoop *loop = NULL;
+
+/* ---------------------------------------------------------------------------------------------------- */
+/* Utilities for bringing up and tearing down session message bus instances */
+
+static void
+watch_parent (gint fd)
+{
+ GPollFD fds[1];
+ gint num_events;
+ gchar buf[512];
+ guint bytes_read;
+ GArray *buses_to_kill_array;
+
+ fds[0].fd = fd;
+ fds[0].events = G_IO_HUP | G_IO_IN;
+ fds[0].revents = 0;
+
+ buses_to_kill_array = g_array_new (FALSE, TRUE, sizeof (guint));
+
+ do
+ {
+ guint pid;
+ guint n;
+
+ num_events = g_poll (fds, 1, -1);
+ if (num_events == 0)
+ continue;
+
+ if (fds[0].revents == G_IO_HUP)
+ {
+ for (n = 0; n < buses_to_kill_array->len; n++)
+ {
+ pid = g_array_index (buses_to_kill_array, guint, n);
+ g_print ("cleaning up bus with pid %d\n", pid);
+ kill (pid, SIGTERM);
+ }
+ g_array_free (buses_to_kill_array, TRUE);
+ exit (0);
+ }
+
+ //g_debug ("data from parent");
+
+ memset (buf, '\0', sizeof buf);
+ again:
+ bytes_read = read (fds[0].fd, buf, sizeof buf);
+ if (bytes_read < 0 && (errno == EAGAIN || errno == EINTR))
+ goto again;
+
+ if (sscanf (buf, "add %d\n", &pid) == 1)
+ {
+ g_array_append_val (buses_to_kill_array, pid);
+ }
+ else if (sscanf (buf, "remove %d\n", &pid) == 1)
+ {
+ for (n = 0; n < buses_to_kill_array->len; n++)
+ {
+ if (g_array_index (buses_to_kill_array, guint, n) == pid)
+ {
+ g_array_remove_index (buses_to_kill_array, n);
+ pid = 0;
+ break;
+ }
+ }
+ if (pid != 0)
+ {
+ g_warning ("unknown pid %d to remove", pid);
+ }
+ }
+ else
+ {
+ g_warning ("unknown command from parent '%s'", buf);
+ }
+ }
+ while (TRUE);
+
+}
+
+static GHashTable *session_bus_address_to_pid = NULL;
+static gint pipe_fds[2];
+
+static const gchar *
+session_bus_up_with_address (const gchar *given_address)
+{
+ gchar *address;
+ int stdout_fd;
+ GError *error;
+ gchar *argv[] = {"dbus-daemon", "--print-address", "--config-file=foo", NULL};
+ GPid pid;
+ gchar buf[512];
+ ssize_t bytes_read;
+ gchar *config_file_name;
+ gint config_file_fd;
+ GString *config_file_contents;
+
+ address = NULL;
+ error = NULL;
+ config_file_name = NULL;
+ config_file_fd = -1;
+ argv[2] = NULL;
+
+ config_file_fd = g_file_open_tmp ("g-dbus-tests-XXXXXX",
+ &config_file_name,
+ &error);
+ if (config_file_fd < 0)
+ {
+ g_warning ("Error creating temporary config file: %s", error->message);
+ g_error_free (error);
+ goto out;
+ }
+
+ config_file_contents = g_string_new (NULL);
+ g_string_append (config_file_contents, "<busconfig>\n");
+ g_string_append (config_file_contents, " <type>session</type>\n");
+ g_string_append_printf (config_file_contents, " <listen>%s</listen>\n", given_address);
+ g_string_append (config_file_contents,
+ " <policy context=\"default\">\n"
+ " <!-- Allow everything to be sent -->\n"
+ " <allow send_destination=\"*\" eavesdrop=\"true\"/>\n"
+ " <!-- Allow everything to be received -->\n"
+ " <allow eavesdrop=\"true\"/>\n"
+ " <!-- Allow anyone to own anything -->\n"
+ " <allow own=\"*\"/>\n"
+ " </policy>\n");
+ g_string_append (config_file_contents, "</busconfig>\n");
+
+ if (write (config_file_fd, config_file_contents->str, config_file_contents->len) != config_file_contents->len)
+ {
+ g_warning ("Error writing %d bytes to config file: %m", (gint) config_file_contents->len);
+ g_string_free (config_file_contents, TRUE);
+ goto out;
+ }
+ g_string_free (config_file_contents, TRUE);
+
+ argv[2] = g_strdup_printf ("--config-file=%s", config_file_name);
+
+ if (session_bus_address_to_pid == NULL)
+ {
+ /* keep a mapping from session bus address to the pid */
+ session_bus_address_to_pid = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+
+ /* fork a child to clean up session buses when we are killed */
+ if (pipe (pipe_fds) != 0)
+ {
+ g_warning ("pipe() failed: %m");
+ g_assert_not_reached ();
+ }
+ switch (fork ())
+ {
+ case -1:
+ g_warning ("fork() failed: %m");
+ g_assert_not_reached ();
+ break;
+
+ case 0:
+ /* child */
+ close (pipe_fds[1]);
+ watch_parent (pipe_fds[0]);
+ break;
+
+ default:
+ /* parent */
+ close (pipe_fds[0]);
+ break;
+ }
+
+ //atexit (cleanup_session_buses);
+ /* TODO: need to handle the cases where we crash */
+ }
+ else
+ {
+ /* check if we already have a bus running for this address */
+ if (g_hash_table_lookup (session_bus_address_to_pid, given_address) != NULL)
+ {
+ g_warning ("Already have a bus instance for the given address %s", given_address);
+ goto out;
+ }
+ }
+
+ if (!g_spawn_async_with_pipes (NULL,
+ argv,
+ NULL,
+ G_SPAWN_SEARCH_PATH,
+ NULL,
+ NULL,
+ &pid,
+ NULL,
+ &stdout_fd,
+ NULL,
+ &error))
+ {
+ g_warning ("Error spawning dbus-daemon: %s", error->message);
+ g_error_free (error);
+ goto out;
+ }
+
+ memset (buf, '\0', sizeof buf);
+ again:
+ bytes_read = read (stdout_fd, buf, sizeof buf);
+ if (bytes_read < 0 && (errno == EAGAIN || errno == EINTR))
+ goto again;
+ close (stdout_fd);
+
+ if (bytes_read == 0 || bytes_read == sizeof buf)
+ {
+ g_warning ("Error reading address from dbus daemon, %d bytes read", (gint) bytes_read);
+ kill (SIGTERM, pid);
+ goto out;
+ }
+
+ address = g_strdup (buf);
+ g_strstrip (address);
+
+ /* write the pid to the child so it can kill it when we die */
+ g_snprintf (buf, sizeof buf, "add %d\n", (guint) pid);
+ write (pipe_fds[1], buf, strlen (buf));
+
+ g_hash_table_insert (session_bus_address_to_pid, address, GUINT_TO_POINTER (pid));
+
+ out:
+ if (config_file_fd > 0)
+ {
+ if (close (config_file_fd) != 0)
+ {
+ g_warning ("Error closing fd for config file %s: %m", config_file_name);
+ }
+ g_assert (config_file_name != NULL);
+ if (unlink (config_file_name) != 0)
+ {
+ g_warning ("Error unlinking config file %s: %m", config_file_name);
+ }
+ }
+ g_free (argv[2]);
+ g_free (config_file_name);
+ return address;
+}
+
+static void
+session_bus_down_with_address (const gchar *address)
+{
+ gpointer value;
+ GPid pid;
+ gchar buf[512];
+
+ g_assert (address != NULL);
+ g_assert (session_bus_address_to_pid != NULL);
+
+ value = g_hash_table_lookup (session_bus_address_to_pid, address);
+ g_assert (value != NULL);
+
+ pid = GPOINTER_TO_UINT (g_hash_table_lookup (session_bus_address_to_pid, address));
+
+ kill (pid, SIGTERM);
+
+ /* write the pid to the child so it won't kill it when we die */
+ g_snprintf (buf, sizeof buf, "remove %d\n", (guint) pid);
+ write (pipe_fds[1], buf, strlen (buf));
+
+ g_hash_table_remove (session_bus_address_to_pid, address);
+}
+
+static gchar *temporary_address = NULL;
+static gchar *temporary_address_used_by_bus = NULL;
+
+static const gchar *
+session_bus_get_temporary_address (void)
+{
+ if (temporary_address == NULL)
+ {
+ /* TODO: maybe use a more random name etc etc */
+ temporary_address = g_strdup_printf ("unix:path=/tmp/g-dbus-tests-pid-%d", getpid ());
+ }
+
+ return temporary_address;
+}
+
+static const gchar *
+session_bus_up (void)
+{
+ if (temporary_address_used_by_bus != NULL)
+ {
+ g_warning ("There is already a session bus up");
+ goto out;
+ }
+
+ temporary_address_used_by_bus = g_strdup (session_bus_up_with_address (session_bus_get_temporary_address ()));
+
+ out:
+ return temporary_address_used_by_bus;
+}
+
+static void
+session_bus_down (void)
+{
+ if (temporary_address_used_by_bus == NULL)
+ {
+ g_warning ("There is not a session bus up");
+ }
+ else
+ {
+ session_bus_down_with_address (temporary_address_used_by_bus);
+ g_free (temporary_address_used_by_bus);
+ temporary_address_used_by_bus = NULL;
+ }
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+/* Message Bus tests - check all aspects of connecting and reconnecting to bus instances */
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+on_opened_no_bus_exists (GDBusConnection *connection,
+ gpointer user_data)
+{
+ g_assert_not_reached ();
+}
+
+static void
+on_closed_no_bus_exists (GDBusConnection *connection,
+ gpointer user_data)
+{
+ g_assert_not_reached ();
+}
+
+static void
+get_connection_callback_no_bus_exists (GDBusConnection *connection,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GError *error;
+ gboolean ret;
+
+ error = NULL;
+ ret = g_dbus_connection_bus_get_finish (connection,
+ result,
+ &error);
+ g_assert_error (error, G_DBUS_ERROR, G_DBUS_ERROR_FILE_NOT_FOUND);
+ g_error_free (error);
+ g_assert (!ret);
+ g_main_loop_quit (loop);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+on_opened_bus_exists (GDBusConnection *connection,
+ gpointer user_data)
+{
+ gboolean *val = user_data;
+ *val = TRUE;
+}
+
+static void
+on_opened_bus_exists_reconnect (GDBusConnection *connection,
+ gpointer user_data)
+{
+ gboolean *val = user_data;
+ *val = TRUE;
+ g_main_loop_quit (loop);
+}
+
+static void
+on_closed_bus_exists (GDBusConnection *connection,
+ gpointer user_data)
+{
+ gboolean *val = user_data;
+ *val = FALSE;
+
+ g_main_loop_quit (loop);
+}
+
+static void
+get_connection_callback_bus_exists (GDBusConnection *connection,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GError *error;
+ gboolean ret;
+ gboolean *val = user_data;
+
+ /* check we get the ::opened signal before the callback */
+ g_assert (*val);
+
+ error = NULL;
+ ret = g_dbus_connection_bus_get_finish (connection,
+ result,
+ &error);
+ g_assert_no_error (error);
+ g_assert (ret);
+ g_main_loop_quit (loop);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+get_connection_callback_singleton (GDBusConnection *connection,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GError *error;
+ gboolean ret;
+
+ error = NULL;
+ ret = g_dbus_connection_bus_get_finish (connection,
+ result,
+ &error);
+ g_assert_no_error (error);
+ g_assert (ret);
+ g_main_loop_quit (loop);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+get_connection_callback_private (GDBusConnection *connection,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GError *error;
+ gboolean ret;
+
+ error = NULL;
+ ret = g_dbus_connection_bus_get_private_finish (connection,
+ result,
+ &error);
+ g_assert_no_error (error);
+ g_assert (ret);
+ g_main_loop_quit (loop);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+test_message_bus_connections (void)
+{
+ GDBusConnection *c;
+ GDBusConnection *c2;
+ gboolean val;
+
+ /* Check for correct behavior when no bus is present */
+ c = g_dbus_connection_bus_get (G_MESSAGE_BUS_TYPE_SESSION,
+ NULL,
+ (GAsyncReadyCallback) get_connection_callback_no_bus_exists,
+ NULL);
+ g_signal_connect (c, "opened", G_CALLBACK (on_opened_no_bus_exists), NULL);
+ g_signal_connect (c, "closed", G_CALLBACK (on_closed_no_bus_exists), NULL);
+ g_assert (!g_dbus_connection_get_is_open (c));
+ g_main_loop_run (loop);
+ g_assert (!g_dbus_connection_get_is_open (c));
+ g_object_unref (c);
+
+ /* Check for correct behavior if a bus is present and that we get the ::opened signal
+ *
+ * Then check that get the ::closed signal when tearing down the bus.
+ */
+ session_bus_up ();
+ val = FALSE;
+ c = g_dbus_connection_bus_get (G_MESSAGE_BUS_TYPE_SESSION,
+ NULL, /* cancellable */
+ (GAsyncReadyCallback) get_connection_callback_bus_exists,
+ &val); /* user_data */
+ g_signal_connect (c, "opened", G_CALLBACK (on_opened_bus_exists), &val);
+ g_signal_connect (c, "closed", G_CALLBACK (on_closed_bus_exists), &val);
+ g_assert (!g_dbus_connection_get_is_open (c));
+ g_main_loop_run (loop);
+ g_assert (g_dbus_connection_get_is_open (c));
+ g_assert (val);
+ g_dbus_connection_set_exit_on_close (c, FALSE);
+ session_bus_down ();
+ g_main_loop_run (loop);
+ g_assert (!g_dbus_connection_get_is_open (c));
+ g_assert (!val);
+
+ /* Now check that we get the ::opened signal on the existing connection object when
+ * bringing up the bus.. this checks that the reconnect logic in GDBusConnection works.
+ *
+ * We replace the ::opened signal handler since we want to break out of the mainloop.
+ */
+ g_signal_handlers_disconnect_by_func (c, on_opened_bus_exists, &val);
+ g_signal_connect (c, "opened", G_CALLBACK (on_opened_bus_exists_reconnect), &val);
+ session_bus_up ();
+ g_main_loop_run (loop);
+ g_assert (g_dbus_connection_get_is_open (c));
+ g_dbus_connection_set_exit_on_close (c, FALSE);
+ g_assert (val);
+
+ /* Check that singleton handling works, e.g. we get the same object for the same bus type */
+ c2 = g_dbus_connection_bus_get (G_MESSAGE_BUS_TYPE_SESSION,
+ NULL, /* cancellable */
+ (GAsyncReadyCallback) get_connection_callback_singleton,
+ NULL); /* user_data */
+ g_assert (c == c2);
+ g_main_loop_run (loop);
+ g_object_unref (c2);
+
+ /* Check that we get a distinct connection, with a distinct unique name, for private connections */
+ c2 = g_dbus_connection_bus_get_private (G_MESSAGE_BUS_TYPE_SESSION,
+ NULL, /* cancellable */
+ (GAsyncReadyCallback) get_connection_callback_private,
+ NULL); /* user_data */
+ g_assert (c != c2);
+ g_main_loop_run (loop);
+ g_assert_cmpstr (g_dbus_connection_get_unique_name (c),
+ !=,
+ g_dbus_connection_get_unique_name (c2));
+ g_object_unref (c2);
+
+ /* Try to bring the bus down and check we get the ::closed signal.
+ *
+ * The existing signal handler does the right thing here.
+ */
+ session_bus_down ();
+ g_main_loop_run (loop);
+ g_assert (!g_dbus_connection_get_is_open (c));
+ g_assert (!val);
+
+ g_object_unref (c);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+/* Test that GBusNameOwner works correctly */
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+on_name_acquired_expect_failure (GBusNameOwner *owner,
+ gpointer user_data)
+{
+ g_assert_not_reached ();
+}
+
+static void
+on_name_lost_expect_failure (GBusNameOwner *owner,
+ gpointer user_data)
+{
+ g_assert_not_reached ();
+}
+
+static void
+on_owner_cb_expect_failure (GBusNameOwner *owner,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ gboolean *val = user_data;
+ gboolean ret;
+ GError *error;
+
+ error = NULL;
+ ret = g_bus_name_owner_new_finish (owner,
+ result,
+ &error);
+ g_assert_error (error, G_DBUS_ERROR, G_DBUS_ERROR_FILE_NOT_FOUND);
+ g_error_free (error);
+ g_assert (!ret);
+
+ *val = TRUE;
+ g_main_loop_quit (loop);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+on_name_acquired_expect_success (GBusNameOwner *owner,
+ gpointer user_data)
+{
+ gboolean *val2 = user_data;
+
+ *val2 = TRUE;
+}
+
+static void
+on_name_lost_expect_success (GBusNameOwner *owner,
+ gpointer user_data)
+{
+ g_assert_not_reached ();
+}
+
+static void
+on_owner_cb_expect_success (GBusNameOwner *owner,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ gboolean *val = user_data;
+ gboolean ret;
+ GError *error;
+
+ error = NULL;
+ ret = g_bus_name_owner_new_finish (owner,
+ result,
+ &error);
+ g_assert_no_error (error);
+ g_assert (ret);
+
+ *val = TRUE;
+ g_main_loop_quit (loop);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+on_name_lost_bringing_down_the_bus (GBusNameOwner *owner,
+ gpointer user_data)
+{
+ gboolean *val = user_data;
+
+ *val = TRUE;
+
+ g_main_loop_quit (loop);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+on_name_acquired_bringing_up_the_bus (GBusNameOwner *owner,
+ gpointer user_data)
+{
+ gboolean *val = user_data;
+
+ *val = TRUE;
+
+ g_main_loop_quit (loop);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+on_owner_cb_expect_failure2 (GBusNameOwner *owner,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ gboolean *val = user_data;
+ gboolean ret;
+ GError *error;
+
+ error = NULL;
+ ret = g_bus_name_owner_new_finish (owner,
+ result,
+ &error);
+ g_assert_error (error, G_DBUS_ERROR, G_DBUS_ERROR_FAILED);
+ g_error_free (error);
+ g_assert (!ret);
+
+ *val = TRUE;
+ g_main_loop_quit (loop);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+on_owner_for_connection_cb_expect_failure (GBusNameOwner *owner,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ gboolean *val = user_data;
+ gboolean ret;
+ GError *error;
+
+ error = NULL;
+ ret = g_bus_name_owner_new_for_connection_finish (owner,
+ result,
+ &error);
+ g_assert_error (error, G_DBUS_ERROR, G_DBUS_ERROR_FAILED);
+ g_error_free (error);
+ g_assert (!ret);
+
+ *val = TRUE;
+ g_main_loop_quit (loop);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+on_name_acquired_for_o2 (GBusNameOwner *owner,
+ gpointer user_data)
+{
+ gboolean *val = user_data;
+
+ *val = TRUE;
+
+ g_main_loop_quit (loop);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+on_name_lost_for_o2 (GBusNameOwner *owner,
+ gpointer user_data)
+{
+ gboolean *val = user_data;
+
+ *val = TRUE;
+
+ g_main_loop_quit (loop);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+test_bus_name_owner (void)
+{
+ GDBusConnection *private_connection;
+ GBusNameOwner *o;
+ GBusNameOwner *o2;
+ gboolean val;
+ gboolean val2;
+
+ /* first try to own a name when there is no bus */
+ val = FALSE;
+ o = g_bus_name_owner_new (G_MESSAGE_BUS_TYPE_SESSION,
+ "org.gtk.Test.Name1",
+ G_BUS_NAME_OWNER_FLAGS_NONE,
+ NULL,
+ (GAsyncReadyCallback) on_owner_cb_expect_failure,
+ &val);
+ g_signal_connect (o, "name-acquired", G_CALLBACK (on_name_acquired_expect_failure), NULL);
+ g_signal_connect (o, "name-lost", G_CALLBACK (on_name_lost_expect_failure), NULL);
+ g_main_loop_run (loop);
+ g_assert (val);
+ g_object_unref (o);
+
+ /* try again, this time with a bus instance - the ::name-acquired signal should fire before the async reply */
+ session_bus_up ();
+ val = FALSE;
+ val2 = FALSE;
+ o = g_bus_name_owner_new (G_MESSAGE_BUS_TYPE_SESSION,
+ "org.gtk.Test.Name1",
+ G_BUS_NAME_OWNER_FLAGS_NONE,
+ NULL,
+ (GAsyncReadyCallback) on_owner_cb_expect_success,
+ &val);
+ g_signal_connect (o, "name-acquired", G_CALLBACK (on_name_acquired_expect_success), &val2);
+ g_signal_connect (o, "name-lost", G_CALLBACK (on_name_lost_expect_success), NULL);
+ g_main_loop_run (loop);
+ g_assert (val);
+ g_assert (val2);
+
+ /* try owning the same name again... the should fail because o is still alive */
+ o2 = g_bus_name_owner_new (G_MESSAGE_BUS_TYPE_SESSION,
+ "org.gtk.Test.Name1",
+ G_BUS_NAME_OWNER_FLAGS_NONE,
+ NULL,
+ (GAsyncReadyCallback) on_owner_cb_expect_failure2,
+ &val);
+ g_main_loop_run (loop);
+ g_assert (val);
+ g_object_unref (o2);
+
+ /* now kill o.. and then attempt to own the same name again.. */
+ g_object_unref (o);
+ val = FALSE;
+ val2 = FALSE;
+ o = g_bus_name_owner_new (G_MESSAGE_BUS_TYPE_SESSION,
+ "org.gtk.Test.Name1",
+ G_BUS_NAME_OWNER_FLAGS_NONE,
+ NULL,
+ (GAsyncReadyCallback) on_owner_cb_expect_success,
+ &val);
+ g_signal_connect (o, "name-acquired", G_CALLBACK (on_name_acquired_expect_success), &val2);
+ g_main_loop_run (loop);
+ g_assert (val);
+ g_assert (val2);
+
+ /* now bring down the bus.. this should trigger the ::name-lost signal */
+ val = FALSE;
+ g_signal_connect (o, "name-lost", G_CALLBACK (on_name_lost_bringing_down_the_bus), &val);
+ g_dbus_connection_set_exit_on_close (g_bus_name_owner_get_connection (o), FALSE);
+ session_bus_down ();
+ g_main_loop_run (loop);
+ g_assert (val);
+
+ /* bring the bus back up... then we should get the ::name-acquired signal
+ *
+ * Can't use existing signal handler since it doesn't quit the main loop.
+ */
+ val = FALSE;
+ g_signal_handlers_disconnect_by_func (o, on_name_acquired_expect_success, &val2);
+ g_signal_connect (o, "name-acquired", G_CALLBACK (on_name_acquired_bringing_up_the_bus), &val);
+ session_bus_up ();
+ g_main_loop_run (loop);
+ g_assert (val);
+
+ /* Create a private connection and a bus name owner for that connection, o2, that tries to own
+ * the name with _REPLACE and _ALLOW_REPLACEMENT. This should fail because o already owns the name
+ * and didn't specify ALLOW_REPLACEMENT.
+ */
+ private_connection = g_dbus_connection_bus_get_private (G_MESSAGE_BUS_TYPE_SESSION,
+ NULL, /* cancellable */
+ (GAsyncReadyCallback) get_connection_callback_private,
+ NULL); /* user_data */
+ g_main_loop_run (loop);
+ val = FALSE;
+ o2 = g_bus_name_owner_new_for_connection (private_connection,
+ "org.gtk.Test.Name1",
+ G_BUS_NAME_OWNER_FLAGS_REPLACE |
+ G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT,
+ NULL,
+ (GAsyncReadyCallback) on_owner_for_connection_cb_expect_failure,
+ &val);
+ g_object_unref (private_connection);
+ g_main_loop_run (loop);
+ g_assert (!g_bus_name_owner_get_owns_name (o2));
+ g_assert (val);
+
+ /* OK, so o is owning the name and o2 is in queue. Kill o and check that o2 acquires the name. */
+ val = FALSE;
+ g_signal_connect (o2, "name-acquired", G_CALLBACK (on_name_acquired_for_o2), &val);
+ g_object_unref (o);
+ g_main_loop_run (loop);
+ g_assert (g_bus_name_owner_get_owns_name (o2));
+ g_assert (val);
+
+ /* Since o2 specified ALLOW_REPLACEMENT, check that o can claim the name only when using REPLACE */
+ val = FALSE;
+ o = g_bus_name_owner_new (G_MESSAGE_BUS_TYPE_SESSION,
+ "org.gtk.Test.Name1",
+ G_BUS_NAME_OWNER_FLAGS_NONE,
+ NULL,
+ (GAsyncReadyCallback) on_owner_cb_expect_failure2,
+ &val);
+ g_main_loop_run (loop);
+ g_assert (val);
+ g_assert (!g_bus_name_owner_get_owns_name (o));
+ g_assert (g_bus_name_owner_get_owns_name (o2));
+ g_object_unref (o);
+ /* and now with REPLACE */
+ val = FALSE;
+ o = g_bus_name_owner_new (G_MESSAGE_BUS_TYPE_SESSION,
+ "org.gtk.Test.Name1",
+ G_BUS_NAME_OWNER_FLAGS_REPLACE,
+ NULL,
+ (GAsyncReadyCallback) on_owner_cb_expect_success,
+ &val);
+ g_main_loop_run (loop);
+ g_assert (val);
+ g_assert (g_bus_name_owner_get_owns_name (o));
+ /* we might not have gotten the signal for o2 yet */
+ if (g_bus_name_owner_get_owns_name (o2))
+ {
+ val = FALSE;
+ g_signal_connect (o2, "name-lost", G_CALLBACK (on_name_lost_for_o2), &val);
+ g_main_loop_run (loop);
+ g_assert (val);
+ g_assert (!g_bus_name_owner_get_owns_name (o2));
+ }
+ g_object_unref (o2);
+ g_object_unref (o);
+
+ session_bus_down ();
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+int
+main (int argc,
+ char *argv[])
+{
+ g_type_init ();
+ g_test_init (&argc, &argv, NULL);
+
+ /* all the tests rely on a shared main loop */
+ loop = g_main_loop_new (NULL, FALSE);
+
+ /* all the tests use a session bus with a well-known address that we can bring up and down
+ * using session_bus_up() and session_bus_down().
+ */
+ g_unsetenv ("DISPLAY");
+ g_setenv ("DBUS_SESSION_BUS_ADDRESS", session_bus_get_temporary_address (), TRUE);
+
+ g_test_add_func ("/gdbus/message-bus-connections", test_message_bus_connections);
+ g_test_add_func ("/gdbus/bus-name-owner", test_bus_name_owner);
+ return g_test_run();
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]