[glib/gdbus-codegen] gdbus-codegen: Generate GDBusObject{, Proxy, Skeleton} subtypes



commit bbe945183be11dafc037fdf5f92cea49202b6401
Author: David Zeuthen <davidz redhat com>
Date:   Mon Apr 25 09:29:18 2011 -0400

    gdbus-codegen: Generate GDBusObject{,Proxy,Skeleton} subtypes
    
    Signed-off-by: David Zeuthen <davidz redhat com>

 docs/reference/gio/gdbus-codegen.xml           |    6 +-
 docs/reference/gio/gio-sections.txt            |   42 ++
 docs/reference/gio/gio.types                   |    3 +
 docs/reference/gio/migrating-gdbus.xml         |    5 +-
 gio/gdbus-codegen/codegen.py                   |  582 +++++++++++++++++++++---
 gio/gdbus-codegen/dbustypes.py                 |    2 +
 gio/gdbusobject.c                              |   57 ---
 gio/gdbusobject.h                              |   17 -
 gio/gdbusobjectmanagerclient.c                 |   18 +-
 gio/gdbusobjectproxy.c                         |   75 +--
 gio/gdbusobjectproxy.h                         |    6 +-
 gio/gdbusobjectskeleton.c                      |   31 --
 gio/gdbusprivate.h                             |    2 -
 gio/gio.symbols                                |    3 +-
 gio/giotypes.h                                 |    8 +-
 gio/tests/gdbus-example-objectmanager-client.c |    6 +-
 gio/tests/gdbus-example-objectmanager-server.c |   10 +-
 gio/tests/gdbus-test-codegen.c                 |  165 ++-----
 gio/tests/test-codegen.xml                     |    6 +
 19 files changed, 685 insertions(+), 359 deletions(-)
---
diff --git a/docs/reference/gio/gdbus-codegen.xml b/docs/reference/gio/gdbus-codegen.xml
index 6eca718..5f229d4 100644
--- a/docs/reference/gio/gdbus-codegen.xml
+++ b/docs/reference/gio/gdbus-codegen.xml
@@ -134,9 +134,9 @@
       <term><option>--c-generate-object-manager</option></term>
       <listitem>
         <para>
-          If this option is passed a #GDBusObjectManagerClient
-          subclass with an appropriate #GDBusProxyTypeFunc is
-          generated.
+          If this option is passed, suitable #GDBusObject,
+          #GDBusObjectProxy, #GDBusObjectSkeleton and
+          #GDBusObjectManagerClient subclasses are generated.
         </para>
       </listitem>
     </varlistentry>
diff --git a/docs/reference/gio/gio-sections.txt b/docs/reference/gio/gio-sections.txt
index 0d733a1..690b45a 100644
--- a/docs/reference/gio/gio-sections.txt
+++ b/docs/reference/gio/gio-sections.txt
@@ -3195,6 +3195,7 @@ G_DBUS_OBJECT_GET_IFACE
 <TITLE>GDBusObjectProxy</TITLE>
 GDBusObjectProxy
 GDBusObjectProxyClass
+g_dbus_object_proxy_new
 g_dbus_object_proxy_get_connection
 <SUBSECTION Standard>
 G_DBUS_OBJECT_PROXY
@@ -3396,6 +3397,47 @@ EXAMPLE_IS_CAT_SKELETON_CLASS
 </SECTION>
 
 <SECTION>
+<FILE>ExampleObject</FILE>
+<TITLE>ExampleObject</TITLE>
+ExampleObject
+ExampleObjectIface
+example_object_get_animal
+example_object_get_cat
+example_object_peek_animal
+example_object_peek_cat
+ExampleObjectProxy
+ExampleObjectProxyClass
+example_object_proxy_new
+ExampleObjectSkeleton
+ExampleObjectSkeletonClass
+example_object_skeleton_new
+example_object_skeleton_set_animal
+example_object_skeleton_set_cat
+<SUBSECTION Standard>
+example_object_get_type
+example_object_proxy_get_type
+example_object_skeleton_get_type
+ExampleObjectProxyPrivate
+ExampleObjectSkeletonPrivate
+EXAMPLE_IS_OBJECT
+EXAMPLE_IS_OBJECT_PROXY
+EXAMPLE_IS_OBJECT_PROXY_CLASS
+EXAMPLE_IS_OBJECT_SKELETON
+EXAMPLE_IS_OBJECT_SKELETON_CLASS
+EXAMPLE_OBJECT
+EXAMPLE_OBJECT_GET_IFACE
+EXAMPLE_OBJECT_PROXY
+EXAMPLE_OBJECT_PROXY_CLASS
+EXAMPLE_OBJECT_PROXY_GET_CLASS
+EXAMPLE_OBJECT_SKELETON
+EXAMPLE_OBJECT_SKELETON_CLASS
+EXAMPLE_OBJECT_SKELETON_GET_CLASS
+EXAMPLE_TYPE_OBJECT
+EXAMPLE_TYPE_OBJECT_PROXY
+EXAMPLE_TYPE_OBJECT_SKELETON
+</SECTION>
+
+<SECTION>
 <FILE>ExampleObjectManagerClient</FILE>
 <TITLE>ExampleObjectManagerClient</TITLE>
 ExampleObjectManagerClient
diff --git a/docs/reference/gio/gio.types b/docs/reference/gio/gio.types
index b40f683..4938012 100644
--- a/docs/reference/gio/gio.types
+++ b/docs/reference/gio/gio.types
@@ -1,3 +1,6 @@
+example_object_get_type
+example_object_proxy_get_type
+example_object_skeleton_get_type
 example_animal_get_type
 example_animal_proxy_get_type
 example_animal_skeleton_get_type
diff --git a/docs/reference/gio/migrating-gdbus.xml b/docs/reference/gio/migrating-gdbus.xml
index 5d82eaa..8977b74 100644
--- a/docs/reference/gio/migrating-gdbus.xml
+++ b/docs/reference/gio/migrating-gdbus.xml
@@ -280,8 +280,8 @@ gdbus-codegen --interface-prefix org.gtk.GDBus.Example.ObjectManager. \
       and <xref
       linkend="gdbus-example-codegen-client"/>. Additionally, since
       the generated code has 100% gtk-doc coverage, see
-      #ExampleAnimal, #ExampleCat and #ExampleObjectManagerClient
-      pages for documentation
+      #ExampleAnimal, #ExampleCat, #ExampleObject and
+      #ExampleObjectManagerClient pages for documentation.
     </para>
 
     <example id="gdbus-example-codegen-server"><title>Server-side application using generated code</title><programlisting><xi:include xmlns:xi="http://www.w3.org/2001/XInclude"; parse="text" href="../../../../gio/tests/gdbus-example-objectmanager-server.c"><xi:fallback>FIXME: MISSING XINCLUDE CONTENT</xi:fallback></xi:include></programlisting></example>
@@ -294,6 +294,7 @@ gdbus-codegen --interface-prefix org.gtk.GDBus.Example.ObjectManager. \
   <xi:include href="../../../../gio/gdbus-example-objectmanager-generated-org.gtk.GDBus.Example.ObjectManager.Cat.xml"/>
   <xi:include href="ExampleAnimal.xml"/>
   <xi:include href="ExampleCat.xml"/>
+  <xi:include href="ExampleObject.xml"/>
   <xi:include href="ExampleObjectManagerClient.xml"/>
 
 </chapter>
diff --git a/gio/gdbus-codegen/codegen.py b/gio/gdbus-codegen/codegen.py
index 8ae519f..d60c632 100644
--- a/gio/gdbus-codegen/codegen.py
+++ b/gio/gdbus-codegen/codegen.py
@@ -95,6 +95,13 @@ class CodeGenerator:
 
         self.c.write('typedef struct\n'
                      '{\n'
+                     '  GDBusInterfaceInfo parent_struct;\n'
+                     '  const gchar *hyphen_name;\n'
+                     '} _ExtendedGDBusInterfaceInfo;\n'
+                     '\n')
+
+        self.c.write('typedef struct\n'
+                     '{\n'
                      '  const _ExtendedGDBusPropertyInfo *info;\n'
                      '  guint prop_id;\n'
                      '  GValue orig_value; /* the value before the change */\n'
@@ -455,41 +462,6 @@ class CodeGenerator:
                          %(i.camel_name, i.name_lower))
             self.h.write('\n')
 
-            # Interface proxy accessors
-            self.h.write(self.docbook_gen.expand(
-                    '/**\n'
-                    ' * %sGET_%s:\n'
-                    ' * @object: A #GDBusObject.\n'
-                    ' *\n'
-                    ' * Gets the #%s instance corresponding to the D-Bus interface #%s, if any.\n'
-                    ' *\n'
-                    ' * This macro can be used on both the client-side (passing a #GDBusObjectProxy) or the service-side (passing a #GDBusObjectSkeleton).\n'
-                    ' *\n'
-                    ' * This macro is just C convenience - other languages will use g_dbus_object_get_interface() to achieve the same result.\n'
-                    ' *\n'
-                    ' * Returns: (transfer full): A #%s or %%NULL if @object does not have said interface. Free with g_object_unref().\n'
-                    %(i.ns_upper, i.name_upper, i.camel_name, i.name, i.camel_name)))
-            self.write_gtkdoc_deprecated_and_since_and_close(i, self.h, 0)
-            self.h.write('#define %sGET_%s(object) (g_dbus_object_lookup_with_typecheck (G_DBUS_OBJECT (object), "%s", %sTYPE_%s))\n'%(i.ns_upper, i.name_upper, i.name, i.ns_upper, i.name_upper))
-            self.h.write(self.docbook_gen.expand(
-                    '/**\n'
-                    ' * %sPEEK_%s:\n'
-                    ' * @object: A #GDBusObject.\n'
-                    ' *\n'
-                    ' * Like the %sGET_%s() macro but doesn\'t increase the reference count on the returned object.\n'
-                    ' *\n'
-                    ' * This macro can be used on both the client-side (passing a #GDBusObjectProxy) or the service-side (passing a #GDBusObjectSkeleton).\n'
-                    ' *\n'
-                    ' * This macro is just C convenience - other languages will use g_dbus_object_get_interface() to achieve the same result..\n'
-                    ' *\n'
-                    ' * <warning>It is not safe to use the returned object if you are on another thread than where the #GDBusObjectManagerClient is running</warning>\n'
-                    ' *\n'
-                    ' * Returns: (transfer none): A #%s or %%NULL if @object does not have said interface. Do not free the returned object, it belongs to @object.\n'
-                    %(i.ns_upper, i.name_upper, i.ns_upper, i.name_upper, i.camel_name)))
-            self.write_gtkdoc_deprecated_and_since_and_close(i, self.h, 0)
-            self.h.write('#define %sPEEK_%s(object) (g_dbus_object_peek_with_typecheck (G_DBUS_OBJECT (object), "%s", %sTYPE_%s))\n'%(i.ns_upper, i.name_upper, i.name, i.ns_upper, i.name_upper))
-            self.h.write('\n')
-
             # Then the skeleton
             self.h.write('\n')
             self.h.write('/* ---- */\n')
