diff --git a/Makefile.am b/Makefile.am index 8ce8d5b..9d95bb8 100644 --- a/Makefile.am +++ b/Makefile.am @@ -4,6 +4,12 @@ DIST_SUBDIRS=dbus bus doc tools test pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = dbus-1.pc +if HAVE_GLIB + SUBDIRS += dbus-gmain + DIST_SUBDIRS += dbus-gmain + pkgconfig_DATA += dbus-gmain-1.pc +endif + DISTCLEANFILES = \ dbus-1.pc diff --git a/configure.in b/configure.in index c603398..18e1ce9 100644 --- a/configure.in +++ b/configure.in @@ -137,6 +137,7 @@ AC_ARG_ENABLE(inotify, AS_HELP_STRING([--enable-inotify],[build with inotify sup AC_ARG_ENABLE(kqueue, AS_HELP_STRING([--enable-kqueue],[build with kqueue support]),enable_kqueue=$enableval,enable_kqueue=auto) AC_ARG_ENABLE(console-owner-file, AS_HELP_STRING([--enable-console-owner-file],[enable console owner file]),enable_console_owner_file=$enableval,enable_console_owner_file=auto) AC_ARG_ENABLE(userdb-cache, AS_HELP_STRING([--enable-userdb-cache],[build with userdb-cache support]),enable_userdb_cache=$enableval,enable_userdb_cache=yes) +AC_ARG_ENABLE(glib, AS_HELP_STRING([--enable-glib],[enable libdbus-gmain glib main loop integration library]),enable_glib=$enableval,enable_glib=yes) AC_ARG_WITH(xml, AS_HELP_STRING([--with-xml=[libxml/expat]],[XML library to use])) AC_ARG_WITH(init-scripts, AS_HELP_STRING([--with-init-scripts=[redhat]],[Style of init scripts to install])) @@ -997,6 +998,16 @@ if test x$dbus_win = xyes ; then fi fi +# glib detection +if test x$enable_glib = xno ; then + have_glib=no; +else + PKG_CHECK_MODULES(GLIB, glib-2.0, have_glib=yes, have_glib=no) +fi +AC_SUBST(GLIB_CFLAGS) +AC_SUBST(GLIB_LIBS) +AM_CONDITIONAL(HAVE_GLIB, test x$have_glib = xyes) + #### Set up final flags DBUS_CLIENT_CFLAGS= DBUS_CLIENT_LIBS="$THREAD_LIBS $NETWORK_libs" @@ -1591,6 +1602,7 @@ bus/dbus.service bus/dbus.socket Makefile dbus/Makefile +dbus-gmain/Makefile bus/Makefile tools/Makefile test/Makefile @@ -1598,6 +1610,7 @@ test/name-test/Makefile doc/Makefile doc/dbus-daemon.1 dbus-1.pc +dbus-gmain-1.pc test/data/valid-config-files/debug-allow-all.conf test/data/valid-config-files/debug-allow-all-sha1.conf test/data/valid-config-files-system/debug-allow-all-pass.conf @@ -1654,6 +1667,7 @@ echo " Building dnotify support: ${have_dnotify} Building kqueue support: ${have_kqueue} Building X11 code: ${enable_x11} + Building glib mainloop integration: ${have_glib} Building Doxygen docs: ${enable_doxygen_docs} Building XML docs: ${enable_xml_docs} Building cache support: ${enable_userdb_cache} diff --git a/dbus-gmain/Makefile.am b/dbus-gmain/Makefile.am new file mode 100644 index 0000000..d6686f4 --- /dev/null +++ b/dbus-gmain/Makefile.am @@ -0,0 +1,53 @@ +INCLUDES = \ + -I$(top_srcdir) \ + -I$(top_builddir) \ + $(DBUS_CFLAGS) \ + $(GLIB_CFLAGS) \ + -DDBUS_COMPILATION=1 \ + -DDBUS_LOCALEDIR=\"$(prefix)/@DATADIRNAME@/locale\" + +lib_LTLIBRARIES=libdbus-gmain-1.la + +dbus-glib-error-switch.h: make-dbus-glib-error-switch.sh + $(LIBTOOL) --mode=execute $(srcdir)/make-dbus-glib-error-switch.sh $(DBUS_INCLUDEDIR)/dbus-1.0/dbus/dbus-protocol.h $@ + +libdbus_gmain_1_la_SOURCES = \ + dbus-gmain.c \ + dbus-gmain.h + +libdbus_gmain_HEADERS = \ + dbus-gmain.h + +libdbus_gmaindir = $(includedir)/dbus-1.0/dbus + +libdbus_gmain_1_la_LIBADD= $(top_builddir)/dbus/libdbus-1.la \ + $(GLIB_LIBS) + +## don't export symbols that start with "_" (we use this +## convention for internal symbols) +libdbus_gmain_1_la_LDFLAGS= -export-symbols-regex "^[^_].*" -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) -no-undefined + +if DBUS_BUILD_TESTS + +## we use noinst_PROGRAMS not check_PROGRAMS for TESTS so that we +## build even when not doing "make check" +noinst_PROGRAMS= $(TESTS) + +## note that TESTS has special meaning (stuff to use in make check) +## so if adding tests not to be run in make check, don't add them to +## TESTS +TESTS=dbus-test-gmain + +## FIXME we aren't running dbus-glib-tool --self-test + +dbus_test_gmain_SOURCES= \ + dbus-test-gmain.c + +dbus_test_gmain_LDADD= $(builddir)/libdbus-gmain-1.la + +else +### not building tests +TESTS= + +endif + diff --git a/dbus-gmain/dbus-gmain.c b/dbus-gmain/dbus-gmain.c new file mode 100644 index 0000000..1e7d846 --- /dev/null +++ b/dbus-gmain/dbus-gmain.c @@ -0,0 +1,683 @@ +/* -*- mode: C; c-file-style: "gnu" -*- */ +/* dbus-gmain.c GLib main loop integration + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include +#include "dbus-gmain.h" +#include + +#include +#define _(x) dgettext (GETTEXT_PACKAGE, x) +#define N_(x) x + +/** + * @defgroup DBusGLibInternals GLib bindings implementation details + * @ingroup DBusInternals + * @brief Implementation details of GLib bindings + * + * @{ + */ + +/** + * DBusGMessageQueue: + * A GSource subclass for dispatching DBusConnection messages. + * We need this on top of the IO handlers, because sometimes + * there are messages to dispatch queued up but no IO pending. + */ +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; + +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; +} + +/* Attach the connection setup to the given watch, removing any + * previously-attached connection setup. + */ +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; + + 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 || handler->cs != cs) + 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; +} + +/** @} */ /* End of GLib bindings internals */ + +/** @addtogroup DBusGLib + * @{ + */ + +/** + * dbus_connection_setup_with_g_main: + * @connection: the connection + * @context: the #GMainContext or #NULL for default context + * + * Sets the watch and timeout functions of a #DBusConnection + * 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 +dbus_connection_setup_with_g_main (DBusConnection *connection, + GMainContext *context) +{ + ConnectionSetup *old_setup; + ConnectionSetup *cs; + + /* FIXME we never free the slot, so its refcount just keeps growing, + * which is kind of broken. + */ + dbus_connection_allocate_data_slot (&_dbus_gmain_connection_slot); + if (_dbus_gmain_connection_slot < 0) + goto nomem; + + 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_error ("Not enough memory to set up DBusConnection for use with GLib"); +} + +/** + * dbus_server_setup_with_g_main: + * @server: the server + * @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 +dbus_server_setup_with_g_main (DBusServer *server, + GMainContext *context) +{ + ConnectionSetup *old_setup; + ConnectionSetup *cs; + + /* FIXME we never free the slot, so its refcount just keeps growing, + * which is kind of broken. + */ + 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_error ("Not enough memory to set up DBusServer for use with GLib"); +} + +/** @} */ /* end of public API */ diff --git a/dbus-gmain/dbus-gmain.h b/dbus-gmain/dbus-gmain.h new file mode 100644 index 0000000..39b8bce --- /dev/null +++ b/dbus-gmain/dbus-gmain.h @@ -0,0 +1,39 @@ +/* -*- mode: C; c-file-style: "gnu" -*- */ +/* dbus-gmain.h GLib main loop integration + * + * Copyright (C) 2002, 2003 CodeFactory AB + * Copyright (C) 2003, 2004 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ +#ifndef DBUS_GMAIN_H +#define DBUS_GMAIN_H + +#include +#include + +G_BEGIN_DECLS + +void dbus_connection_setup_with_g_main (DBusConnection *connection, + GMainContext *context); +void dbus_server_setup_with_g_main (DBusServer *server, + GMainContext *context); + +G_END_DECLS + +#endif /* DBUS_GMAIN_H */ diff --git a/dbus-gmain/dbus-test-gmain.c b/dbus-gmain/dbus-test-gmain.c new file mode 100644 index 0000000..0a92b65 --- /dev/null +++ b/dbus-gmain/dbus-test-gmain.c @@ -0,0 +1,95 @@ +#include +#include +#include "dbus/dbus.h" +#include "dbus-gmain.h" + +DBusConnection *bus; +GMainContext *main_context; + +typedef struct _SpiReentrantCallClosure +{ + GMainLoop *loop; + DBusMessage *reply; +} SpiReentrantCallClosure; + +static void +set_reply (DBusPendingCall * pending, void *user_data) +{ + SpiReentrantCallClosure* closure = (SpiReentrantCallClosure *) user_data; + + closure->reply = dbus_pending_call_steal_reply (pending); + dbus_connection_setup_with_g_main (bus, NULL); + + g_main_loop_quit (closure->loop); +} + +static DBusMessage * +send_and_allow_reentry (DBusConnection * bus, DBusMessage * message) +{ + DBusPendingCall *pending; + SpiReentrantCallClosure closure; + + closure.loop = g_main_loop_new (main_context, FALSE); + dbus_connection_setup_with_g_main (bus, main_context); + + if (!dbus_connection_send_with_reply (bus, message, &pending, 3000)) + { + dbus_connection_setup_with_g_main (bus, NULL); + return NULL; + } + dbus_pending_call_set_notify (pending, set_reply, (void *) &closure, NULL); + g_main_loop_run (closure.loop); + + g_main_loop_unref (closure.loop); + return closure.reply; +} + +int +main(int argc, const char *argv[]) +{ + DBusError error; + DBusMessage *message = NULL, *reply = NULL; + dbus_int32_t pid; + const char *str; + + main_context = g_main_context_new (); + dbus_error_init (&error); + bus = dbus_bus_get (DBUS_BUS_SESSION, &error); + if (!bus) + { + fprintf(stderr, "Couldn't connect to bus: %s\n", error.name); + return 1; + } + dbus_connection_setup_with_g_main (bus, NULL); + message = dbus_message_new_method_call ("org.freedesktop.DBus", "/org/freedesktop/DBus", DBUS_INTERFACE_DBUS, "GetId"); + reply = send_and_allow_reentry (bus, message); + if (dbus_message_get_type (reply) == DBUS_MESSAGE_TYPE_ERROR) + { + char *err; + dbus_message_get_args (reply, NULL, DBUS_TYPE_STRING, &err, DBUS_TYPE_INVALID); + fprintf (stderr, "Got error: %s\n", err); + return 1; + } + dbus_message_unref (reply); + dbus_message_unref (message); + message = dbus_message_new_method_call ("org.freedesktop.DBus", "/org/freedesktop/DBus", DBUS_INTERFACE_DBUS, "GetId"); + reply = send_and_allow_reentry (bus, message); + if (!reply) + { + fprintf(stderr, "Sorry; dbus wouldn't answer me: %s\n", error.message); + exit(1); + } + if (dbus_message_get_type (reply) == DBUS_MESSAGE_TYPE_ERROR) + { + char *err; + dbus_message_get_args (reply, NULL, DBUS_TYPE_STRING, &err, DBUS_TYPE_INVALID); + fprintf (stderr, "Got error: %s\n", err); + return 1; + } + if (!dbus_message_get_args (reply, &error, DBUS_TYPE_STRING, &str, DBUS_TYPE_INVALID)) + { + fprintf(stderr, "Sorry; can't communicate: %s\n", error.message); + exit(1); + } + exit (0); +}