diff --git a/gio/gapplication.c b/gio/gapplication.c index 32341cf68..1172a591f 100644 --- a/gio/gapplication.c +++ b/gio/gapplication.c @@ -159,6 +159,14 @@ * * * + * + * Using extra D-Bus hooks with a GApplication + * + * + * FIXME: MISSING XINCLUDE CONTENT + * + * + * */ /** @@ -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", diff --git a/gio/gapplication.h b/gio/gapplication.h index f5d912f0b..087682ebc 100644 --- a/gio/gapplication.h +++ b/gio/gapplication.h @@ -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; diff --git a/gio/gapplicationimpl-dbus.c b/gio/gapplicationimpl-dbus.c index df3f103be..1248d0f1d 100644 --- a/gio/gapplicationimpl-dbus.c +++ b/gio/gapplicationimpl-dbus.c @@ -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); diff --git a/gio/tests/Makefile.am b/gio/tests/Makefile.am index c5cf59d4a..14411e222 100644 --- a/gio/tests/Makefile.am +++ b/gio/tests/Makefile.am @@ -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) diff --git a/gio/tests/gapplication-example-dbushooks.c b/gio/tests/gapplication-example-dbushooks.c new file mode 100644 index 000000000..ab33f460e --- /dev/null +++ b/gio/tests/gapplication-example-dbushooks.c @@ -0,0 +1,99 @@ +#include +#include +#include + +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; +}