@@ -524,11 +496,98 @@ class CodeGenerator:
 
             self.h.write('\n')
 
-        # Finally, the proxy manager
+        # Finally, the Object, ObjectProxy, ObjectSkeleton and ObjectManagerClient
         if self.generate_objmanager:
             self.h.write('\n')
             self.h.write('/* ---- */\n')
             self.h.write('\n')
+            self.h.write('#define %sTYPE_OBJECT (%sobject_get_type ())\n'%(self.ns_upper, self.ns_lower))
+            self.h.write('#define %sOBJECT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), %sTYPE_OBJECT, %sObject))\n'%(self.ns_upper, self.ns_upper, self.namespace))
+            self.h.write('#define %sIS_OBJECT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), %sTYPE_OBJECT))\n'%(self.ns_upper, self.ns_upper))
+            self.h.write('#define %sOBJECT_GET_IFACE(o) (G_TYPE_INSTANCE_GET_INTERFACE ((o), %sTYPE_OBJECT, %sObject))\n'%(self.ns_upper, self.ns_upper, self.namespace))
+            self.h.write('\n')
+            self.h.write('struct _%sObject;\n'%(self.namespace))
+            self.h.write('typedef struct _%sObject %sObject;\n'%(self.namespace, self.namespace))
+            self.h.write('typedef struct _%sObjectIface %sObjectIface;\n'%(self.namespace, self.namespace))
+            self.h.write('\n')
+            self.h.write('struct _%sObjectIface\n'%(self.namespace))
+            self.h.write('{\n'
+                         '  GTypeInterface parent_iface;\n'
+                         '};\n'
+                         '\n')
+            self.h.write('GType %sobject_get_type (void) G_GNUC_CONST;\n'
+                         '\n'
+                         %(self.ns_lower))
+            for i in self.ifaces:
+                if i.deprecated:
+                    self.h.write('G_GNUC_DEPRECATED ')
+                self.h.write ('%s *%sobject_get_%s (%sObject *object);\n'
+                              %(i.camel_name, self.ns_lower, i.name_upper.lower(), self.namespace))
+            for i in self.ifaces:
+                if i.deprecated:
+                    self.h.write('G_GNUC_DEPRECATED ')
+                self.h.write ('%s *%sobject_peek_%s (%sObject *object);\n'
+                              %(i.camel_name, self.ns_lower, i.name_upper.lower(), self.namespace))
+            self.h.write('\n')
+            self.h.write('#define %sTYPE_OBJECT_PROXY (%sobject_proxy_get_type ())\n'%(self.ns_upper, self.ns_lower))
+            self.h.write('#define %sOBJECT_PROXY(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), %sTYPE_OBJECT_PROXY, %sObjectProxy))\n'%(self.ns_upper, self.ns_upper, self.namespace))
+            self.h.write('#define %sOBJECT_PROXY_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), %sTYPE_OBJECT_PROXY, %sObjectProxyClass))\n'%(self.ns_upper, self.ns_upper, self.namespace))
+            self.h.write('#define %sOBJECT_PROXY_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), %sTYPE_OBJECT_PROXY, %sObjectProxyClass))\n'%(self.ns_upper, self.ns_upper, self.namespace))
+            self.h.write('#define %sIS_OBJECT_PROXY(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), %sTYPE_OBJECT_PROXY))\n'%(self.ns_upper, self.ns_upper))
+            self.h.write('#define %sIS_OBJECT_PROXY_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), %sTYPE_OBJECT_PROXY))\n'%(self.ns_upper, self.ns_upper))
+            self.h.write('\n')
+            self.h.write('typedef struct _%sObjectProxy %sObjectProxy;\n'%(self.namespace, self.namespace))
+            self.h.write('typedef struct _%sObjectProxyClass %sObjectProxyClass;\n'%(self.namespace, self.namespace))
+            self.h.write('typedef struct _%sObjectProxyPrivate %sObjectProxyPrivate;\n'%(self.namespace, self.namespace))
+            self.h.write('\n')
+            self.h.write('struct _%sObjectProxy\n'%(self.namespace))
+            self.h.write('{\n')
+            self.h.write('  GDBusObjectProxy parent_instance;\n')
+            self.h.write('  %sObjectProxyPrivate *priv;\n'%(self.namespace))
+            self.h.write('};\n')
+            self.h.write('\n')
+            self.h.write('struct _%sObjectProxyClass\n'%(self.namespace))
+            self.h.write('{\n')
+            self.h.write('  GDBusObjectProxyClass parent_class;\n')
+            self.h.write('};\n')
+            self.h.write('\n')
+            self.h.write('GType %sobject_proxy_get_type (void) G_GNUC_CONST;\n'%(self.ns_lower))
+            self.h.write('%sObjectProxy *%sobject_proxy_new (GDBusConnection *connection, const gchar *object_path);\n'%(self.namespace, self.ns_lower))
+            self.h.write('\n')
+            self.h.write('#define %sTYPE_OBJECT_SKELETON (%sobject_skeleton_get_type ())\n'%(self.ns_upper, self.ns_lower))
+            self.h.write('#define %sOBJECT_SKELETON(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), %sTYPE_OBJECT_SKELETON, %sObjectSkeleton))\n'%(self.ns_upper, self.ns_upper, self.namespace))
+            self.h.write('#define %sOBJECT_SKELETON_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), %sTYPE_OBJECT_SKELETON, %sObjectSkeletonClass))\n'%(self.ns_upper, self.ns_upper, self.namespace))
+            self.h.write('#define %sOBJECT_SKELETON_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), %sTYPE_OBJECT_SKELETON, %sObjectSkeletonClass))\n'%(self.ns_upper, self.ns_upper, self.namespace))
+            self.h.write('#define %sIS_OBJECT_SKELETON(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), %sTYPE_OBJECT_SKELETON))\n'%(self.ns_upper, self.ns_upper))
+            self.h.write('#define %sIS_OBJECT_SKELETON_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), %sTYPE_OBJECT_SKELETON))\n'%(self.ns_upper, self.ns_upper))
+            self.h.write('\n')
+            self.h.write('typedef struct _%sObjectSkeleton %sObjectSkeleton;\n'%(self.namespace, self.namespace))
+            self.h.write('typedef struct _%sObjectSkeletonClass %sObjectSkeletonClass;\n'%(self.namespace, self.namespace))
+            self.h.write('typedef struct _%sObjectSkeletonPrivate %sObjectSkeletonPrivate;\n'%(self.namespace, self.namespace))
+            self.h.write('\n')
+            self.h.write('struct _%sObjectSkeleton\n'%(self.namespace))
+            self.h.write('{\n')
+            self.h.write('  GDBusObjectSkeleton parent_instance;\n')
+            self.h.write('  %sObjectSkeletonPrivate *priv;\n'%(self.namespace))
+            self.h.write('};\n')
+            self.h.write('\n')
+            self.h.write('struct _%sObjectSkeletonClass\n'%(self.namespace))
+            self.h.write('{\n')
+            self.h.write('  GDBusObjectSkeletonClass parent_class;\n')
+            self.h.write('};\n')
+            self.h.write('\n')
+            self.h.write('GType %sobject_skeleton_get_type (void) G_GNUC_CONST;\n'%(self.ns_lower))
+            self.h.write('%sObjectSkeleton *%sobject_skeleton_new (const gchar *object_path);\n'
+                         %(self.namespace, self.ns_lower))
+            for i in self.ifaces:
+                if i.deprecated:
+                    self.h.write('G_GNUC_DEPRECATED ')
+                self.h.write ('void %sobject_skeleton_set_%s (%sObjectSkeleton *object, %s *interface_);\n'
+                              %(self.ns_lower, i.name_upper.lower(), self.namespace, i.camel_name))
+            self.h.write('\n')
+
+            self.h.write('/* ---- */\n')
+            self.h.write('\n')
             self.h.write('#define %sTYPE_OBJECT_MANAGER_CLIENT (%sobject_manager_client_get_type ())\n'%(self.ns_upper, self.ns_lower))
             self.h.write('#define %sOBJECT_MANAGER_CLIENT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), %sTYPE_OBJECT_MANAGER_CLIENT, %sObjectManagerClient))\n'%(self.ns_upper, self.ns_upper, self.namespace))
             self.h.write('#define %sOBJECT_MANAGER_CLIENT_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), %sTYPE_OBJECT_MANAGER_CLIENT, %sObjectManagerClientClass))\n'%(self.ns_upper, self.ns_upper, self.namespace))
@@ -799,28 +858,32 @@ class CodeGenerator:
                              '\n')
 
             num_anno = self.generate_annotations('_%s_annotation_info'%(i.name_lower), i.annotations)
-            self.c.write('static const GDBusInterfaceInfo _%s_interface_info =\n'
+            self.c.write('static const _ExtendedGDBusInterfaceInfo _%s_interface_info =\n'
                          '{\n'
-                         '  -1,\n'
-                         '  "%s",\n'%(i.name_lower, i.name))
+                         '  {\n'
+                         '    -1,\n'
+                         '    "%s",\n'%(i.name_lower, i.name))
             if len(i.methods) == 0:
-                self.c.write('  NULL,\n')
+                self.c.write('    NULL,\n')
             else:
-                self.c.write('  (GDBusMethodInfo **) &_%s_method_info_pointers,\n'%(i.name_lower))
+                self.c.write('    (GDBusMethodInfo **) &_%s_method_info_pointers,\n'%(i.name_lower))
             if len(i.signals) == 0:
-                self.c.write('  NULL,\n')
+                self.c.write('    NULL,\n')
             else:
-                self.c.write('  (GDBusSignalInfo **) &_%s_signal_info_pointers,\n'%(i.name_lower))
+                self.c.write('    (GDBusSignalInfo **) &_%s_signal_info_pointers,\n'%(i.name_lower))
             if len(i.properties) == 0:
-                self.c.write('  NULL,\n')
+                self.c.write('    NULL,\n')
             else:
-                self.c.write('  (GDBusPropertyInfo **) &_%s_property_info_pointers,\n'%(i.name_lower))
+                self.c.write('    (GDBusPropertyInfo **) &_%s_property_info_pointers,\n'%(i.name_lower))
             if num_anno == 0:
-                self.c.write('  NULL\n')
+                self.c.write('    NULL\n')
             else:
