application: Add dbus register/unregister hooks

When the application is using its D-Bus backend, it is useful to be able
to export extra D-Bus objects at the right time, i.e. *before* the application
tries to own the bus name. This is accomplished here by adding a hook
in GApplicationClass for this; and a corresponding hook that will be called
on unregistration to undo whatever the register hook did.

Bug #675509.
This commit is contained in:
Christian Persch 2012-05-05 16:52:28 +02:00
parent f642209ef4
commit 4979c1d075
5 changed files with 162 additions and 2 deletions

View File

@ -159,6 +159,14 @@
* </xi:include>
* </programlisting>
* </example>
*
* <example id="gapplication-example-dbushooks"><title>Using extra D-Bus hooks with a GApplication</title>
* <programlisting>
* <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="../../../../gio/tests/gapplication-example-dbushooks.c">
* <xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback>
* </xi:include>
* </programlisting>
* </example>
*/
/**
@ -190,6 +198,16 @@
* g_application_run() if the use-count is non-zero. Since 2.32,
* GApplication is iterating the main context directly and is not
* using @run_mainloop anymore
* @dbus_register: invoked locally during registration, if the application is
* using its D-Bus backend. You can use this to export extra objects on the
* bus, that need to exist before the application tries to own the bus name.
* The function is passed the #GDBusConnection to to session bus, and the
* object path that #GApplication will use to export is D-Bus API.
* If this function returns %TRUE, registration will proceed; otherwise
* registration will abort. Since: 2.34
* @dbus_unregister: invoked locally during unregistration, if the application
* is using its D-Bus backend. Use this to undo anything done by the
* @dbus_register vfunc. Since: 2.34
*
* Virtual function table for #GApplication.
*
@ -506,6 +524,22 @@ g_application_real_add_platform_data (GApplication *application,
{
}
static gboolean
g_application_real_dbus_register (GApplication *application,
GDBusConnection *connection,
const gchar *object_path,
GError **error)
{
return TRUE;
}
static void
g_application_real_dbus_unregister (GApplication *application,
GDBusConnection *connection,
const gchar *object_path)
{
}
/* GObject implementation stuff {{{1 */
static void
g_application_set_property (GObject *object,
@ -682,6 +716,8 @@ g_application_class_init (GApplicationClass *class)
class->command_line = g_application_real_command_line;
class->local_command_line = g_application_real_local_command_line;
class->add_platform_data = g_application_real_add_platform_data;
class->dbus_register = g_application_real_dbus_register;
class->dbus_unregister = g_application_real_dbus_unregister;
g_object_class_install_property (object_class, PROP_APPLICATION_ID,
g_param_spec_string ("application-id",

View File

@ -90,8 +90,16 @@ struct _GApplicationClass
void (* run_mainloop) (GApplication *application);
void (* shutdown) (GApplication *application);
gboolean (* dbus_register) (GApplication *application,
GDBusConnection *connection,
const gchar *object_path,
GError **error);
void (* dbus_unregister) (GApplication *application,
GDBusConnection *connection,
const gchar *object_path);
/*< private >*/
gpointer padding[11];
gpointer padding[9];
};
GType g_application_get_type (void) G_GNUC_CONST;

View File

@ -97,7 +97,7 @@ struct _GApplicationImpl
gboolean properties_live;
gboolean primary;
gpointer app;
GApplication *app;
};
@ -228,6 +228,7 @@ g_application_impl_attempt_primary (GApplicationImpl *impl,
const static GDBusInterfaceVTable vtable = {
g_application_impl_method_call,
};
GApplicationClass *app_class = G_APPLICATION_GET_CLASS (impl->app);
GVariant *reply;
guint32 rval;
@ -271,6 +272,12 @@ g_application_impl_attempt_primary (GApplicationImpl *impl,
if (impl->actions_id == 0)
return FALSE;
if (!app_class->dbus_register (impl->app,
impl->session_bus,
impl->object_path,
error))
return FALSE;
if (impl->bus_name == NULL)
{
/* If this is a non-unique application then it is sufficient to
@ -315,6 +322,12 @@ g_application_impl_attempt_primary (GApplicationImpl *impl,
static void
g_application_impl_stop_primary (GApplicationImpl *impl)
{
GApplicationClass *app_class = G_APPLICATION_GET_CLASS (impl->app);
app_class->dbus_unregister (impl->app,
impl->session_bus,
impl->object_path);
if (impl->object_id)
{
g_dbus_connection_unregister_object (impl->session_bus, impl->object_id);

View File

@ -120,6 +120,7 @@ SAMPLE_PROGS = \
gapplication-example-cmdline2 \
gapplication-example-cmdline3 \
gapplication-example-actions \
gapplication-example-dbushooks \
gdbus-daemon \
$(NULL)
@ -451,6 +452,9 @@ gapplication_example_cmdline3_LDADD = $(progs_ldadd)
gapplication_example_actions_SOURCES = gapplication-example-actions.c
gapplication_example_actions_LDADD = $(progs_ldadd)
gapplication_example_dbushooks_SOURCES = gapplication-example-dbushooks.c
gapplication_example_dbushooks_LDADD = $(progs_ldadd)
gmenumodel_SOURCES = gmenumodel.c gdbus-sessionbus.h gdbus-sessionbus.c
gmenumodel_LDADD = $(progs_ldadd)

View File

@ -0,0 +1,99 @@
#include <gio/gio.h>
#include <stdlib.h>
#include <string.h>
static void
activate (GApplication *application)
{
g_print ("activated\n");
/* Note: when doing a longer-lasting action here that returns
* to the mainloop, you should use g_application_hold() and
* g_application_release() to keep the application alive until
* the action is completed.
*/
}
typedef GApplication TestApplication;
typedef GApplicationClass TestApplicationClass;
static GType test_application_get_type (void);
G_DEFINE_TYPE (TestApplication, test_application, G_TYPE_APPLICATION)
static gboolean
test_application_dbus_register (GApplication *application,
GDBusConnection *connection,
const gchar *object_path,
GError **error)
{
/* We must chain up to the parent class */
if (!G_APPLICATION_CLASS (test_application_parent_class)->dbus_register (application,
connection,
object_path,
error))
return FALSE;
/* Now we can do our own stuff here. For example, we could export some D-Bus objects */
return TRUE;
}
static void
test_application_dbus_unregister (GApplication *application,
GDBusConnection *connection,
const gchar *object_path)
{
/* Do our own stuff here, e.g. unexport any D-Bus objects we exported in the dbus_register
* hook above. Be sure to check that we actually did export them, since the hook
* above might have returned early due to the parent class' hook returning FALSE!
*/
/* Lastly, we must chain up to the parent class */
G_APPLICATION_CLASS (test_application_parent_class)->dbus_unregister (application,
connection,
object_path);
}
static void
test_application_init (TestApplication *app)
{
}
static void
test_application_class_init (TestApplicationClass *class)
{
GApplicationClass *g_application_class = G_APPLICATION_CLASS (class);
g_application_class->dbus_register = test_application_dbus_register;
g_application_class->dbus_unregister = test_application_dbus_unregister;
}
static GApplication *
test_application_new (const gchar *application_id,
GApplicationFlags flags)
{
g_return_val_if_fail (g_application_id_is_valid (application_id), NULL);
g_type_init ();
return g_object_new (test_application_get_type (),
"application-id", application_id,
"flags", flags,
NULL);
}
int
main (int argc, char **argv)
{
GApplication *app;
int status;
app = test_application_new ("org.gtk.TestApplication", 0);
g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
g_application_set_inactivity_timeout (app, 10000);
status = g_application_run (app, argc, argv);
g_object_unref (app);
return status;
}