diff options
author | Simon McVittie <simon.mcvittie@collabora.co.uk> | 2014-03-14 19:19:34 +0000 |
---|---|---|
committer | Simon McVittie <simon.mcvittie@collabora.co.uk> | 2014-03-26 18:20:58 +0000 |
commit | 225806386dd163b35b8cc8d3fdccb9434709c99d (patch) | |
tree | 95bc177a90f1cb8c63eb22a4dd082aa98f24c5bc | |
parent | 7ee8429d49a8b625b3fa8c41a0a9f47e8c547d00 (diff) |
TpSvcInterfaceInfo, TpSvcInterfaceSkeleton: add
These will let us export TpSvc objects as GDBus objects.
TpSvcInterfaceSkeleton is private, so it's OK that it makes assumptions
about how TpDBusDaemon will manage its life-cycle.
-rw-r--r-- | docs/reference/telepathy-glib/telepathy-glib-docs.sgml | 1 | ||||
-rw-r--r-- | docs/reference/telepathy-glib/telepathy-glib-sections.txt | 9 | ||||
-rw-r--r-- | telepathy-glib/Makefile.am | 4 | ||||
-rw-r--r-- | telepathy-glib/core-svc-interface.c | 106 | ||||
-rw-r--r-- | telepathy-glib/core-svc-interface.h | 50 | ||||
-rw-r--r-- | telepathy-glib/debug-internal.h | 3 | ||||
-rw-r--r-- | telepathy-glib/debug.c | 2 | ||||
-rw-r--r-- | telepathy-glib/svc-interface-skeleton-internal.h | 71 | ||||
-rw-r--r-- | telepathy-glib/svc-interface-skeleton.c | 243 | ||||
-rw-r--r-- | telepathy-glib/telepathy-glib.h | 1 |
10 files changed, 489 insertions, 1 deletions
diff --git a/docs/reference/telepathy-glib/telepathy-glib-docs.sgml b/docs/reference/telepathy-glib/telepathy-glib-docs.sgml index b72135681..c9d740bfb 100644 --- a/docs/reference/telepathy-glib/telepathy-glib-docs.sgml +++ b/docs/reference/telepathy-glib/telepathy-glib-docs.sgml @@ -177,6 +177,7 @@ <chapter id="ch-service-dbus"> <title>Low-level generated code - service-side</title> <xi:include href="tp-svc.xml"/> + <xi:include href="xml/core-svc-interface.xml"/> <xi:include href="xml/svc-channel.xml"/> <xi:include href="xml/svc-channel-group.xml"/> diff --git a/docs/reference/telepathy-glib/telepathy-glib-sections.txt b/docs/reference/telepathy-glib/telepathy-glib-sections.txt index d8ece0bc5..f07c63f9c 100644 --- a/docs/reference/telepathy-glib/telepathy-glib-sections.txt +++ b/docs/reference/telepathy-glib/telepathy-glib-sections.txt @@ -6331,3 +6331,12 @@ tp_cli_logger_add_signals <SUBSECTION Private> TpLoggerPriv </SECTION> + +<SECTION> +<INCLUDE>telepathy-glib/telepathy-glib.h</INCLUDE> +<TITLE>TpSvcInterface</TITLE> +<FILE>core-svc-interface</FILE> +TpSvcInterfaceInfo +tp_svc_interface_peek_dbus_interface_info +tp_svc_interface_set_dbus_interface_info +</SECTION> diff --git a/telepathy-glib/Makefile.am b/telepathy-glib/Makefile.am index 418818ce2..3aae81205 100644 --- a/telepathy-glib/Makefile.am +++ b/telepathy-glib/Makefile.am @@ -85,6 +85,7 @@ tpginclude_HEADERS = \ contact.h \ contact-operations.h \ base-contact-list.h \ + core-svc-interface.h \ dbus.h \ dbus-daemon.h \ dbus-properties-mixin.h \ @@ -190,6 +191,7 @@ libtelepathy_glib_core_internal_la_LIBADD = $(ALL_LIBS) libtelepathy_glib_core_internal_la_SOURCES = \ core-dbus.c \ core-proxy.c \ + core-svc-interface.c \ core-util.c \ errors.c \ $(NULL) @@ -335,6 +337,8 @@ libtelepathy_glib_main_internal_la_SOURCES = \ stream-tube-channel.c \ stream-tube-connection-internal.h \ stream-tube-connection.c \ + svc-interface-skeleton.c \ + svc-interface-skeleton-internal.h \ text-channel.c \ tls-certificate.c \ tls-certificate-rejection.c \ diff --git a/telepathy-glib/core-svc-interface.c b/telepathy-glib/core-svc-interface.c new file mode 100644 index 000000000..ec9820aab --- /dev/null +++ b/telepathy-glib/core-svc-interface.c @@ -0,0 +1,106 @@ +/* + * Copyright © 2014 Collabora Ltd. + * + * 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.1 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <config.h> +#include <telepathy-glib/core-svc-interface.h> + +/** + * SECTION:core-svc-interface + * @title: TpSvcInterface + * @short_description: glue to export `TpSvc` interfaces on D-Bus + * + * #TpSvcInterfaceInfo describes a dbus-glib-style #GInterface in sufficient + * detail to export it on a #GDBusConnection. + * + * Since: 0.UNRELEASED + */ + +/** + * TpSvcInterfaceInfo: (skip) + * @ref_count: currently -1 since these structures can only be statically + * allocated; will be used for the reference count in the same way + * as #GDBusInterfaceInfo if necessary + * @interface_info: the GDBus interface information + * @vtable: the GDBus vtable, which must expect the object that + * implements the `TpSvc` interface (*not* the #GDBusInterfaceSkeleton!) + * as its `user_data` + * @signals: (array zero-terminated=1): a %NULL-terminated array of + * GLib signal names in the same order as `interface_info->signals` + * + * The necessary glue between a dbus-glib-style `TpSvc` #GInterface + * and telepathy-glib. + * + * These structs are intended to be programmatically-generated. + */ + +static GQuark +quark (void) +{ + static GQuark q = 0; + + if (G_UNLIKELY (q == 0)) + { + q = g_quark_from_static_string ( + "tp_svc_interface_set_dbus_interface_info"); + } + + return q; +} + +/** + * tp_svc_interface_peek_dbus_interface_info: (skip) + * @g_interface: The #GType of a service interface + * + * See whether the given interface has Telepathy code generation data + * attached. + * + * Returns: (transfer null): a #TpSvcInterfaceInfo struct, or %NULL + */ +const TpSvcInterfaceInfo * +tp_svc_interface_peek_dbus_interface_info (GType g_interface) +{ + return g_type_get_qdata (g_interface, quark ()); +} + +/** + * tp_svc_interface_set_dbus_interface_info: (skip) + * @g_interface: The #GType of a service interface + * @info: struct encapsulating the #GDBusInterfaceInfo, the #GDBusVTable + * and the GLib signal names corresponding to D-Bus signals + * @vtable: the vtable, whose methods must expect the object + * implementing @g_interface as their user-data + * + * Declare that @g_interface implements the given D-Bus interface, with the + * given vtable. This may only be called once per GInterface, usually from + * a section of its base_init function that only runs once. + * + * This is typically only used within generated code; there is normally no + * reason to call it manually. + */ +void +tp_svc_interface_set_dbus_interface_info (GType g_interface, + const TpSvcInterfaceInfo *info) +{ + g_return_if_fail (G_TYPE_IS_INTERFACE (g_interface)); + g_return_if_fail (info->ref_count == -1); + g_return_if_fail (tp_svc_interface_peek_dbus_interface_info (g_interface) + == NULL); + + /* g_type_set_qdata wants a non-const pointer */ + g_type_set_qdata (g_interface, quark (), (gpointer) info); +} diff --git a/telepathy-glib/core-svc-interface.h b/telepathy-glib/core-svc-interface.h new file mode 100644 index 000000000..dd5d7933f --- /dev/null +++ b/telepathy-glib/core-svc-interface.h @@ -0,0 +1,50 @@ +/* + * Copyright © 2014 Collabora Ltd. + * + * 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.1 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#if !defined (_TP_GLIB_H_INSIDE) && !defined (_TP_COMPILATION) +#error "Only <telepathy-glib/telepathy-glib.h> can be included directly." +#endif + +#ifndef __TP_CORE_SVC_INTERFACE_H__ +#define __TP_CORE_SVC_INTERFACE_H__ + +#include <gio/gio.h> + +#include <telepathy-glib/defs.h> + +G_BEGIN_DECLS + +typedef struct _TpSvcInterfaceInfo TpSvcInterfaceInfo; + +struct _TpSvcInterfaceInfo { + volatile gint ref_count; + GDBusInterfaceInfo *interface_info; + GDBusInterfaceVTable *vtable; + gchar **signals; + gpointer _reserved[8]; +}; + +void tp_svc_interface_set_dbus_interface_info (GType type, + const TpSvcInterfaceInfo *info); + +const TpSvcInterfaceInfo *tp_svc_interface_peek_dbus_interface_info ( + GType type); + +G_END_DECLS + +#endif diff --git a/telepathy-glib/debug-internal.h b/telepathy-glib/debug-internal.h index 7e756844d..0e09b070f 100644 --- a/telepathy-glib/debug-internal.h +++ b/telepathy-glib/debug-internal.h @@ -36,7 +36,8 @@ typedef enum TP_DEBUG_CALL = 1 << 18, /* Quis custodiet ipsos custodes? */ TP_DEBUG_DEBUGGER = 1 << 19, - TP_DEBUG_TLS = 1 << 20 + TP_DEBUG_TLS = 1 << 20, + TP_DEBUG_SVC = 1 << 21 } TpDebugFlags; gboolean _tp_debug_flag_is_set (TpDebugFlags flag); diff --git a/telepathy-glib/debug.c b/telepathy-glib/debug.c index 62099558f..f8ffc66da 100644 --- a/telepathy-glib/debug.c +++ b/telepathy-glib/debug.c @@ -104,6 +104,7 @@ static GDebugKey keys[] = { { "call", TP_DEBUG_CALL }, { "debugger", TP_DEBUG_DEBUGGER }, { "tls", TP_DEBUG_TLS }, + { "svc", TP_DEBUG_SVC }, { 0, } }; @@ -139,6 +140,7 @@ static DebugKeyToDomain key_to_domain[] = { { TP_DEBUG_ROOM_CONFIG, G_LOG_DOMAIN "/room-config" }, { TP_DEBUG_DEBUGGER, G_LOG_DOMAIN "/debugger" }, { TP_DEBUG_TLS, G_LOG_DOMAIN "/tls" }, + { TP_DEBUG_SVC, G_LOG_DOMAIN "/svc" }, { 0, NULL } }; diff --git a/telepathy-glib/svc-interface-skeleton-internal.h b/telepathy-glib/svc-interface-skeleton-internal.h new file mode 100644 index 000000000..0fb2dd736 --- /dev/null +++ b/telepathy-glib/svc-interface-skeleton-internal.h @@ -0,0 +1,71 @@ +/*<private_header>*/ +/* + * Copyright © 2014 Collabora Ltd. + * + * 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.1 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef __TP_SVC_INTERFACE_SKELETON_INTERNAL_H__ +#define __TP_SVC_INTERFACE_SKELETON_INTERNAL_H__ + +#include <gio/gio.h> + +#include <telepathy-glib/core-svc-interface.h> +#include <telepathy-glib/defs.h> + +G_BEGIN_DECLS + +typedef struct _TpSvcInterfaceSkeleton TpSvcInterfaceSkeleton; +typedef struct _TpSvcInterfaceSkeletonClass TpSvcInterfaceSkeletonClass; +typedef struct _TpSvcInterfaceSkeletonPrivate TpSvcInterfaceSkeletonPrivate; + +GType _tp_svc_interface_skeleton_get_type (void); + +#define TP_TYPE_SVC_INTERFACE_SKELETON \ + (_tp_svc_interface_skeleton_get_type ()) +#define TP_SVC_INTERFACE_SKELETON(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), TP_TYPE_SVC_INTERFACE_SKELETON, \ + TpSvcInterfaceSkeleton)) +#define TP_SVC_INTERFACE_SKELETON_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), TP_TYPE_SVC_INTERFACE_SKELETON, \ + TpSvcInterfaceSkeletonClass)) +#define TP_IS_SVC_INTERFACE_SKELETON(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TP_TYPE_SVC_INTERFACE_SKELETON)) +#define TP_IS_SVC_INTERFACE_SKELETON_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), TP_TYPE_SVC_INTERFACE_SKELETON)) +#define TP_SVC_INTERFACE_SKELETON_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), TP_TYPE_SVC_INTERFACE_SKELETON, \ + TpSvcInterfaceSkeletonClass)) + +struct _TpSvcInterfaceSkeletonClass +{ + /*< private >*/ + GDBusInterfaceSkeletonClass parent_class; +}; + +struct _TpSvcInterfaceSkeleton +{ + /*< private >*/ + GDBusInterfaceSkeleton parent; + TpSvcInterfaceSkeletonPrivate *priv; +}; + +TpSvcInterfaceSkeleton *_tp_svc_interface_skeleton_new (gpointer object, + GType iface, + const TpSvcInterfaceInfo *iinfo); + +G_END_DECLS + +#endif diff --git a/telepathy-glib/svc-interface-skeleton.c b/telepathy-glib/svc-interface-skeleton.c new file mode 100644 index 000000000..547a360f6 --- /dev/null +++ b/telepathy-glib/svc-interface-skeleton.c @@ -0,0 +1,243 @@ +/* + * Copyright © 2014 Collabora Ltd. + * + * 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.1 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <config.h> +#include <telepathy-glib/svc-interface-skeleton-internal.h> + +#include <dbus/dbus-glib.h> + +#include <telepathy-glib/dbus-properties-mixin.h> +#include <telepathy-glib/variant-util.h> + +#define DEBUG_FLAG TP_DEBUG_SVC +#include "debug-internal.h" + +struct _TpSvcInterfaceSkeletonPrivate +{ + GWeakRef object; + TpSvcInterfaceInfo *iinfo; +}; + +G_DEFINE_TYPE (TpSvcInterfaceSkeleton, _tp_svc_interface_skeleton, + G_TYPE_DBUS_INTERFACE_SKELETON) + +static void +_tp_svc_interface_skeleton_init (TpSvcInterfaceSkeleton *self) +{ + self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, + TP_TYPE_SVC_INTERFACE_SKELETON, TpSvcInterfaceSkeletonPrivate); +} + +static void +tp_svc_interface_skeleton_dispose (GObject *obj) +{ + TpSvcInterfaceSkeleton *self = TP_SVC_INTERFACE_SKELETON (obj); + + /* not using g_weak_ref_clear() in order to be idempotent */ + g_weak_ref_set (&self->priv->object, NULL); + + G_OBJECT_CLASS (_tp_svc_interface_skeleton_parent_class)->dispose (obj); +} + +static GDBusInterfaceInfo * +tp_svc_interface_skeleton_get_info (GDBusInterfaceSkeleton *skel) +{ + TpSvcInterfaceSkeleton *self = TP_SVC_INTERFACE_SKELETON (skel); + + return self->priv->iinfo->interface_info; +} + +static void +tp_svc_interface_skeleton_method_call (GDBusConnection *connection, + const gchar *sender, + const gchar *object_path, + const gchar *interface_name, + const gchar *method_name, + GVariant *parameters, + GDBusMethodInvocation *invocation, + gpointer user_data) +{ + TpSvcInterfaceSkeleton *self = TP_SVC_INTERFACE_SKELETON (user_data); + GObject *object; + + DEBUG ("%s.%s on %s %p from %s", interface_name, method_name, object_path, + self, sender); + + object = g_weak_ref_get (&self->priv->object); + /* TpDBusDaemon is meant to unexport us automatically when the object + * goes away */ + g_return_if_fail (object != NULL); + + self->priv->iinfo->vtable->method_call (connection, + sender, object_path, interface_name, method_name, parameters, + invocation, object); + g_object_unref (object); +} + +static GDBusInterfaceVTable vtable = { + tp_svc_interface_skeleton_method_call, + NULL, + NULL +}; + +static GDBusInterfaceVTable * +tp_svc_interface_skeleton_get_vtable (GDBusInterfaceSkeleton *skel) +{ + return &vtable; +} + +static GVariant * +tp_svc_interface_skeleton_get_properties (GDBusInterfaceSkeleton *skel) +{ + TpSvcInterfaceSkeleton *self = TP_SVC_INTERFACE_SKELETON (skel); + GVariant *ret; + GHashTable *asv; + const gchar *iface_name = self->priv->iinfo->interface_info->name; + + /* For now assume we have the TpDBusPropertiesMixin if we have + * any properties at all. This never returns NULL. */ + asv = tp_dbus_properties_mixin_dup_all ((GObject *) self, iface_name); + + ret = g_variant_ref_sink (tp_asv_to_vardict (asv)); + g_hash_table_unref (asv); + return ret; +} + +static void +tp_svc_interface_skeleton_flush (GDBusInterfaceSkeleton *skel) +{ + /* stub: we emit any changes immediately, and we implement Properties + * elsewhere anyway */ +} + +static void +_tp_svc_interface_skeleton_class_init (TpSvcInterfaceSkeletonClass *cls) +{ + GObjectClass *obj_cls = G_OBJECT_CLASS (cls); + GDBusInterfaceSkeletonClass *skel_cls = G_DBUS_INTERFACE_SKELETON_CLASS (cls); + + g_type_class_add_private (cls, sizeof (TpSvcInterfaceSkeleton)); + + obj_cls->dispose = tp_svc_interface_skeleton_dispose; + + skel_cls->get_info = tp_svc_interface_skeleton_get_info; + skel_cls->get_vtable = tp_svc_interface_skeleton_get_vtable; + skel_cls->get_properties = tp_svc_interface_skeleton_get_properties; + skel_cls->flush = tp_svc_interface_skeleton_flush; +} + +typedef struct { + GClosure closure; + /* (transfer none) - the closure ensures we have a ref */ + TpSvcInterfaceSkeleton *self; + /* (transfer none) - borrowed from the interface info */ + const gchar *name; +} SignalClosure; + +static void +tp_svc_interface_skeleton_emit_signal (GClosure *closure, + GValue *return_value, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint, + gpointer marshal_data) +{ + SignalClosure *sc = (SignalClosure *) closure; + TpSvcInterfaceSkeleton *self = sc->self; + GDBusInterfaceSkeleton *skel = G_DBUS_INTERFACE_SKELETON (self); + const gchar *path = g_dbus_interface_skeleton_get_object_path (skel); + GVariantBuilder builder; + guint i; + + DEBUG ("%s.%s from %s %p", self->priv->iinfo->interface_info->name, + sc->name, path, self); + + g_variant_builder_init (&builder, G_VARIANT_TYPE_TUPLE); + + /* Skip parameter 0, which is the GObject. */ + for (i = 1; i < n_param_values; i++) + g_variant_builder_add_value (&builder, + dbus_g_value_build_g_variant (param_values + i)); + + /* we only support being exported on one connection */ + g_dbus_connection_emit_signal ( + g_dbus_interface_skeleton_get_connection (skel), + NULL, /* broadcast */ + g_dbus_interface_skeleton_get_object_path (skel), + self->priv->iinfo->interface_info->name, + sc->name, + /* consume floating ref */ + g_variant_builder_end (&builder), + /* cannot fail unless a parameter is incompatible with D-Bus, + * so ignore error */ + NULL); +} + +/* + * _tp_svc_interface_skeleton_new: (skip) + * @object: (type GObject.Object): a #GObject + * @iface: a `TpSvc` interface on the object + * @iinfo: a description of the corresponding D-Bus interface + * + * Returns: (transfer full): a new interface skeleton wrapping @iface + * on @object + */ +TpSvcInterfaceSkeleton * +_tp_svc_interface_skeleton_new (gpointer object, + GType iface, + const TpSvcInterfaceInfo *iinfo) +{ + TpSvcInterfaceSkeleton *self; + + /* not bothering to refcount it, it must be static for now */ + g_return_val_if_fail (iinfo->ref_count == -1, NULL); + + self = g_object_new (TP_TYPE_SVC_INTERFACE_SKELETON, + NULL); + g_weak_ref_init (&self->priv->object, object); + self->priv->iinfo = (TpSvcInterfaceInfo *) iinfo; + + if (iinfo->signals != NULL) + { + guint i; + + for (i = 0; iinfo->signals[i] != NULL; i++) + { + const gchar *glib_name; + const gchar *dbus_name; + SignalClosure *closure; + + g_assert (iinfo->interface_info->signals[i] != NULL); + + glib_name = iinfo->signals[i]; + dbus_name = iinfo->interface_info->signals[i]->name; + + closure = (SignalClosure *) g_closure_new_object (sizeof (*closure), + (GObject *) self); + g_closure_set_marshal ((GClosure *) closure, + tp_svc_interface_skeleton_emit_signal); + closure->self = self; + closure->name = dbus_name; + + g_signal_connect_closure (object, glib_name, (GClosure *) closure, + FALSE); + } + } + + return self; +} diff --git a/telepathy-glib/telepathy-glib.h b/telepathy-glib/telepathy-glib.h index 4d099ba55..ab853639b 100644 --- a/telepathy-glib/telepathy-glib.h +++ b/telepathy-glib/telepathy-glib.h @@ -66,6 +66,7 @@ #include <telepathy-glib/channel.h> #include <telepathy-glib/client.h> #include <telepathy-glib/client-message.h> +#include <telepathy-glib/core-svc-interface.h> #include <telepathy-glib/cm-message.h> #include <telepathy-glib/connection-contact-list.h> #include <telepathy-glib/connection-manager.h> |