-                self.c.write('  (GDBusAnnotationInfo **) &_%s_annotation_info_pointers\n'%(i.name_lower))
-            self.c.write('};\n'
-                         '\n')
+                self.c.write('    (GDBusAnnotationInfo **) &_%s_annotation_info_pointers\n'%(i.name_lower))
+            self.c.write('  },\n'
+                         '  "%s",\n'
+                         '};\n'
+                         '\n'
+                         %(i.name_hyphen))
             self.c.write('\n')
             self.c.write(self.docbook_gen.expand(
                     '/**\n'
@@ -1945,11 +2008,11 @@ class CodeGenerator:
                      '  GVariantBuilder builder;\n'
                      '  guint n;\n'
                      '  g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));\n'
-                     '  if (_%s_interface_info.properties == NULL)\n'
+                     '  if (_%s_interface_info.parent_struct.properties == NULL)\n'
                      '    goto out;\n'
-                     '  for (n = 0; _%s_interface_info.properties[n] != NULL; n++)\n'
+                     '  for (n = 0; _%s_interface_info.parent_struct.properties[n] != NULL; n++)\n'
                      '    {\n'
-                     '      GDBusPropertyInfo *info = _%s_interface_info.properties[n];\n'
+                     '      GDBusPropertyInfo *info = _%s_interface_info.parent_struct.properties[n];\n'
                      '      if (info->flags & G_DBUS_PROPERTY_INFO_FLAGS_READABLE)\n'
                      '        {\n'
                      '          GVariant *value;\n'
@@ -2241,6 +2304,405 @@ class CodeGenerator:
 
     # ---------------------------------------------------------------------------------------------------
 
+    def generate_object(self):
+        self.c.write('/* ------------------------------------------------------------------------\n'
+                     ' * Code for Object, ObjectProxy and ObjectSkeleton\n'
+                     ' * ------------------------------------------------------------------------\n'
+                     ' */\n'
+                     '\n')
+
+        self.c.write(self.docbook_gen.expand(
+                '/**\n'
+                ' * SECTION:%sObject\n'
+                ' * @title: %sObject\n'
+                ' * @short_description: Specialized GDBusObject types\n'
+                ' *\n'
+                ' * This section contains the #%sObject, #%sObjectProxy, and #%sObjectSkeleton types which make it easier to work with objects implementing generated types for D-Bus interfaces.\n'
+                ' */\n'
+                %(self.namespace, self.namespace, self.namespace, self.namespace, self.namespace)))
+        self.c.write('\n')
+
+        self.c.write(self.docbook_gen.expand(
+                '/**\n'
+                ' * %sObject:\n'
+                ' *\n'
+                ' * The #%sObject type is a specialized container of interfaces.\n'
+                ' */\n'
+                %(self.namespace, self.namespace)))
+        self.c.write('\n')
+
+        self.c.write(self.docbook_gen.expand(
+                '/**\n'
+                ' * %sObjectIface:\n'
+                ' * @parent_iface: The parent interface.\n'
+                ' *\n'
+                ' * Virtual table for the #%sObject interface.\n'
+                ' */\n'
+                %(self.namespace, self.namespace)))
+        self.c.write('\n')
+
+        self.c.write('static void\n'
+                     '%sobject_default_init (%sObjectIface *iface)\n'
+                     '{\n'
+                     %(self.ns_lower, self.namespace));
+        for i in self.ifaces:
+            self.c.write(self.docbook_gen.expand(
+                    '  /**\n'
+                    '   * %sObject:%s:\n'
+                    '   *\n'
+                    '   * The #%s instance corresponding to the D-Bus interface #%s, if any.\n'
+                    '   *\n'
+                    '   * Connect to the #GObject::notify signal to get informed of property changes.\n'
+                    %(self.namespace, i.name_hyphen, i.camel_name, i.name)))
+            self.write_gtkdoc_deprecated_and_since_and_close(i, self.c, 2)
+            self.c.write('  g_object_interface_install_property (iface, g_param_spec_object ("%s", "%s", "%s", %sTYPE_%s, G_PARAM_READWRITE|G_PARAM_STATIC_STRINGS));\n'
+                         '\n'
+                         %(i.name_hyphen, i.name_hyphen, i.name_hyphen, self.ns_upper, i.name_upper))
+        self.c.write('}\n'
+                     '\n')
+
+        self.c.write('typedef %sObjectIface %sObjectInterface;\n'%(self.namespace, self.namespace))
+        self.c.write('G_DEFINE_INTERFACE_WITH_CODE (%sObject, %sobject, G_TYPE_OBJECT, g_type_interface_add_prerequisite (g_define_type_id, G_TYPE_DBUS_OBJECT));\n'%(self.namespace, self.ns_lower))
+        self.c.write('\n')
+
+        for i in self.ifaces:
+            self.c.write(self.docbook_gen.expand(
+                    '/**\n'
+                    ' * %sobject_get_%s:\n'
+                    ' * @object: A #%sObject.\n'
+                    ' *\n'
+                    ' * Gets the #%s instance for the D-Bus interface #%s on @object, if any.\n'
+                    ' *\n'
+                    ' * Returns: (transfer full): A #%s that must be freed with g_object_unref() or %%NULL if @object does not implement the interface.\n'
+                    %(self.ns_lower, i.name_upper.lower(), i.camel_name, i.camel_name, i.name, i.camel_name)))
+            self.write_gtkdoc_deprecated_and_since_and_close(i, self.c, 0)
+            self.c.write ('%s *%sobject_get_%s (%sObject *object)\n'
+                          %(i.camel_name, self.ns_lower, i.name_upper.lower(), self.namespace))
+            self.c.write('{\n'
+                         '  GDBusInterface *ret;\n'
+                         '  ret = g_dbus_object_get_interface (G_DBUS_OBJECT (object), "%s");\n'
+                         '  if (ret == NULL)\n'
+                         '    return NULL;\n'
+                         '  return %s%s (ret);\n'
+                         '}\n'
+                         '\n'
+                         %(i.name, self.ns_upper, i.name_upper))
+        self.c.write('\n')
+        for i in self.ifaces:
+            self.c.write(self.docbook_gen.expand(
+                    '/**\n'
+                    ' * %sobject_peek_%s: (skip)\n'
+                    ' * @object: A #%sObject.\n'
+                    ' *\n'
+                    ' * Like %sobject_get_%s() but doesn\' increase the reference count on the returned object.\n'
+                    ' *\n'
+                    ' * <warning>It is not safe to use the returned object if you are on another thread than the one where the #GDBusObjectManagerClient or #GDBusObjectManagerServer for @object is running.</warning>\n'
+                    ' *\n'
+                    ' * Returns: (transfer none): A #%s or %%NULL if @object does not implement the interface. Do not free the returned object, it is owned by @object.\n'
+                    %(self.ns_lower, i.name_upper.lower(), i.camel_name, self.ns_lower, i.name_upper.lower(), i.camel_name)))
+            self.write_gtkdoc_deprecated_and_since_and_close(i, self.c, 0)
+            self.c.write ('%s *%sobject_peek_%s (%sObject *object)\n'
+                          %(i.camel_name, self.ns_lower, i.name_upper.lower(), self.namespace))
+            self.c.write('{\n'
+                         '  GDBusInterface *ret;\n'
+                         '  ret = g_dbus_object_get_interface (G_DBUS_OBJECT (object), "%s");\n'
+                         '  if (ret == NULL)\n'
+                         '    return NULL;\n'
+                         '  g_object_unref (ret);\n'
+                         '  return %s%s (ret);\n'
+                         '}\n'
+                         '\n'
+                         %(i.name, self.ns_upper, i.name_upper))
+        self.c.write('\n')
+        # shared by ObjectProxy and ObjectSkeleton classes
+        self.c.write('static void\n'
+                     '%sobject_notify (GDBusObject *object, GDBusInterface *interface)\n'
+                     '{\n'
+                     '  g_object_notify (G_OBJECT (object), ((_ExtendedGDBusInterfaceInfo *) g_dbus_interface_get_info (interface))->hyphen_name);\n'
+                     '}\n'
+                     '\n'
+                     %(self.ns_lower))
+
+        self.c.write(self.docbook_gen.expand(
+                '/**\n'
+                ' * %sObjectProxy:\n'
+                ' *\n'
+                ' * The #%sObjectProxy structure contains only private data and should only be accessed using the provided API.\n'
+                %(self.namespace, self.namespace)))
+        self.c.write(' */\n')
+        self.c.write('\n')
+        self.c.write(self.docbook_gen.expand(
+                '/**\n'
+                ' * %sObjectProxyClass:\n'
+                ' * @parent_class: The parent class.\n'
+                ' *\n'
+                ' * Class structure for #%sObjectProxy.\n'
+                %(self.namespace, self.namespace)))
+        self.c.write(' */\n')
+        self.c.write('\n')
+        # class boilerplate
+        self.c.write('static void\n'
+                     '%sobject_proxy__%sobject_iface_init (%sObjectIface *iface)\n'
+                     '{\n'
+                     '}\n'
+                     '\n'
+                     %(self.ns_lower, self.ns_lower, self.namespace))
+        self.c.write('static void\n'
+                     '%sobject_proxy__g_dbus_object_iface_init (GDBusObjectIface *iface)\n'
+                     '{\n'
+                     '  iface->interface_added = %sobject_notify;\n'
+                     '  iface->interface_removed = %sobject_notify;\n'
+                     '}\n'
+                     '\n'
+                     %(self.ns_lower, self.ns_lower, self.ns_lower))
+        self.c.write('\n')
+        self.c.write('G_DEFINE_TYPE_WITH_CODE (%sObjectProxy, %sobject_proxy, G_TYPE_DBUS_OBJECT_PROXY,\n'
+                     '                         G_IMPLEMENT_INTERFACE (%sTYPE_OBJECT, %sobject_proxy__%sobject_iface_init)\n'
+                     '                         G_IMPLEMENT_INTERFACE (G_TYPE_DBUS_OBJECT, %sobject_proxy__g_dbus_object_iface_init));\n'
+                     '\n'
+                     %(self.namespace, self.ns_lower, self.ns_upper, self.ns_lower, self.ns_lower, self.ns_lower))
+        # class boilerplate
+        self.c.write('static void\n'
+                     '%sobject_proxy_init (%sObjectProxy *object)\n'
+                     '{\n'
+                     '}\n'
+                     '\n'%(self.ns_lower, self.namespace))
+        self.c.write('static void\n'
+                     '%sobject_proxy_set_property (GObject      *_object,\n'
+                     '  guint         prop_id,\n'
+                     '  const GValue *value,\n'
+                     '  GParamSpec   *pspec)\n'
+                     '{\n'
+                     '  G_OBJECT_WARN_INVALID_PROPERTY_ID (_object, prop_id, pspec);\n'
+                     %(self.ns_lower))
+        self.c.write('}\n'
+                     '\n'%())
+        self.c.write('static void\n'
+                     '%sobject_proxy_get_property (GObject      *_object,\n'
+                     '  guint         prop_id,\n'
+                     '  GValue       *value,\n'
+                     '  GParamSpec   *pspec)\n'
+                     '{\n'
+                     '  %sObjectProxy *object = %sOBJECT_PROXY (_object);\n'
+                     '  GDBusInterface *interface;\n'
+                     '\n'
+                     '  switch (prop_id)\n'
+                     '    {\n'
+                     %(self.ns_lower, self.namespace, self.ns_upper))
+        n = 1
+        for i in self.ifaces:
+            self.c.write('    case %d:\n'
+                         '      interface = g_dbus_object_get_interface (G_DBUS_OBJECT (object), "%s");\n'
+                         '      g_value_take_object (value, interface);\n'
+                         '      break;\n'
+                         '\n'
+                         %(n, i.name))
+            n += 1
+        self.c.write('    default:\n'
+                     '      G_OBJECT_WARN_INVALID_PROPERTY_ID (_object, prop_id, pspec);\n'
+                     '      break;\n'
+                     '  }\n'
+                     '}\n'
+                     '\n'%())
+        self.c.write('static void\n'
+                     '%sobject_proxy_class_init (%sObjectProxyClass *klass)\n'
+                     '{\n'
+                     '  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);\n'
+                     '\n'
+                     '  gobject_class->set_property = %sobject_proxy_set_property;\n'
+                     '  gobject_class->get_property = %sobject_proxy_get_property;\n'
+                     '\n'
+                     %(self.ns_lower, self.namespace, self.ns_lower, self.ns_lower))
+        n = 1
+        for i in self.ifaces:
+            self.c.write('  g_object_class_override_property (gobject_class, %d, "%s");'
+                         '\n'
+                         %(n, i.name_hyphen))
+            n += 1
+        self.c.write('}\n'
+                     '\n')
+
+        self.c.write(self.docbook_gen.expand(
+                '/**\n'
+                ' * %sobject_proxy_new:\n'
+                ' * @connection: A #GDBusConnection.\n'
+                ' * @object_path: An object path.\n'
+                ' *\n'
+                ' * Creates a new proxy object.\n'
+                ' *\n'
+                ' * Returns: (transfer full): The proxy object.\n'
+                ' */\n'
+                %(self.ns_lower)))
+        self.c.write('%sObjectProxy *\n'
+                     '%sobject_proxy_new (GDBusConnection *connection,\n'
+                     '  const gchar *object_path)\n'
+                     '{\n'
+                     '  g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL);\n'
+                     '  g_return_val_if_fail (g_variant_is_object_path (object_path), NULL);\n'
+                     '  return %sOBJECT_PROXY (g_object_new (%sTYPE_OBJECT_PROXY, "connection", connection, "object-path", object_path, NULL));\n'
+                     '}\n'
+                     '\n'%(self.namespace, self.ns_lower, self.ns_upper, self.ns_upper))
+
+        self.c.write(self.docbook_gen.expand(
+                '/**\n'
+                ' * %sObjectSkeleton:\n'
+                ' *\n'
+                ' * The #%sObjectSkeleton structure contains only private data and should only be accessed using the provided API.\n'
+                %(self.namespace, self.namespace)))
+        self.c.write(' */\n')
+        self.c.write('\n')
+        self.c.write(self.docbook_gen.expand(
+                '/**\n'
+                ' * %sObjectSkeletonClass:\n'
+                ' * @parent_class: The parent class.\n'
+                ' *\n'
+                ' * Class structure for #%sObjectSkeleton.\n'
+                %(self.namespace, self.namespace)))
+        self.c.write(' */\n')
+        self.c.write('\n')
+        # class boilerplate
+        self.c.write('static void\n'
+                     '%sobject_skeleton__%sobject_iface_init (%sObjectIface *iface)\n'
+                     '{\n'
+                     '}\n'
+                     '\n'
+                     %(self.ns_lower, self.ns_lower, self.namespace))
+        self.c.write('\n')
+        self.c.write('static void\n'
+                     '%sobject_skeleton__g_dbus_object_iface_init (GDBusObjectIface *iface)\n'
+                     '{\n'
+                     '  iface->interface_added = %sobject_notify;\n'
+                     '  iface->interface_removed = %sobject_notify;\n'
+                     '}\n'
+                     '\n'
+                     %(self.ns_lower, self.ns_lower, self.ns_lower))
+        self.c.write('G_DEFINE_TYPE_WITH_CODE (%sObjectSkeleton, %sobject_skeleton, G_TYPE_DBUS_OBJECT_SKELETON,\n'
+                     '                         G_IMPLEMENT_INTERFACE (%sTYPE_OBJECT, %sobject_skeleton__%sobject_iface_init)\n'
+                     '                         G_IMPLEMENT_INTERFACE (G_TYPE_DBUS_OBJECT, %sobject_skeleton__g_dbus_object_iface_init));\n'
+                     '\n'
+                     %(self.namespace, self.ns_lower, self.ns_upper, self.ns_lower, self.ns_lower, self.ns_lower))
+        # class boilerplate
+        self.c.write('static void\n'
+                     '%sobject_skeleton_init (%sObjectSkeleton *object)\n'
+                     '{\n'
+                     '}\n'
+                     '\n'%(self.ns_lower, self.namespace))
+        self.c.write('static void\n'
+                     '%sobject_skeleton_set_property (GObject      *_object,\n'
+                     '  guint         prop_id,\n'
+                     '  const GValue *value,\n'
+                     '  GParamSpec   *pspec)\n'
+                     '{\n'
+                     '  %sObjectSkeleton *object = %sOBJECT_SKELETON (_object);\n'
+                     '  GDBusInterfaceSkeleton *interface;\n'
+                     '\n'
+                     '  switch (prop_id)\n'
+                     '    {\n'
+                     %(self.ns_lower, self.namespace, self.ns_upper))
+        n = 1
+        for i in self.ifaces:
+            self.c.write('    case %d:\n'
+                         '      interface = g_value_get_object (value);\n'
+                         '      if (interface != NULL)\n'
+                         '        {\n'
+                         '          g_warn_if_fail (%sIS_%s (interface));\n'
+                         '          g_dbus_object_skeleton_add_interface (G_DBUS_OBJECT_SKELETON (object), interface);\n'
+                         '        }\n'
+                         '      else\n'
+                         '        {\n'
+                         '          g_dbus_object_skeleton_remove_interface_by_name (G_DBUS_OBJECT_SKELETON (object), "%s");\n'
+                         '        }\n'
+                         '      break;\n'
+                         '\n'
+                         %(n, self.ns_upper, i.name_upper, i.name))
+            n += 1
+        self.c.write('    default:\n'
+                     '      G_OBJECT_WARN_INVALID_PROPERTY_ID (_object, prop_id, pspec);\n'
+                     '      break;\n'
+                     '  }\n'
+                     '}\n'
+                     '\n'%())
+        self.c.write('static void\n'
+                     '%sobject_skeleton_get_property (GObject      *_object,\n'
+                     '  guint         prop_id,\n'
+                     '  GValue       *value,\n'
+                     '  GParamSpec   *pspec)\n'
+                     '{\n'
+                     '  %sObjectSkeleton *object = %sOBJECT_SKELETON (_object);\n'
+                     '  GDBusInterface *interface;\n'
+                     '\n'
+                     '  switch (prop_id)\n'
+                     '    {\n'
+                     %(self.ns_lower, self.namespace, self.ns_upper))
+        n = 1
+        for i in self.ifaces:
+            self.c.write('    case %d:\n'
+                         '      interface = g_dbus_object_get_interface (G_DBUS_OBJECT (object), "%s");\n'
+                         '      g_value_take_object (value, interface);\n'
+                         '      break;\n'
+                         '\n'
+                         %(n, i.name))
+            n += 1
+        self.c.write('    default:\n'
+                     '      G_OBJECT_WARN_INVALID_PROPERTY_ID (_object, prop_id, pspec);\n'
+                     '      break;\n'
+                     '  }\n'
+                     '}\n'
+                     '\n'%())
+        self.c.write('static void\n'
+                     '%sobject_skeleton_class_init (%sObjectSkeletonClass *klass)\n'
+                     '{\n'
+                     '  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);\n'
+                     '\n'
+                     '  gobject_class->set_property = %sobject_skeleton_set_property;\n'
+                     '  gobject_class->get_property = %sobject_skeleton_get_property;\n'
+                     '\n'
+                     %(self.ns_lower, self.namespace, self.ns_lower, self.ns_lower))
+        n = 1
+        for i in self.ifaces:
+            self.c.write('  g_object_class_override_property (gobject_class, %d, "%s");'
+                         '\n'
+                         %(n, i.name_hyphen))
+            n += 1
+        self.c.write('}\n'
+                     '\n')
+        self.c.write(self.docbook_gen.expand(
+                '/**\n'
+                ' * %sobject_skeleton_new:\n'
+                ' * @object_path: An object path.\n'
+                ' *\n'
+                ' * Creates a new skeleton object.\n'
+                ' *\n'
+                ' * Returns: (transfer full): The skeleton object.\n'
+                ' */\n'
+                %(self.ns_lower)))
+        self.c.write('%sObjectSkeleton *\n'
+                     '%sobject_skeleton_new (const gchar *object_path)\n'
+                     '{\n'
+                     '  g_return_val_if_fail (g_variant_is_object_path (object_path), NULL);\n'
+                     '  return %sOBJECT_SKELETON (g_object_new (%sTYPE_OBJECT_SKELETON, "object-path", object_path, NULL));\n'
+                     '}\n'
+                     '\n'%(self.namespace, self.ns_lower, self.ns_upper, self.ns_upper))
+        for i in self.ifaces:
+            self.c.write(self.docbook_gen.expand(
+                    '/**\n'
+                    ' * %sobject_skeleton_set_%s:\n'
+                    ' * @object: A #%sObjectSkeleton.\n'
+                    ' * @interface_: (allow-none): A #%s or %%NULL to clear the interface.\n'
+                    ' *\n'
+                    ' * Sets the #%s instance for the D-Bus interface #%s on @object.\n'
+                    %(self.ns_lower, i.name_upper.lower(), self.namespace, i.camel_name, i.camel_name, i.name)))
+            self.write_gtkdoc_deprecated_and_since_and_close(i, self.c, 0)
+            self.c.write ('void %sobject_skeleton_set_%s (%sObjectSkeleton *object, %s *interface_)\n'
+                          %(self.ns_lower, i.name_upper.lower(), self.namespace, i.camel_name))
+            self.c.write('{\n'
+                         '  g_object_set (G_OBJECT (object), "%s", interface_, NULL);\n'
+                         '}\n'
+                         '\n'
+                         %(i.name_hyphen))
+        self.c.write('\n')
+
+
     def generate_object_manager_client(self):
         self.c.write('/* ------------------------------------------------------------------------\n'
                      ' * Code for ObjectManager client\n'
@@ -2252,7 +2714,7 @@ class CodeGenerator:
                 '/**\n'
                 ' * SECTION:%sObjectManagerClient\n'
                 ' * @title: %sObjectManagerClient\n'
-                ' * @short_description: Generated #GDBusObjectManagerClient subclass\n'
+                ' * @short_description: Generated GDBusObjectManagerClient type\n'
                 ' *\n'
                 ' * This section contains a #GDBusObjectManagerClient that uses %sobject_manager_client_get_proxy_type() as the #GDBusProxyTypeFunc.\n'
                 ' */\n'
@@ -2300,13 +2762,13 @@ class CodeGenerator:
                 ' * %sobject_manager_client_get_proxy_type:\n'
                 ' * @manager: A #GDBusObjectManagerClient.\n'
                 ' * @object_path: The object path of the remote object (unused).\n'
-                ' * @interface_name: Interface name of the remote object.\n'
+                ' * @interface_name: (allow-none): Interface name of the remote object or %%NULL to get the object proxy #GType.\n'
                 ' * @user_data: User data (unused).\n'
                 ' *\n'
-                ' * A #GDBusProxyTypeFunc that maps @interface_name to the generated #GDBusProxy<!-- -->-derived types.\n'
+                ' * A #GDBusProxyTypeFunc that maps @interface_name to the generated #GDBusObjectProxy<!-- -->- and #GDBusProxy<!-- -->-derived types.\n'
                 ' *\n'
-                ' * Returns: A #GDBusProxy<!-- -->-derived #GType.\n'
-                %(self.ns_lower)))
+                ' * Returns: A #GDBusProxy<!-- -->-derived #GType if @interface_name is not %%NULL, otherwise the #GType for #%sObjectProxy.\n'
+                %(self.ns_lower, self.namespace)))
         self.c.write(' */\n')
         self.c.write('GType\n'
                      '%sobject_manager_client_get_proxy_type (GDBusObjectManagerClient *manager, const gchar *object_path, const gchar *interface_name, gpointer user_data)\n'
@@ -2316,9 +2778,12 @@ class CodeGenerator:
                      '  static GHashTable *lookup_hash;\n'
                      '  GType ret;\n'
                      '\n'
+                     '  if (interface_name == NULL)\n'
+                     '    return %sTYPE_OBJECT_PROXY;\n'
                      '  if (g_once_init_enter (&once_init_value))\n'
                      '    {\n'
-                     '      lookup_hash = g_hash_table_new (g_str_hash, g_str_equal);\n')
+                     '      lookup_hash = g_hash_table_new (g_str_hash, g_str_equal);\n'
+                     %(self.ns_upper))
         for i in self.ifaces:
             self.c.write('      g_hash_table_insert (lookup_hash, "%s", GSIZE_TO_POINTER (%sTYPE_%s_PROXY));\n'
                          %(i.name, i.ns_upper, i.name_upper))
@@ -2587,5 +3052,6 @@ class CodeGenerator:
             self.generate_proxy(i)
             self.generate_skeleton(i)
         if self.generate_objmanager:
+            self.generate_object()
             self.generate_object_manager_client()
         self.generate_outro()
diff --git a/gio/gdbus-codegen/dbustypes.py b/gio/gdbus-codegen/dbustypes.py
index 1eb1282..3a39f13 100644
--- a/gio/gdbus-codegen/dbustypes.py
+++ b/gio/gdbus-codegen/dbustypes.py
@@ -349,6 +349,8 @@ class Interface:
                 self.name_lower = utils.camel_case_to_uscore(name_with_ns)
             self.name_upper = utils.camel_case_to_uscore(name).upper()
 
+        self.name_hyphen = self.name_upper.lower().replace('_', '-')
+
         if utils.lookup_annotation(self.annotations, 'org.freedesktop.DBus.Deprecated') == 'true':
             self.deprecated = True
 
diff --git a/gio/gdbusobject.c b/gio/gdbusobject.c
index c982fe0..8c16d66 100644
--- a/gio/gdbusobject.c
+++ b/gio/gdbusobject.c
@@ -146,60 +146,3 @@ g_dbus_object_get_interface (GDBusObject *object,
   g_return_val_if_fail (g_dbus_is_interface_name (interface_name), NULL);
   return iface->get_interface (object, interface_name);
 }
-
-
-/**
- * g_dbus_object_peek_with_typecheck:
- * @object: A #GDBusObject.
- * @interface_name: A D-Bus interface name.
- * @type: The #GType that the returned object must conform to.
- *
- * Like g_dbus_object_lookup_with_typecheck() except that the caller
- * does not own a reference to the returned object.
- *
- * <note><para>This function is intended to only be used in type
- * implementations.</para></note>
- *
- * Returns: (transfer none): A #GDBusInterface implementing @type or
- *   %NULL if not found. Do not free the returned object, it is owned
- *   by @object.
- *
- * Since: 2.30
- */
-gpointer
-g_dbus_object_peek_with_typecheck (GDBusObject *object,
-                                   const gchar *interface_name,
-                                   GType        type)
-{
-  GDBusObjectIface *iface = G_DBUS_OBJECT_GET_IFACE (object);
-  g_return_val_if_fail (g_dbus_is_interface_name (interface_name), NULL);
-  return iface->peek_with_typecheck (object, interface_name, type);
-}
-
-/**
- * g_dbus_object_lookup_with_typecheck:
- * @object: A #GDBusObject.
- * @interface_name: A D-Bus interface name.
- * @type: The #GType that the returned object must conform to.
- *
- * Like g_dbus_object_get_interface() but warns on stderr if the
- * returned object, if any, does not conform to @type.
- *
- * <note><para>This function is intended to only be used in type
- * implementations.</para></note>
- *
- * Returns: (transfer full): A #GDBusInterface implementing @type or
- *   %NULL if not found. Free with g_object_unref().
- *
- * Since: 2.30
- */
-gpointer
-g_dbus_object_lookup_with_typecheck (GDBusObject *object,
-                                     const gchar *interface_name,
-                                     GType        type)
-{
-  GDBusObjectIface *iface = G_DBUS_OBJECT_GET_IFACE (object);
-  g_return_val_if_fail (g_dbus_is_interface_name (interface_name), NULL);
-  return iface->lookup_with_typecheck (object, interface_name, type);
-}
-
diff --git a/gio/gdbusobject.h b/gio/gdbusobject.h
index 603229f..5212926 100644
--- a/gio/gdbusobject.h
+++ b/gio/gdbusobject.h
@@ -40,9 +40,6 @@ typedef struct _GDBusObjectIface GDBusObjectIface;
  * @get_object_path: Returns the object path. See g_dbus_object_get_object_path().
  * @get_interfaces: Returns all interfaces. See g_dbus_object_get_interfaces().
  * @get_interface: Returns an interface by name. See g_dbus_object_get_interface().
- * @lookup_with_typecheck: Like @get_interface but warns on stderr if the returned object, if any,
- *   does not conform to @type. Returned object must be freed by the caller.
- * @peek_with_typecheck: Like @lookup_with_typecheck but does not transfer the reference.
  * @interface_added: Signal handler for the #GDBusObject::interface-added signal.
  * @interface_removed: Signal handler for the #GDBusObject::interface-removed signal.
  *
@@ -64,13 +61,6 @@ struct _GDBusObjectIface
   GDBusInterface  *(*get_interface)   (GDBusObject  *object,
                                        const gchar  *interface_name);
 
-  gpointer         (*lookup_with_typecheck) (GDBusObject *object,
-                                             const gchar *interface_name,
-                                             GType        type);
-  gpointer         (*peek_with_typecheck)   (GDBusObject *object,
-                                             const gchar *interface_name,
-                                             GType        type);
-
   /* Signals */
   void (*interface_added)   (GDBusObject     *object,
                              GDBusInterface  *interface_);
@@ -85,13 +75,6 @@ GList           *g_dbus_object_get_interfaces  (GDBusObject  *object);
 GDBusInterface  *g_dbus_object_get_interface   (GDBusObject  *object,
                                                 const gchar  *interface_name);
 
-gpointer         g_dbus_object_peek_with_typecheck   (GDBusObject *object,
-                                                      const gchar *interface_name,
-                                                      GType        type);
-gpointer         g_dbus_object_lookup_with_typecheck (GDBusObject *object,
-                                                      const gchar *interface_name,
-                                                      GType        type);
-
 G_END_DECLS
 
 #endif /* __G_DBUS_OBJECT_H__ */
diff --git a/gio/gdbusobjectmanagerclient.c b/gio/gdbusobjectmanagerclient.c
index fe33d4b..474152d 100644
--- a/gio/gdbusobjectmanagerclient.c
+++ b/gio/gdbusobjectmanagerclient.c
@@ -1387,7 +1387,23 @@ add_interfaces (GDBusObjectManagerClient *manager,
   op = g_hash_table_lookup (manager->priv->map_object_path_to_object_proxy, object_path);
   if (op == NULL)
     {
-      op = _g_dbus_object_proxy_new (manager->priv->connection, object_path);
+      GType object_proxy_type;
+      if (manager->priv->get_proxy_type_func != NULL)
+        {
+          object_proxy_type = manager->priv->get_proxy_type_func (manager,
+                                                                  object_path,
+                                                                  NULL,
+                                                                  manager->priv->get_proxy_type_user_data);
+          g_warn_if_fail (g_type_is_a (object_proxy_type, G_TYPE_DBUS_OBJECT_PROXY));
+        }
+      else
+        {
+          object_proxy_type = G_TYPE_DBUS_OBJECT_PROXY;
+        }
+      op = g_object_new (object_proxy_type,
+                         "connection", manager->priv->connection,
+                         "object-path", object_path,
+                         NULL);
       added = TRUE;
     }
 
diff --git a/gio/gdbusobjectproxy.c b/gio/gdbusobjectproxy.c
index 39d3126..46f249b 100644
--- a/gio/gdbusobjectproxy.c
+++ b/gio/gdbusobjectproxy.c
@@ -37,9 +37,9 @@
  * @include: gio/gio.h
  *
  * A #GDBusObjectProxy is an object used to represent a remote object
- * with one or more D-Bus interfaces. You cannot instantiate a
- * #GDBusObjectProxy yourself - you need to use a
- * #GDBusObjectManagerClient to get one.
+ * with one or more D-Bus interfaces. Normally, you don't instantiate
+ * a #GDBusObjectProxy yourself - typically #GDBusObjectManagerClient
+ * is used to obtain it.
  *
  * Since: 2.30
  */
@@ -104,8 +104,18 @@ g_dbus_object_proxy_set_property (GObject       *object,
                                   const GValue  *value,
                                   GParamSpec    *pspec)
 {
+  GDBusObjectProxy *proxy = G_DBUS_OBJECT_PROXY (object);
+
   switch (prop_id)
     {
+    case PROP_OBJECT_PATH:
+      proxy->priv->object_path = g_value_dup_string (value);
+      break;
+
+    case PROP_CONNECTION:
+      proxy->priv->connection = g_value_dup_object (value);
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (_object, prop_id, pspec);
       break;
@@ -134,7 +144,8 @@ g_dbus_object_proxy_class_init (GDBusObjectProxyClass *klass)
                                                         "Object Path",
                                                         "The object path of the proxy",
                                                         NULL,
-                                                        G_PARAM_READABLE |
+                                                        G_PARAM_READWRITE |
+                                                        G_PARAM_CONSTRUCT_ONLY |
                                                         G_PARAM_STATIC_STRINGS));
 
   /**
@@ -146,11 +157,12 @@ g_dbus_object_proxy_class_init (GDBusObjectProxyClass *klass)
    */
   g_object_class_install_property (gobject_class,
                                    PROP_CONNECTION,
-                                   g_param_spec_string ("connection",
+                                   g_param_spec_object ("connection",
                                                         "Connection",
                                                         "The connection of the proxy",
-                                                        NULL,
-                                                        G_PARAM_READABLE |
+                                                        G_TYPE_DBUS_CONNECTION,
+                                                        G_PARAM_READWRITE |
+                                                        G_PARAM_CONSTRUCT_ONLY |
                                                         G_PARAM_STATIC_STRINGS));
 
   g_type_class_add_private (klass, sizeof (GDBusObjectProxyPrivate));
@@ -231,18 +243,15 @@ g_dbus_object_proxy_get_interfaces (GDBusObject *object)
 /* ---------------------------------------------------------------------------------------------------- */
 
 GDBusObjectProxy *
-_g_dbus_object_proxy_new (GDBusConnection *connection,
-                          const gchar *object_path)
+g_dbus_object_proxy_new (GDBusConnection *connection,
+                         const gchar *object_path)
 {
-  GDBusObjectProxy *proxy;
-
   g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL);
   g_return_val_if_fail (g_variant_is_object_path (object_path), NULL);
-
-  proxy = G_DBUS_OBJECT_PROXY (g_object_new (G_TYPE_DBUS_OBJECT_PROXY, NULL));
-  proxy->priv->object_path = g_strdup (object_path);
-  proxy->priv->connection = g_object_ref (connection);
-  return proxy;
+  return G_DBUS_OBJECT_PROXY (g_object_new (G_TYPE_DBUS_OBJECT_PROXY,
+                                            "object-path", object_path,
+                                            "connection", connection,
+                                            NULL));
 }
 
 void
@@ -281,44 +290,10 @@ _g_dbus_object_proxy_remove_interface (GDBusObjectProxy *proxy,
     }
 }
 
-static gpointer
-g_dbus_object_proxy_lookup_with_typecheck (GDBusObject *object,
-                                           const gchar *interface_name,
-                                           GType        type)
-{
-  GDBusObjectProxy *proxy = G_DBUS_OBJECT_PROXY (object);
-  GDBusProxy *ret;
-
-  g_return_val_if_fail (G_IS_DBUS_OBJECT_PROXY (proxy), NULL);
-  g_return_val_if_fail (g_dbus_is_interface_name (interface_name), NULL);
-
-  ret = g_hash_table_lookup (proxy->priv->map_name_to_iface, interface_name);
-  if (ret != NULL)
-    {
-      g_warn_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (ret, type));
-      g_object_ref (ret);
-    }
-  return ret;
-}
-
-static gpointer
-g_dbus_object_proxy_peek_with_typecheck (GDBusObject  *object,
-                                         const gchar  *interface_name,
-                                         GType         type)
-{
-  GDBusProxy *ret;
-  ret = g_dbus_object_proxy_lookup_with_typecheck (object, interface_name, type);
-  if (ret != NULL)
-    g_object_unref (ret);
-  return ret;
-}
-
 static void
 dbus_object_interface_init (GDBusObjectIface *iface)
 {
   iface->get_object_path       = g_dbus_object_proxy_get_object_path;
   iface->get_interfaces        = g_dbus_object_proxy_get_interfaces;
   iface->get_interface         = g_dbus_object_proxy_get_interface;
-  iface->peek_with_typecheck   = g_dbus_object_proxy_peek_with_typecheck;
-  iface->lookup_with_typecheck = g_dbus_object_proxy_lookup_with_typecheck;
 }
diff --git a/gio/gdbusobjectproxy.h b/gio/gdbusobjectproxy.h
index c8e3f30..58aef85 100644
--- a/gio/gdbusobjectproxy.h
+++ b/gio/gdbusobjectproxy.h
@@ -68,8 +68,10 @@ struct _GDBusObjectProxyClass
   gpointer padding[8];
 };
 
-GType            g_dbus_object_proxy_get_type         (void) G_GNUC_CONST;
-GDBusConnection *g_dbus_object_proxy_get_connection   (GDBusObjectProxy *proxy);
+GType             g_dbus_object_proxy_get_type       (void) G_GNUC_CONST;
+GDBusObjectProxy *g_dbus_object_proxy_new            (GDBusConnection   *connection,
+                                                      const gchar       *object_path);
+GDBusConnection  *g_dbus_object_proxy_get_connection (GDBusObjectProxy  *proxy);
 
 G_END_DECLS
 
diff --git a/gio/gdbusobjectskeleton.c b/gio/gdbusobjectskeleton.c
index 134003f..ce7362f 100644
--- a/gio/gdbusobjectskeleton.c
+++ b/gio/gdbusobjectskeleton.c
@@ -435,43 +435,12 @@ g_dbus_object_skeleton_flush (GDBusObjectSkeleton *object)
     }
 }
 
-static gpointer
-g_dbus_object_skeleton_lookup_with_typecheck (GDBusObject *object,
-                                              const gchar *interface_name,
-                                              GType        type)
-{
-  GDBusObjectSkeleton *skeleton = G_DBUS_OBJECT_SKELETON (object);
-  GDBusProxy *ret;
-
-  ret = g_hash_table_lookup (skeleton->priv->map_name_to_iface, interface_name);
-  if (ret != NULL)
-    {
-      g_warn_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (ret, type));
-      g_object_ref (ret);
-    }
-  return ret;
-}
-
-static gpointer
-g_dbus_object_skeleton_peek_with_typecheck   (GDBusObject *object,
-                                              const gchar *interface_name,
-                                              GType        type)
-{
-  GDBusInterfaceSkeleton *ret;
-  ret = g_dbus_object_skeleton_lookup_with_typecheck (object, interface_name, type);
-  if (ret != NULL)
-    g_object_unref (ret);
-  return ret;
-}
-
 static void
 dbus_object_interface_init (GDBusObjectIface *iface)
 {
   iface->get_object_path = g_dbus_object_skeleton_get_object_path;
   iface->get_interfaces  = g_dbus_object_skeleton_get_interfaces;
   iface->get_interface  = g_dbus_object_skeleton_get_interface;
-  iface->lookup_with_typecheck = g_dbus_object_skeleton_lookup_with_typecheck;
-  iface->peek_with_typecheck = g_dbus_object_skeleton_peek_with_typecheck;
 }
 
 gboolean
diff --git a/gio/gdbusprivate.h b/gio/gdbusprivate.h
index 203c4ac..651d4d6 100644
--- a/gio/gdbusprivate.h
+++ b/gio/gdbusprivate.h
@@ -133,8 +133,6 @@ gboolean _g_signal_accumulator_false_handled (GSignalInvocationHint *ihint,
 
 gboolean _g_dbus_object_skeleton_has_authorize_method_handlers (GDBusObjectSkeleton *object);
 
-GDBusObjectProxy *_g_dbus_object_proxy_new (GDBusConnection *connection,
-                                            const gchar *object_path);
 void _g_dbus_object_proxy_add_interface (GDBusObjectProxy *proxy,
                                          GDBusProxy       *interface_proxy);
 void _g_dbus_object_proxy_remove_interface (GDBusObjectProxy *proxy,
diff --git a/gio/gio.symbols b/gio/gio.symbols
index 0dfcb61..650ca96 100644
--- a/gio/gio.symbols
+++ b/gio/gio.symbols
@@ -2121,13 +2121,12 @@ g_dbus_object_get_interface
 g_dbus_object_get_interfaces
 g_dbus_object_get_object_path
 g_dbus_object_get_type
-g_dbus_object_lookup_with_typecheck
-g_dbus_object_peek_with_typecheck
 #endif
 #endif
 
 #if IN_HEADER(__G_DBUS_OBJECT_PROXY_H__)
 #if IN_FILE(__G_DBUS_OBJECT_PROXY_C__)
+g_dbus_object_proxy_new
 g_dbus_object_proxy_get_connection
 g_dbus_object_proxy_get_type
 #endif
diff --git a/gio/giotypes.h b/gio/giotypes.h
index a91eb10..3cc4f66 100644
--- a/gio/giotypes.h
+++ b/gio/giotypes.h
@@ -431,18 +431,20 @@ typedef struct _GDBusObjectManagerServer    GDBusObjectManagerServer;
  * GDBusProxyTypeFunc:
  * @manager: A #GDBusObjectManagerClient.
  * @object_path: The object path of the remote object.
- * @interface_name: The interface name of the remote object.
+ * @interface_name: (allow-none): The interface name of the remote object or %NULL if a #GDBusObjectProxy #GType is requested.
  * @user_data: User data.
  *
  * Function signature for a function used to determine the #GType to
- * use for an interface proxy.
+ * use for an interface proxy (if @interface_name is not %NULL) or
+ * object proxy (if @interface_name is %NULL).
  *
  * This function is called in the
  * <link linkend="g-main-context-push-thread-default">thread-default main loop</link>
  * that @manager was constructed in.
  *
  * Returns: A #GType to use for the remote object. The returned type
- * must be a #GDBusProxy derived type.
+ *   must be a #GDBusProxy<!-- -->- or #GDBusObjectProxy<!-- -->-derived
+ *   type.
  *
  * Since: 2.30
  */
diff --git a/gio/tests/gdbus-example-objectmanager-client.c b/gio/tests/gdbus-example-objectmanager-client.c
index 19a3c82..b413890 100644
--- a/gio/tests/gdbus-example-objectmanager-client.c
+++ b/gio/tests/gdbus-example-objectmanager-client.c
@@ -13,12 +13,12 @@ print_objects (GDBusObjectManager *manager)
   objects = g_dbus_object_manager_get_objects (manager);
   for (l = objects; l != NULL; l = l->next)
     {
-      GDBusObject *object = G_DBUS_OBJECT (l->data);
+      ExampleObject *object = EXAMPLE_OBJECT (l->data);
       GList *interfaces;
       GList *ll;
-      g_print (" - Object at %s\n", g_dbus_object_get_object_path (object));
+      g_print (" - Object at %s\n", g_dbus_object_get_object_path (G_DBUS_OBJECT (object)));
 
-      interfaces = g_dbus_object_get_interfaces (object);
+      interfaces = g_dbus_object_get_interfaces (G_DBUS_OBJECT (object));
       for (ll = interfaces; ll != NULL; ll = ll->next)
         {
           GDBusInterface *interface = G_DBUS_INTERFACE (ll->data);
diff --git a/gio/tests/gdbus-example-objectmanager-server.c b/gio/tests/gdbus-example-objectmanager-server.c
index 79d866c..0ef9c49 100644
--- a/gio/tests/gdbus-example-objectmanager-server.c
+++ b/gio/tests/gdbus-example-objectmanager-server.c
@@ -62,7 +62,7 @@ on_bus_acquired (GDBusConnection *connection,
                  const gchar     *name,
                  gpointer         user_data)
 {
-  GDBusObjectSkeleton *object;
+  ExampleObjectSkeleton *object;
   guint n;
 
   g_print ("Acquired a message bus connection\n");
@@ -77,7 +77,7 @@ on_bus_acquired (GDBusConnection *connection,
 
       /* Create a new D-Bus object at the path /example/Animals/N where N is 000..009 */
       s = g_strdup_printf ("/example/Animals/%03d", n);
-      object = g_dbus_object_skeleton_new (s);
+      object = example_object_skeleton_new (s);
       g_free (s);
 
       /* Make the newly created object export the interface
@@ -86,7 +86,7 @@ on_bus_acquired (GDBusConnection *connection,
        */
       animal = example_animal_skeleton_new ();
       example_animal_set_mood (animal, "Happy");
-      g_dbus_object_skeleton_add_interface (object, G_DBUS_INTERFACE_SKELETON (animal));
+      example_object_skeleton_set_animal (object, animal);
       g_object_unref (animal);
 
       /* Cats are odd animals - so some of our objects implement the
@@ -97,7 +97,7 @@ on_bus_acquired (GDBusConnection *connection,
         {
           ExampleCat *cat;
           cat = example_cat_skeleton_new ();
-          g_dbus_object_skeleton_add_interface (object, G_DBUS_INTERFACE_SKELETON (cat));
+          example_object_skeleton_set_cat (object, cat);
           g_object_unref (cat);
         }
 
@@ -108,7 +108,7 @@ on_bus_acquired (GDBusConnection *connection,
                         NULL); /* user_data */
 
       /* Export the object (@manager takes its own reference to @object) */
-      g_dbus_object_manager_server_export (manager, object);
+      g_dbus_object_manager_server_export (manager, G_DBUS_OBJECT_SKELETON (object));
       g_object_unref (object);
     }
 }
diff --git a/gio/tests/gdbus-test-codegen.c b/gio/tests/gdbus-test-codegen.c
index f7e7de3..896573c 100644
--- a/gio/tests/gdbus-test-codegen.c
+++ b/gio/tests/gdbus-test-codegen.c
@@ -1624,7 +1624,7 @@ om_on_signal (GDBusConnection *connection,
 static GAsyncResult *om_res = NULL;
 
 static void
-om_pm_start_cb (GDBusObjectManagerClient *manager,
+om_pm_start_cb (FooObjectManagerClient *manager,
                 GAsyncResult      *res,
                 gpointer           user_data)
 {
@@ -1633,26 +1633,6 @@ om_pm_start_cb (GDBusObjectManagerClient *manager,
   g_main_loop_quit (loop);
 }
 
-static GType
-get_proxy_type (GDBusObjectManagerClient *manager,
-                const gchar       *object_path,
-                const gchar       *interface_name,
-                gpointer           user_data)
-{
-  GType type;
-
-  g_assert_cmpint (GPOINTER_TO_UINT (user_data), ==, 42);
-
-  type = G_TYPE_DBUS_PROXY;
-  /* only map Bar and Bat, not other interface types */
-  if (g_strcmp0 (interface_name, "org.project.Bar") == 0)
-    type = FOO_TYPE_BAR_PROXY;
-  else if (g_strcmp0 (interface_name, "org.project.Bat") == 0)
-    type = FOO_TYPE_BAT_PROXY;
-
-  return type;
-}
-
 static void
 on_interface_added (GDBusObject    *object,
                     GDBusInterface *interface,
@@ -1724,10 +1704,9 @@ om_check_property_and_signal_emission (GMainLoop  *loop,
 static void
 check_object_manager (void)
 {
-  GDBusObjectSkeleton *o;
-  GDBusObjectSkeleton *o2;
+  FooObjectSkeleton *o;
+  FooObjectSkeleton *o2;
   GDBusInterfaceSkeleton *i;
-  GDBusInterfaceSkeleton *i2;
   GDBusConnection *c;
   GDBusObjectManagerServer *manager;
   GDBusNodeInfo *info;
@@ -1741,10 +1720,6 @@ check_object_manager (void)
   GDBusObject *op;
   GDBusProxy *p;
   FooBar *bar_skeleton;
-  FooBar *bar_p;
-  FooBar *bar_p2;
-  FooComAcmeCoyote *coyote_p;
-  guint old_ref_count;
 
   loop = g_main_loop_new (NULL, FALSE);
 
@@ -1777,15 +1752,12 @@ check_object_manager (void)
    * GDBusObjectManagerClient firing before om_on_signal().
    */
   error = NULL;
-  pm = g_dbus_object_manager_client_new_sync (c,
-                                              G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE,
-                                              g_dbus_connection_get_unique_name (c),
-                                              "/managed",
-                                              get_proxy_type,
-                                              GUINT_TO_POINTER (42),
-                                              NULL, /* GDestroyNotify */
-                                              NULL, /* GCancellable */
-                                              &error);
+  pm = foo_object_manager_client_new_sync (c,
+                                           G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE,
+                                           g_dbus_connection_get_unique_name (c),
+                                           "/managed",
+                                           NULL, /* GCancellable */
+                                           &error);
   g_assert_error (error, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD);
   g_error_free (error);
   g_assert (pm == NULL);
@@ -1805,19 +1777,16 @@ check_object_manager (void)
 
   /* Now try to create the the proxy manager again - this time it should work */
   error = NULL;
-  g_dbus_object_manager_client_new (c,
-                                    G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE,
-                                    g_dbus_connection_get_unique_name (c),
-                                    "/managed",
-                                    get_proxy_type,
-                                    GUINT_TO_POINTER (42),
-                                    NULL, /* GDestroyNotify */
-                                    NULL, /* GCancellable */
-                                    (GAsyncReadyCallback) om_pm_start_cb,
-                                    loop);
+  foo_object_manager_client_new (c,
+                                 G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE,
+                                 g_dbus_connection_get_unique_name (c),
+                                 "/managed",
+                                 NULL, /* GCancellable */
+                                 (GAsyncReadyCallback) om_pm_start_cb,
+                                 loop);
   g_main_loop_run (loop);
   error = NULL;
-  pm = g_dbus_object_manager_client_new_finish (om_res, &error);
+  pm = foo_object_manager_client_new_finish (om_res, &error);
   g_object_unref (om_res);
   g_assert_no_error (error);
   g_assert (pm != NULL);
@@ -1836,22 +1805,22 @@ check_object_manager (void)
   /* First, export an object with a single interface (also check that
    * g_dbus_interface_get_object() works and that the object isn't reffed)
    */
-  o = g_dbus_object_skeleton_new ("/managed/first");
+  o = foo_object_skeleton_new ("/managed/first");
   i = G_DBUS_INTERFACE_SKELETON (foo_bar_skeleton_new ());
   g_assert (g_dbus_interface_get_object (G_DBUS_INTERFACE (i)) == NULL);
   g_assert_cmpint (G_OBJECT (o)->ref_count, ==, 1);
-  g_dbus_object_skeleton_add_interface (o, i);
+  foo_object_skeleton_set_bar (o, FOO_BAR (i));
   g_assert_cmpint (G_OBJECT (o)->ref_count, ==, 1);
   g_assert (g_dbus_interface_get_object (G_DBUS_INTERFACE (i)) == G_DBUS_OBJECT (o));
   g_assert_cmpint (G_OBJECT (o)->ref_count, ==, 1);
   g_assert_cmpint (G_OBJECT (o)->ref_count, ==, 1);
-  g_dbus_object_skeleton_remove_interface (o, i);
+  foo_object_skeleton_set_bar (o, NULL);
   g_assert (g_dbus_interface_get_object (G_DBUS_INTERFACE (i)) == NULL);
   g_assert_cmpint (G_OBJECT (o)->ref_count, ==, 1);
-  g_dbus_object_skeleton_add_interface (o, i);
+  foo_object_skeleton_set_bar (o, FOO_BAR (i));
   g_assert (g_dbus_interface_get_object (G_DBUS_INTERFACE (i)) == G_DBUS_OBJECT (o));
   g_assert_cmpint (G_OBJECT (o)->ref_count, ==, 1);
-  g_dbus_object_manager_server_export (manager, o);
+  g_dbus_object_manager_server_export (manager, G_DBUS_OBJECT_SKELETON (o));
 
   /* ... check we get the InterfacesAdded signal */
   om_data->state = 1;
@@ -1868,7 +1837,7 @@ check_object_manager (void)
   g_dbus_node_info_unref (info);
 
   /* Now, check adding the same interface replaces the existing one */
-  g_dbus_object_skeleton_add_interface (o, i);
+  foo_object_skeleton_set_bar (o, FOO_BAR (i));
   /* ... check we get the InterfacesRemoved */
   om_data->state = 3;
   g_main_loop_run (om_data->loop);
@@ -1887,7 +1856,7 @@ check_object_manager (void)
 
   /* check adding an interface of same type (but not same object) replaces the existing one */
   i = G_DBUS_INTERFACE_SKELETON (foo_bar_skeleton_new ());
-  g_dbus_object_skeleton_add_interface (o, i);
+  foo_object_skeleton_set_bar (o, FOO_BAR (i));
   /* ... check we get the InterfacesRemoved and then InterfacesAdded */
   om_data->state = 7;
   g_main_loop_run (om_data->loop);
@@ -1905,7 +1874,7 @@ check_object_manager (void)
 
   /* check adding an interface of another type doesn't replace the existing one */
   i = G_DBUS_INTERFACE_SKELETON (foo_bat_skeleton_new ());
-  g_dbus_object_skeleton_add_interface (o, i);
+  foo_object_skeleton_set_bat (o, FOO_BAT (i));
   g_object_unref (i);
   /* ... check we get the InterfacesAdded */
   om_data->state = 11;
@@ -1923,7 +1892,7 @@ check_object_manager (void)
   g_dbus_node_info_unref (info);
 
   /* check we can remove an interface */
-  g_dbus_object_skeleton_remove_interface_by_name (o, "org.project.Bar");
+  foo_object_skeleton_set_bar (o, NULL);
   /* ... check we get the InterfacesRemoved */
   om_data->state = 13;
   g_main_loop_run (om_data->loop);
@@ -1942,7 +1911,7 @@ check_object_manager (void)
    * (Note: if a signal was emitted we'd assert in the signal handler
    * because we're in state 14)
    */
-  g_dbus_object_skeleton_remove_interface_by_name (o, "org.project.Bar");
+  foo_object_skeleton_set_bar (o, NULL);
   /* ... check introspection data */
   info = introspect (c, g_dbus_connection_get_unique_name (c), "/managed/first", loop);
   g_assert_cmpint (count_interfaces (info), ==, 4); /* Bat + Properties,Introspectable,Peer */
@@ -1950,7 +1919,7 @@ check_object_manager (void)
   g_dbus_node_info_unref (info);
 
   /* remove the last interface */
-  g_dbus_object_skeleton_remove_interface_by_name (o, "org.project.Bat");
+  foo_object_skeleton_set_bat (o, NULL);
   /* ... check we get the InterfacesRemoved */
   om_data->state = 15;
   g_main_loop_run (om_data->loop);
@@ -1966,7 +1935,7 @@ check_object_manager (void)
 
   /* and add an interface again */
   i = G_DBUS_INTERFACE_SKELETON (foo_com_acme_coyote_skeleton_new ());
-  g_dbus_object_skeleton_add_interface (o, i);
+  foo_object_skeleton_set_com_acme_coyote (o, FOO_COM_ACME_COYOTE (i));
   g_object_unref (i);
   /* ... check we get the InterfacesAdded */
   om_data->state = 17;
@@ -1989,16 +1958,16 @@ check_object_manager (void)
   /* -------------------------------------------------- */
 
   /* create a new object with two interfaces */
-  o2 = g_dbus_object_skeleton_new ("/managed/second");
+  o2 = foo_object_skeleton_new ("/managed/second");
   i = G_DBUS_INTERFACE_SKELETON (foo_bar_skeleton_new ());
   bar_skeleton = FOO_BAR (i); /* save for later test */
-  g_dbus_object_skeleton_add_interface (o2, i);
+  foo_object_skeleton_set_bar (o2, FOO_BAR (i));
   g_object_unref (i);
   i = G_DBUS_INTERFACE_SKELETON (foo_bat_skeleton_new ());
-  g_dbus_object_skeleton_add_interface (o2, i);
+  foo_object_skeleton_set_bat (o2, FOO_BAT (i));
   g_object_unref (i);
   /* ... add it */
-  g_dbus_object_manager_server_export (manager, o2);
+  g_dbus_object_manager_server_export (manager, G_DBUS_OBJECT_SKELETON (o2));
   /* ... check we get the InterfacesAdded with _two_ interfaces */
   om_data->state = 101;
   g_main_loop_run (om_data->loop);
@@ -2016,27 +1985,9 @@ check_object_manager (void)
   om_check_get_all (c, loop,
                     "({objectpath '/managed/first': {'com.acme.Coyote': {'Mood': <''>}}, '/managed/second': {'org.project.Bar': {'y': <byte 0x00>, 'b': <false>, 'n': <int16 0>, 'q': <uint16 0>, 'i': <0>, 'u': <uint32 0>, 'x': <int64 0>, 't': <uint64 0>, 'd': <0.0>, 's': <''>, 'o': <objectpath '/'>, 'g': <signature ''>, 'ay': <b''>, 'as': <@as []>, 'aay': <@aay []>, 'ao': <@ao []>, 'ag': <@ag []>, 'FinallyNormalName': <''>, 'ReadonlyProperty': <''>, 'unset_i': <0>, 'unset_d': <0.0>, 'unset_s': <''>, 'unset_o': <objectpath '/'>, 'unset_g': <signature ''>, 'unset_ay': <b''>, 'unset_as': <@as []>, 'unset_ao': <@ao []>, 'unset_ag': <@ag []>, 'unset_struct': <(0, 0.0, '', objectpath '/', signature '', @ay [], @as [], @ao [], @ag [])>}, 'org.project.Bat': {'force_i': <0>, 'force_s': <''>, 'force_ay': <@ay []>, 'force_struct': <(0,)>}}},)");
 
-  /* check that the _GET_ and _PEEK_ macros work on the server side */
-  i = FOO_PEEK_BAR (o);
-  g_assert (i == NULL);
-  i = FOO_PEEK_COM_ACME_COYOTE (o);
-  g_assert (i != NULL);
-  g_assert (g_type_is_a (G_TYPE_FROM_INSTANCE (i), G_TYPE_DBUS_INTERFACE_SKELETON));
-  g_assert (g_type_is_a (G_TYPE_FROM_INSTANCE (i), FOO_TYPE_COM_ACME_COYOTE));
-  g_assert (g_type_is_a (G_TYPE_FROM_INSTANCE (i), FOO_TYPE_COM_ACME_COYOTE_SKELETON));
-  /* ... and that PEEK doesn't increase the ref_count but GET does */
-  g_assert_cmpint (G_OBJECT (i)->ref_count, ==, 2);
-  i2 = FOO_PEEK_COM_ACME_COYOTE (o);
-  g_assert (i == i2);
-  g_assert_cmpint (G_OBJECT (i)->ref_count, ==, 2);
-  i2 = FOO_GET_COM_ACME_COYOTE (o);
-  g_assert (i == i2);
-  g_assert_cmpint (G_OBJECT (i)->ref_count, ==, 3);
-  g_object_unref (i);
-
   /* Also check that the ObjectManagerClient returns these objects - and
-   * that they are of the right GType cf. what we requested via
-   * our ::get-proxy-type signal handler
+   * that they are of the right GType cf. what was requested via
+   * the generated ::get-proxy-type signal handler
    */
   object_proxies = g_dbus_object_manager_get_objects (pm);
   g_assert (g_list_length (object_proxies) == 2);
@@ -2044,15 +1995,16 @@ check_object_manager (void)
   g_list_free (object_proxies);
   op = g_dbus_object_manager_get_object (pm, "/managed/first");
   g_assert (op != NULL);
+  g_assert (FOO_IS_OBJECT_PROXY (op));
   g_assert_cmpstr (g_dbus_object_get_object_path (op), ==, "/managed/first");
   proxies = g_dbus_object_get_interfaces (op);
   g_assert (g_list_length (proxies) == 1);
   g_list_foreach (proxies, (GFunc) g_object_unref, NULL);
   g_list_free (proxies);
-  p = G_DBUS_PROXY (g_dbus_object_get_interface (op, "com.acme.Coyote"));
+  p = G_DBUS_PROXY (foo_object_get_com_acme_coyote (FOO_OBJECT (op)));
   g_assert (p != NULL);
-  g_assert_cmpint (G_TYPE_FROM_INSTANCE (p), ==, G_TYPE_DBUS_PROXY);
-  g_assert (!g_type_is_a (G_TYPE_FROM_INSTANCE (p), FOO_TYPE_COM_ACME_COYOTE));
+  g_assert_cmpint (G_TYPE_FROM_INSTANCE (p), ==, FOO_TYPE_COM_ACME_COYOTE_PROXY);
+  g_assert (g_type_is_a (G_TYPE_FROM_INSTANCE (p), FOO_TYPE_COM_ACME_COYOTE));
   g_object_unref (p);
   p = (GDBusProxy *) g_dbus_object_get_interface (op, "org.project.NonExisting");
   g_assert (p == NULL);
@@ -2060,17 +2012,18 @@ check_object_manager (void)
   /* -- */
   op = g_dbus_object_manager_get_object (pm, "/managed/second");
   g_assert (op != NULL);
+  g_assert (FOO_IS_OBJECT_PROXY (op));
   g_assert_cmpstr (g_dbus_object_get_object_path (op), ==, "/managed/second");
   proxies = g_dbus_object_get_interfaces (op);
   g_assert (g_list_length (proxies) == 2);
   g_list_foreach (proxies, (GFunc) g_object_unref, NULL);
   g_list_free (proxies);
-  p = G_DBUS_PROXY (g_dbus_object_get_interface (op, "org.project.Bat"));
+  p = G_DBUS_PROXY (foo_object_get_bat (FOO_OBJECT (op)));
   g_assert (p != NULL);
   g_assert_cmpint (G_TYPE_FROM_INSTANCE (p), ==, FOO_TYPE_BAT_PROXY);
   g_assert (g_type_is_a (G_TYPE_FROM_INSTANCE (p), FOO_TYPE_BAT));
   g_object_unref (p);
-  p = G_DBUS_PROXY (g_dbus_object_get_interface (op, "org.project.Bar"));
+  p = G_DBUS_PROXY (foo_object_get_bar (FOO_OBJECT (op)));
   g_assert (p != NULL);
   g_assert_cmpint (G_TYPE_FROM_INSTANCE (p), ==, FOO_TYPE_BAR_PROXY);
   g_assert (g_type_is_a (G_TYPE_FROM_INSTANCE (p), FOO_TYPE_BAR));
@@ -2085,40 +2038,6 @@ check_object_manager (void)
 
   /* -------------------------------------------------- */
 
-  /* check that the _GET_ and _PEEK_ macros work on the proxy side */
-  op = g_dbus_object_manager_get_object (pm, "/managed/second");
-  bar_p = FOO_GET_BAR (op);
-  old_ref_count = G_OBJECT (op)->ref_count;
-  g_assert (g_dbus_interface_get_object (G_DBUS_INTERFACE (bar_p)) == op);
-  g_assert_cmpint (old_ref_count, ==, G_OBJECT (op)->ref_count);
-  g_assert (g_type_is_a (G_TYPE_FROM_INSTANCE (bar_p), FOO_TYPE_BAR));
-  g_assert (g_type_is_a (G_TYPE_FROM_INSTANCE (bar_p), G_TYPE_DBUS_PROXY));
-  g_assert_cmpint (G_OBJECT (bar_p)->ref_count, ==, 2);
-  g_object_unref (bar_p);
-  bar_p2 = FOO_PEEK_BAR (op);
-  g_assert (bar_p2 == bar_p);
-  g_assert_cmpint (G_OBJECT (bar_p)->ref_count, ==, 1);
-  coyote_p = FOO_GET_COM_ACME_COYOTE (op);
-  g_assert (coyote_p == NULL);
-  coyote_p = FOO_PEEK_COM_ACME_COYOTE (op);
-  g_assert (coyote_p == NULL);
-  g_object_unref (op);
-
-  /* Also, check that we warn on stderr in case the get_proxy_type() function is
-   * wrong etc.
-   */
-  op = g_dbus_object_manager_get_object (pm, "/managed/first");
-  bar_p = FOO_GET_BAR (op);
-  g_assert (bar_p == NULL);
-  if (g_test_trap_fork (0, G_TEST_TRAP_SILENCE_STDERR))
-    {
-      coyote_p = FOO_GET_COM_ACME_COYOTE (op);
-    }
-  g_test_trap_assert_stderr ("*runtime check failed: (G_TYPE_CHECK_INSTANCE_TYPE (ret, type))*");
-  g_object_unref (op);
-
-  /* -------------------------------------------------- */
-
   /* Now remove the second object added above */
   g_dbus_object_manager_server_unexport (manager, "/managed/second");
   /* ... check we get InterfacesRemoved with both interfaces */
diff --git a/gio/tests/test-codegen.xml b/gio/tests/test-codegen.xml
index 162d850..84518a3 100644
--- a/gio/tests/test-codegen.xml
+++ b/gio/tests/test-codegen.xml
@@ -349,6 +349,9 @@
     <signal name="BazSignal"/>
   </interface>
 
+  <!-- ChangingInterfaceV2:
+       @since: 2.0
+  -->
   <interface name="ChangingInterfaceV2">
     <!--
       NewSignalIn2:
@@ -370,6 +373,9 @@
     <method name="FooMethod"/>
   </interface>
 
+  <!-- ChangingInterfaceV10:
+       @since: 10.0
+  -->
   <interface name="ChangingInterfaceV10">
     <!--
       AddedSignalIn10:



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]