You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
614 lines
32 KiB
614 lines
32 KiB
2 years ago
|
From aea538fe703652fd0a39b2ac9185133849cfdcc4 Mon Sep 17 00:00:00 2001
|
||
|
From: Thomas Jost <schnouki@schnouki.net>
|
||
|
Date: Thu, 13 Dec 2018 03:06:02 -0800
|
||
|
Subject: [PATCH] gdbus-codegen: honor "Property.EmitsChangedSignal"
|
||
|
annotations
|
||
|
|
||
|
Co-Authored-by: Andy Holmes <andrew.g.r.holmes@gmail.com>
|
||
|
---
|
||
|
gio/gdbus-2.0/codegen/codegen.py | 18 ++++++++++-----
|
||
|
gio/gdbus-2.0/codegen/dbustypes.py | 7 ++++++
|
||
|
gio/tests/gdbus-test-codegen.c | 36 +++++++++++++++++++++++++-----
|
||
|
gio/tests/test-codegen.xml | 6 +++++
|
||
|
4 files changed, 56 insertions(+), 11 deletions(-)
|
||
|
|
||
|
diff --git a/gio/gdbus-2.0/codegen/codegen.py b/gio/gdbus-2.0/codegen/codegen.py
|
||
|
index f6892af95..442bd3f5d 100644
|
||
|
--- a/gio/gdbus-2.0/codegen/codegen.py
|
||
|
+++ b/gio/gdbus-2.0/codegen/codegen.py
|
||
|
@@ -638,61 +638,62 @@ class CodeGenerator:
|
||
|
'# include <gio/gunixfdlist.h>\n'
|
||
|
'#endif\n'
|
||
|
'\n')
|
||
|
|
||
|
self.outfile.write('typedef struct\n'
|
||
|
'{\n'
|
||
|
' GDBusArgInfo parent_struct;\n'
|
||
|
' gboolean use_gvariant;\n'
|
||
|
'} _ExtendedGDBusArgInfo;\n'
|
||
|
'\n')
|
||
|
|
||
|
self.outfile.write('typedef struct\n'
|
||
|
'{\n'
|
||
|
' GDBusMethodInfo parent_struct;\n'
|
||
|
' const gchar *signal_name;\n'
|
||
|
' gboolean pass_fdlist;\n'
|
||
|
'} _ExtendedGDBusMethodInfo;\n'
|
||
|
'\n')
|
||
|
|
||
|
self.outfile.write('typedef struct\n'
|
||
|
'{\n'
|
||
|
' GDBusSignalInfo parent_struct;\n'
|
||
|
' const gchar *signal_name;\n'
|
||
|
'} _ExtendedGDBusSignalInfo;\n'
|
||
|
'\n')
|
||
|
|
||
|
self.outfile.write('typedef struct\n'
|
||
|
'{\n'
|
||
|
' GDBusPropertyInfo parent_struct;\n'
|
||
|
' const gchar *hyphen_name;\n'
|
||
|
- ' gboolean use_gvariant;\n'
|
||
|
+ ' guint use_gvariant : 1;\n'
|
||
|
+ ' guint emits_changed_signal : 1;\n'
|
||
|
'} _ExtendedGDBusPropertyInfo;\n'
|
||
|
'\n')
|
||
|
|
||
|
self.outfile.write('typedef struct\n'
|
||
|
'{\n'
|
||
|
' GDBusInterfaceInfo parent_struct;\n'
|
||
|
' const gchar *hyphen_name;\n'
|
||
|
'} _ExtendedGDBusInterfaceInfo;\n'
|
||
|
'\n')
|
||
|
|
||
|
self.outfile.write('typedef struct\n'
|
||
|
'{\n'
|
||
|
' const _ExtendedGDBusPropertyInfo *info;\n'
|
||
|
' guint prop_id;\n'
|
||
|
' GValue orig_value; /* the value before the change */\n'
|
||
|
'} ChangedProperty;\n'
|
||
|
'\n'
|
||
|
'static void\n'
|
||
|
'_changed_property_free (ChangedProperty *data)\n'
|
||
|
'{\n'
|
||
|
' g_value_unset (&data->orig_value);\n'
|
||
|
' g_free (data);\n'
|
||
|
'}\n'
|
||
|
'\n')
|
||
|
|
||
|
self.outfile.write('static gboolean\n'
|
||
|
'_g_strv_equal0 (gchar **a, gchar **b)\n'
|
||
|
'{\n'
|
||
|
' gboolean ret = FALSE;\n'
|
||
|
' guint n;\n'
|
||
|
@@ -933,63 +934,67 @@ class CodeGenerator:
|
||
|
'\n')
|
||
|
|
||
|
# ---
|
||
|
|
||
|
if len(i.properties) > 0:
|
||
|
for p in i.properties:
|
||
|
if p.readable and p.writable:
|
||
|
access = 'G_DBUS_PROPERTY_INFO_FLAGS_READABLE | G_DBUS_PROPERTY_INFO_FLAGS_WRITABLE'
|
||
|
elif p.readable:
|
||
|
access = 'G_DBUS_PROPERTY_INFO_FLAGS_READABLE'
|
||
|
elif p.writable:
|
||
|
access = 'G_DBUS_PROPERTY_INFO_FLAGS_WRITABLE'
|
||
|
else:
|
||
|
access = 'G_DBUS_PROPERTY_INFO_FLAGS_NONE'
|
||
|
num_anno = self.generate_annotations('_%s_property_%s_annotation_info'%(i.name_lower, p.name_lower), p.annotations)
|
||
|
self.outfile.write('static const _ExtendedGDBusPropertyInfo _%s_property_info_%s =\n'
|
||
|
'{\n'
|
||
|
' {\n'
|
||
|
' -1,\n'
|
||
|
' (gchar *) "%s",\n'
|
||
|
' (gchar *) "%s",\n'
|
||
|
' %s,\n'%(i.name_lower, p.name_lower, p.name, p.arg.signature, access))
|
||
|
if num_anno == 0:
|
||
|
self.outfile.write(' NULL\n')
|
||
|
else:
|
||
|
self.outfile.write(' (GDBusAnnotationInfo **) &_%s_property_%s_annotation_info_pointers\n'%(i.name_lower, p.name_lower))
|
||
|
self.outfile.write(' },\n'
|
||
|
' "%s",\n'
|
||
|
%(p.name_hyphen))
|
||
|
if not utils.lookup_annotation(p.annotations, 'org.gtk.GDBus.C.ForceGVariant'):
|
||
|
- self.outfile.write(' FALSE\n')
|
||
|
+ self.outfile.write(' FALSE,\n')
|
||
|
else:
|
||
|
+ self.outfile.write(' TRUE,\n')
|
||
|
+ if p.emits_changed_signal:
|
||
|
self.outfile.write(' TRUE\n')
|
||
|
+ else:
|
||
|
+ self.outfile.write(' FALSE\n')
|
||
|
self.outfile.write('};\n'
|
||
|
'\n')
|
||
|
|
||
|
self.outfile.write('static const GDBusPropertyInfo * const _%s_property_info_pointers[] =\n'
|
||
|
'{\n'%(i.name_lower))
|
||
|
for p in i.properties:
|
||
|
self.outfile.write(' &_%s_property_info_%s.parent_struct,\n'%(i.name_lower, p.name_lower))
|
||
|
self.outfile.write(' NULL\n'
|
||
|
'};\n'
|
||
|
'\n')
|
||
|
|
||
|
num_anno = self.generate_annotations('_%s_annotation_info'%(i.name_lower), i.annotations)
|
||
|
self.outfile.write('static const _ExtendedGDBusInterfaceInfo _%s_interface_info =\n'
|
||
|
'{\n'
|
||
|
' {\n'
|
||
|
' -1,\n'
|
||
|
' (gchar *) "%s",\n'%(i.name_lower, i.name))
|
||
|
if len(i.methods) == 0:
|
||
|
self.outfile.write(' NULL,\n')
|
||
|
else:
|
||
|
self.outfile.write(' (GDBusMethodInfo **) &_%s_method_info_pointers,\n'%(i.name_lower))
|
||
|
if len(i.signals) == 0:
|
||
|
self.outfile.write(' NULL,\n')
|
||
|
else:
|
||
|
self.outfile.write(' (GDBusSignalInfo **) &_%s_signal_info_pointers,\n'%(i.name_lower))
|
||
|
if len(i.properties) == 0:
|
||
|
self.outfile.write(' NULL,\n')
|
||
|
else:
|
||
|
self.outfile.write(' (GDBusPropertyInfo **) &_%s_property_info_pointers,\n'%(i.name_lower))
|
||
|
if num_anno == 0:
|
||
|
@@ -2568,68 +2573,71 @@ class CodeGenerator:
|
||
|
# this allows use of g_object_freeze_notify()/g_object_thaw_notify() ...
|
||
|
# This is useful when updating several properties from another thread than
|
||
|
# where the idle will be emitted from
|
||
|
self.outfile.write('static void\n'
|
||
|
'%s_skeleton_notify (GObject *object,\n'
|
||
|
' GParamSpec *pspec G_GNUC_UNUSED)\n'
|
||
|
'{\n'
|
||
|
' %sSkeleton *skeleton = %s%s_SKELETON (object);\n'
|
||
|
' g_mutex_lock (&skeleton->priv->lock);\n'
|
||
|
' if (skeleton->priv->changed_properties != NULL &&\n'
|
||
|
' skeleton->priv->changed_properties_idle_source == NULL)\n'
|
||
|
' {\n'
|
||
|
' skeleton->priv->changed_properties_idle_source = g_idle_source_new ();\n'
|
||
|
' g_source_set_priority (skeleton->priv->changed_properties_idle_source, G_PRIORITY_DEFAULT);\n'
|
||
|
' g_source_set_callback (skeleton->priv->changed_properties_idle_source, _%s_emit_changed, g_object_ref (skeleton), (GDestroyNotify) g_object_unref);\n'
|
||
|
' g_source_set_name (skeleton->priv->changed_properties_idle_source, "[generated] _%s_emit_changed");\n'
|
||
|
' g_source_attach (skeleton->priv->changed_properties_idle_source, skeleton->priv->context);\n'
|
||
|
' g_source_unref (skeleton->priv->changed_properties_idle_source);\n'
|
||
|
' }\n'
|
||
|
' g_mutex_unlock (&skeleton->priv->lock);\n'
|
||
|
'}\n'
|
||
|
'\n'
|
||
|
%(i.name_lower, i.camel_name, i.ns_upper, i.name_upper, i.name_lower, i.name_lower))
|
||
|
|
||
|
self.outfile.write('static void\n'
|
||
|
'%s_skeleton_set_property (GObject *object,\n'
|
||
|
' guint prop_id,\n'
|
||
|
' const GValue *value,\n'
|
||
|
' GParamSpec *pspec)\n'
|
||
|
'{\n'%(i.name_lower))
|
||
|
- self.outfile.write(' %sSkeleton *skeleton = %s%s_SKELETON (object);\n'
|
||
|
+ self.outfile.write(' const _ExtendedGDBusPropertyInfo *info;\n'
|
||
|
+ ' %sSkeleton *skeleton = %s%s_SKELETON (object);\n'
|
||
|
' g_assert (prop_id != 0 && prop_id - 1 < %d);\n'
|
||
|
+ ' info = (const _ExtendedGDBusPropertyInfo *) _%s_property_info_pointers[prop_id - 1];\n'
|
||
|
' g_mutex_lock (&skeleton->priv->lock);\n'
|
||
|
' g_object_freeze_notify (object);\n'
|
||
|
' if (!_g_value_equal (value, &skeleton->priv->properties[prop_id - 1]))\n'
|
||
|
' {\n'
|
||
|
- ' if (g_dbus_interface_skeleton_get_connection (G_DBUS_INTERFACE_SKELETON (skeleton)) != NULL)\n'
|
||
|
- ' _%s_schedule_emit_changed (skeleton, (const _ExtendedGDBusPropertyInfo *) _%s_property_info_pointers[prop_id - 1], prop_id, &skeleton->priv->properties[prop_id - 1]);\n'
|
||
|
+ ' if (g_dbus_interface_skeleton_get_connection (G_DBUS_INTERFACE_SKELETON (skeleton)) != NULL &&\n'
|
||
|
+ ' info->emits_changed_signal)\n'
|
||
|
+ ' _%s_schedule_emit_changed (skeleton, info, prop_id, &skeleton->priv->properties[prop_id - 1]);\n'
|
||
|
' g_value_copy (value, &skeleton->priv->properties[prop_id - 1]);\n'
|
||
|
' g_object_notify_by_pspec (object, pspec);\n'
|
||
|
' }\n'
|
||
|
' g_mutex_unlock (&skeleton->priv->lock);\n'
|
||
|
' g_object_thaw_notify (object);\n'
|
||
|
%(i.camel_name, i.ns_upper, i.name_upper, len(i.properties), i.name_lower, i.name_lower))
|
||
|
self.outfile.write('}\n'
|
||
|
'\n')
|
||
|
|
||
|
self.outfile.write('static void\n'
|
||
|
'%s_skeleton_init (%sSkeleton *skeleton)\n'
|
||
|
'{\n'
|
||
|
'#if GLIB_VERSION_MAX_ALLOWED >= GLIB_VERSION_2_38\n'
|
||
|
' skeleton->priv = %s_skeleton_get_instance_private (skeleton);\n'
|
||
|
'#else\n'
|
||
|
' skeleton->priv = G_TYPE_INSTANCE_GET_PRIVATE (skeleton, %sTYPE_%s_SKELETON, %sSkeletonPrivate);\n'
|
||
|
'#endif\n\n'
|
||
|
%(i.name_lower, i.camel_name,
|
||
|
i.name_lower,
|
||
|
i.ns_upper, i.name_upper, i.camel_name))
|
||
|
self.outfile.write(' g_mutex_init (&skeleton->priv->lock);\n')
|
||
|
self.outfile.write(' skeleton->priv->context = g_main_context_ref_thread_default ();\n')
|
||
|
if len(i.properties) > 0:
|
||
|
self.outfile.write(' skeleton->priv->properties = g_new0 (GValue, %d);\n'%(len(i.properties)))
|
||
|
n = 0
|
||
|
for p in i.properties:
|
||
|
self.outfile.write(' g_value_init (&skeleton->priv->properties[%d], %s);\n'%(n, p.arg.gtype))
|
||
|
n += 1
|
||
|
self.outfile.write('}\n'
|
||
|
'\n')
|
||
|
diff --git a/gio/gdbus-2.0/codegen/dbustypes.py b/gio/gdbus-2.0/codegen/dbustypes.py
|
||
|
index bfc69f596..359880ff7 100644
|
||
|
--- a/gio/gdbus-2.0/codegen/dbustypes.py
|
||
|
+++ b/gio/gdbus-2.0/codegen/dbustypes.py
|
||
|
@@ -300,89 +300,96 @@ class Signal:
|
||
|
arg_count = 0
|
||
|
for a in self.args:
|
||
|
a.post_process(interface_prefix, cns, cns_upper, cns_lower, arg_count)
|
||
|
arg_count += 1
|
||
|
|
||
|
if utils.lookup_annotation(self.annotations, 'org.freedesktop.DBus.Deprecated') == 'true':
|
||
|
self.deprecated = True
|
||
|
|
||
|
class Property:
|
||
|
def __init__(self, name, signature, access):
|
||
|
self.name = name
|
||
|
self.signature = signature
|
||
|
self.access = access
|
||
|
self.annotations = []
|
||
|
self.arg = Arg('value', self.signature)
|
||
|
self.arg.annotations = self.annotations
|
||
|
self.readable = False
|
||
|
self.writable = False
|
||
|
if self.access == 'readwrite':
|
||
|
self.readable = True
|
||
|
self.writable = True
|
||
|
elif self.access == 'read':
|
||
|
self.readable = True
|
||
|
elif self.access == 'write':
|
||
|
self.writable = True
|
||
|
else:
|
||
|
print_error('Invalid access type "{}"'.format(self.access))
|
||
|
self.doc_string = ''
|
||
|
self.since = ''
|
||
|
self.deprecated = False
|
||
|
+ self.emits_changed_signal = True
|
||
|
|
||
|
def post_process(self, interface_prefix, cns, cns_upper, cns_lower, containing_iface):
|
||
|
if len(self.doc_string) == 0:
|
||
|
self.doc_string = utils.lookup_docs(self.annotations)
|
||
|
if len(self.since) == 0:
|
||
|
self.since = utils.lookup_since(self.annotations)
|
||
|
if len(self.since) == 0:
|
||
|
self.since = containing_iface.since
|
||
|
|
||
|
name = self.name
|
||
|
overridden_name = utils.lookup_annotation(self.annotations, 'org.gtk.GDBus.C.Name')
|
||
|
if utils.is_ugly_case(overridden_name):
|
||
|
self.name_lower = overridden_name.lower()
|
||
|
else:
|
||
|
if overridden_name:
|
||
|
name = overridden_name
|
||
|
self.name_lower = utils.camel_case_to_uscore(name).lower().replace('-', '_')
|
||
|
self.name_hyphen = self.name_lower.replace('_', '-')
|
||
|
# don't clash with the GType getter, e.g.: GType foo_bar_get_type (void); G_GNUC_CONST
|
||
|
if self.name_lower == 'type':
|
||
|
self.name_lower = 'type_'
|
||
|
|
||
|
# recalculate arg
|
||
|
self.arg.annotations = self.annotations
|
||
|
self.arg.post_process(interface_prefix, cns, cns_upper, cns_lower, 0)
|
||
|
|
||
|
if utils.lookup_annotation(self.annotations, 'org.freedesktop.DBus.Deprecated') == 'true':
|
||
|
self.deprecated = True
|
||
|
|
||
|
+ # FIXME: for now we only support 'false' and 'const' on the signal itself, see #674913 and
|
||
|
+ # http://dbus.freedesktop.org/doc/dbus-specification.html#introspection-format
|
||
|
+ # for details
|
||
|
+ if utils.lookup_annotation(self.annotations, 'org.freedesktop.DBus.Property.EmitsChangedSignal') in ('false', 'const'):
|
||
|
+ self.emits_changed_signal = False
|
||
|
+
|
||
|
class Interface:
|
||
|
def __init__(self, name):
|
||
|
self.name = name
|
||
|
self.methods = []
|
||
|
self.signals = []
|
||
|
self.properties = []
|
||
|
self.annotations = []
|
||
|
self.doc_string = ''
|
||
|
self.doc_string_brief = ''
|
||
|
self.since = ''
|
||
|
self.deprecated = False
|
||
|
|
||
|
def post_process(self, interface_prefix, c_namespace):
|
||
|
if len(self.doc_string) == 0:
|
||
|
self.doc_string = utils.lookup_docs(self.annotations)
|
||
|
if len(self.doc_string_brief) == 0:
|
||
|
self.doc_string_brief = utils.lookup_brief_docs(self.annotations)
|
||
|
if len(self.since) == 0:
|
||
|
self.since = utils.lookup_since(self.annotations)
|
||
|
|
||
|
if len(c_namespace) > 0:
|
||
|
if utils.is_ugly_case(c_namespace):
|
||
|
cns = c_namespace.replace('_', '')
|
||
|
cns_upper = c_namespace.upper() + '_'
|
||
|
cns_lower = c_namespace.lower() + '_'
|
||
|
else:
|
||
|
cns = c_namespace
|
||
|
cns_upper = utils.camel_case_to_uscore(c_namespace).upper() + '_'
|
||
|
cns_lower = utils.camel_case_to_uscore(c_namespace).lower() + '_'
|
||
|
else:
|
||
|
diff --git a/gio/tests/gdbus-test-codegen.c b/gio/tests/gdbus-test-codegen.c
|
||
|
index 1c4e83c4c..c906d05ae 100644
|
||
|
--- a/gio/tests/gdbus-test-codegen.c
|
||
|
+++ b/gio/tests/gdbus-test-codegen.c
|
||
|
@@ -1740,103 +1740,127 @@ on_object_proxy_added (GDBusObjectManagerClient *manager,
|
||
|
gpointer user_data)
|
||
|
{
|
||
|
OMData *om_data = user_data;
|
||
|
om_data->num_object_proxy_added_signals += 1;
|
||
|
g_signal_connect (object_proxy,
|
||
|
"interface-added",
|
||
|
G_CALLBACK (on_interface_added),
|
||
|
om_data);
|
||
|
g_signal_connect (object_proxy,
|
||
|
"interface-removed",
|
||
|
G_CALLBACK (on_interface_removed),
|
||
|
om_data);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
on_object_proxy_removed (GDBusObjectManagerClient *manager,
|
||
|
GDBusObjectProxy *object_proxy,
|
||
|
gpointer user_data)
|
||
|
{
|
||
|
OMData *om_data = user_data;
|
||
|
om_data->num_object_proxy_removed_signals += 1;
|
||
|
g_assert_cmpint (g_signal_handlers_disconnect_by_func (object_proxy,
|
||
|
G_CALLBACK (on_interface_added),
|
||
|
om_data), ==, 1);
|
||
|
g_assert_cmpint (g_signal_handlers_disconnect_by_func (object_proxy,
|
||
|
G_CALLBACK (on_interface_removed),
|
||
|
om_data), ==, 1);
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
-property_d_changed (GObject *object,
|
||
|
- GParamSpec *pspec,
|
||
|
- gpointer user_data)
|
||
|
+property_changed (GObject *object,
|
||
|
+ GParamSpec *pspec,
|
||
|
+ gpointer user_data)
|
||
|
{
|
||
|
gboolean *changed = user_data;
|
||
|
|
||
|
*changed = TRUE;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
om_check_property_and_signal_emission (GMainLoop *loop,
|
||
|
FooiGenBar *skeleton,
|
||
|
FooiGenBar *proxy)
|
||
|
{
|
||
|
gboolean d_changed = FALSE;
|
||
|
+ gboolean quiet_changed = FALSE;
|
||
|
+ gboolean quiet_too_changed = FALSE;
|
||
|
guint handler;
|
||
|
|
||
|
/* First PropertiesChanged */
|
||
|
g_assert_cmpint (foo_igen_bar_get_i (skeleton), ==, 0);
|
||
|
g_assert_cmpint (foo_igen_bar_get_i (proxy), ==, 0);
|
||
|
foo_igen_bar_set_i (skeleton, 1);
|
||
|
_g_assert_property_notify (proxy, "i");
|
||
|
g_assert_cmpint (foo_igen_bar_get_i (skeleton), ==, 1);
|
||
|
g_assert_cmpint (foo_igen_bar_get_i (proxy), ==, 1);
|
||
|
|
||
|
/* Double-check the gdouble case */
|
||
|
g_assert_cmpfloat (foo_igen_bar_get_d (skeleton), ==, 0.0);
|
||
|
g_assert_cmpfloat (foo_igen_bar_get_d (proxy), ==, 0.0);
|
||
|
foo_igen_bar_set_d (skeleton, 1.0);
|
||
|
_g_assert_property_notify (proxy, "d");
|
||
|
|
||
|
/* Verify that re-setting it to the same value doesn't cause a
|
||
|
* notify on the proxy, by taking advantage of the fact that
|
||
|
* notifications are serialized.
|
||
|
*/
|
||
|
handler = g_signal_connect (proxy, "notify::d",
|
||
|
- G_CALLBACK (property_d_changed), &d_changed);
|
||
|
+ G_CALLBACK (property_changed), &d_changed);
|
||
|
foo_igen_bar_set_d (skeleton, 1.0);
|
||
|
foo_igen_bar_set_i (skeleton, 2);
|
||
|
_g_assert_property_notify (proxy, "i");
|
||
|
g_assert (d_changed == FALSE);
|
||
|
g_signal_handler_disconnect (proxy, handler);
|
||
|
|
||
|
+ /* Verify that re-setting a property with the "EmitsChangedSignal"
|
||
|
+ * set to false doesn't emit a signal. */
|
||
|
+ handler = g_signal_connect (proxy, "notify::quiet",
|
||
|
+ G_CALLBACK (property_changed), &quiet_changed);
|
||
|
+ foo_igen_bar_set_quiet (skeleton, "hush!");
|
||
|
+ foo_igen_bar_set_i (skeleton, 3);
|
||
|
+ _g_assert_property_notify (proxy, "i");
|
||
|
+ g_assert (quiet_changed == FALSE);
|
||
|
+ g_assert_cmpstr (foo_igen_bar_get_quiet (skeleton), ==, "hush!");
|
||
|
+ g_signal_handler_disconnect (proxy, handler);
|
||
|
+
|
||
|
+ /* Also verify that re-setting a property with the "EmitsChangedSignal"
|
||
|
+ * set to 'const' doesn't emit a signal. */
|
||
|
+ handler = g_signal_connect (proxy, "notify::quiet-too",
|
||
|
+ G_CALLBACK (property_changed), &quiet_changed);
|
||
|
+ foo_igen_bar_set_quiet_too (skeleton, "hush too!");
|
||
|
+ foo_igen_bar_set_i (skeleton, 4);
|
||
|
+ _g_assert_property_notify (proxy, "i");
|
||
|
+ g_assert (quiet_too_changed == FALSE);
|
||
|
+ g_assert_cmpstr (foo_igen_bar_get_quiet_too (skeleton), ==, "hush too!");
|
||
|
+ g_signal_handler_disconnect (proxy, handler);
|
||
|
+
|
||
|
/* Then just a regular signal */
|
||
|
foo_igen_bar_emit_another_signal (skeleton, "word");
|
||
|
_g_assert_signal_received (proxy, "another-signal");
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
check_object_manager (void)
|
||
|
{
|
||
|
FooiGenObjectSkeleton *o = NULL;
|
||
|
FooiGenObjectSkeleton *o2 = NULL;
|
||
|
FooiGenObjectSkeleton *o3 = NULL;
|
||
|
GDBusInterfaceSkeleton *i;
|
||
|
GDBusConnection *c;
|
||
|
GDBusObjectManagerServer *manager = NULL;
|
||
|
GDBusNodeInfo *info;
|
||
|
GError *error;
|
||
|
GMainLoop *loop;
|
||
|
OMData *om_data = NULL;
|
||
|
guint om_signal_id = -1;
|
||
|
GDBusObjectManager *pm = NULL;
|
||
|
GList *object_proxies;
|
||
|
GList *proxies;
|
||
|
GDBusObject *op;
|
||
|
GDBusProxy *p;
|
||
|
FooiGenBar *bar_skeleton;
|
||
|
GDBusInterface *iface;
|
||
|
gchar *path, *name, *name_owner;
|
||
|
GDBusConnection *c2;
|
||
|
GDBusObjectManagerClientFlags flags;
|
||
|
|
||
|
@@ -2124,73 +2148,73 @@ check_object_manager (void)
|
||
|
"({objectpath '/managed/first': {'com.acme.Coyote': {'Mood': <''>}}},)");
|
||
|
|
||
|
/* -------------------------------------------------- */
|
||
|
|
||
|
/* create a new object with two interfaces */
|
||
|
o2 = foo_igen_object_skeleton_new ("/managed/second");
|
||
|
i = G_DBUS_INTERFACE_SKELETON (foo_igen_bar_skeleton_new ());
|
||
|
bar_skeleton = FOO_IGEN_BAR (i); /* save for later test */
|
||
|
foo_igen_object_skeleton_set_bar (o2, FOO_IGEN_BAR (i));
|
||
|
g_clear_object (&i);
|
||
|
i = G_DBUS_INTERFACE_SKELETON (foo_igen_bat_skeleton_new ());
|
||
|
foo_igen_object_skeleton_set_bat (o2, FOO_IGEN_BAT (i));
|
||
|
g_clear_object (&i);
|
||
|
/* ... add it */
|
||
|
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);
|
||
|
g_assert_cmpint (om_data->state, ==, 102);
|
||
|
g_assert_cmpint (om_data->num_object_proxy_added_signals, ==, 5);
|
||
|
g_assert_cmpint (om_data->num_object_proxy_removed_signals, ==, 3);
|
||
|
g_assert_cmpint (om_data->num_interface_added_signals, ==, 1);
|
||
|
g_assert_cmpint (om_data->num_interface_removed_signals, ==, 1);
|
||
|
|
||
|
/* -------------------------------------------------- */
|
||
|
|
||
|
/* Now that we have a couple of objects with interfaces, check
|
||
|
* that ObjectManager.GetManagedObjects() works
|
||
|
*/
|
||
|
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,)>}}},)");
|
||
|
+ "({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': <''>, 'quiet': <''>, 'quiet_too': <''>, '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,)>}}},)");
|
||
|
|
||
|
/* Set connection to NULL, causing everything to be unexported.. verify this.. and
|
||
|
* then set the connection back.. and then check things still work
|
||
|
*/
|
||
|
g_dbus_object_manager_server_set_connection (manager, NULL);
|
||
|
info = introspect (c, g_dbus_connection_get_unique_name (c), "/managed", loop);
|
||
|
g_assert_cmpint (count_interfaces (info), ==, 0); /* nothing */
|
||
|
g_dbus_node_info_unref (info);
|
||
|
|
||
|
g_dbus_object_manager_server_set_connection (manager, c);
|
||
|
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,)>}}},)");
|
||
|
+ "({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': <''>, 'quiet': <''>, 'quiet_too': <''>, '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,)>}}},)");
|
||
|
|
||
|
/* Also check that the ObjectManagerClient returns these objects - and
|
||
|
* 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);
|
||
|
g_list_free_full (object_proxies, g_object_unref);
|
||
|
op = g_dbus_object_manager_get_object (pm, "/managed/first");
|
||
|
g_assert (op != NULL);
|
||
|
g_assert (FOO_IGEN_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_free_full (proxies, g_object_unref);
|
||
|
p = G_DBUS_PROXY (foo_igen_object_get_com_acme_coyote (FOO_IGEN_OBJECT (op)));
|
||
|
g_assert (p != NULL);
|
||
|
g_assert_cmpint (G_TYPE_FROM_INSTANCE (p), ==, FOO_IGEN_TYPE_COM_ACME_COYOTE_PROXY);
|
||
|
g_assert (g_type_is_a (G_TYPE_FROM_INSTANCE (p), FOO_IGEN_TYPE_COM_ACME_COYOTE));
|
||
|
g_clear_object (&p);
|
||
|
p = (GDBusProxy *) g_dbus_object_get_interface (op, "org.project.NonExisting");
|
||
|
g_assert (p == NULL);
|
||
|
g_clear_object (&op);
|
||
|
|
||
|
/* -- */
|
||
|
op = g_dbus_object_manager_get_object (pm, "/managed/second");
|
||
|
g_assert (op != NULL);
|
||
|
g_assert (FOO_IGEN_IS_OBJECT_PROXY (op));
|
||
|
g_assert_cmpstr (g_dbus_object_get_object_path (op), ==, "/managed/second");
|
||
|
proxies = g_dbus_object_get_interfaces (op);
|
||
|
diff --git a/gio/tests/test-codegen.xml b/gio/tests/test-codegen.xml
|
||
|
index 885a21f77..39d8769c7 100644
|
||
|
--- a/gio/tests/test-codegen.xml
|
||
|
+++ b/gio/tests/test-codegen.xml
|
||
|
@@ -79,60 +79,66 @@
|
||
|
<arg type="aay" name="array_of_bytestrings" />
|
||
|
<arg type="a{s(ii)}" name="dict_s_to_pairs" />
|
||
|
</signal>
|
||
|
|
||
|
<signal name="AnotherSignal">
|
||
|
<arg type="s" name="word" />
|
||
|
</signal>
|
||
|
|
||
|
<property name="y" type="y" access="readwrite">
|
||
|
<annotation name="org.gtk.GDBus.DocString" value="<para>Property docs, yah...</para><para>Second paragraph.</para>"/>
|
||
|
</property>
|
||
|
<property name="b" type="b" access="readwrite"/>
|
||
|
<property name="n" type="n" access="readwrite"/>
|
||
|
<property name="q" type="q" access="readwrite"/>
|
||
|
<property name="i" type="i" access="readwrite"/>
|
||
|
<property name="u" type="u" access="readwrite"/>
|
||
|
<property name="x" type="x" access="readwrite"/>
|
||
|
<property name="t" type="t" access="readwrite"/>
|
||
|
<property name="d" type="d" access="readwrite"/>
|
||
|
<property name="s" type="s" access="readwrite"/>
|
||
|
<property name="o" type="o" access="readwrite"/>
|
||
|
<property name="g" type="g" access="readwrite"/>
|
||
|
<property name="ay" type="ay" access="readwrite"/>
|
||
|
<property name="as" type="as" access="readwrite"/>
|
||
|
<property name="aay" type="aay" access="readwrite"/>
|
||
|
<property name="ao" type="ao" access="readwrite"/>
|
||
|
<property name="ag" type="ag" access="readwrite"/>
|
||
|
<property name="FinallyNormalName" type="s" access="readwrite"/>
|
||
|
<property name="ReadonlyProperty" type="s" access="read"/>
|
||
|
<property name="WriteonlyProperty" type="s" access="write"/>
|
||
|
+ <property name="quiet" type="s" access="readwrite">
|
||
|
+ <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
|
||
|
+ </property>
|
||
|
+ <property name="quiet_too" type="s" access="readwrite">
|
||
|
+ <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
|
||
|
+ </property>
|
||
|
|
||
|
<!-- unset properties -->
|
||
|
<property name="unset_i" type="i" access="readwrite"/>
|
||
|
<property name="unset_d" type="d" access="readwrite"/>
|
||
|
<property name="unset_s" type="s" access="readwrite"/>
|
||
|
<property name="unset_o" type="o" access="readwrite"/>
|
||
|
<property name="unset_g" type="g" access="readwrite"/>
|
||
|
<property name="unset_ay" type="ay" access="readwrite"/>
|
||
|
<property name="unset_as" type="as" access="readwrite"/>
|
||
|
<property name="unset_ao" type="ao" access="readwrite"/>
|
||
|
<property name="unset_ag" type="ag" access="readwrite"/>
|
||
|
<property name="unset_struct" type="(idsogayasaoag)" access="readwrite"/>
|
||
|
</interface> <!-- End org.project.Bar -->
|
||
|
|
||
|
<!-- Namespaced -->
|
||
|
<interface name="org.project.Bar.Frobnicator">
|
||
|
<method name="RandomMethod"/>
|
||
|
</interface>
|
||
|
|
||
|
<!-- Empty -->
|
||
|
<interface name="org.project.Baz">
|
||
|
</interface>
|
||
|
|
||
|
<!-- Outside D-Bus prefix -->
|
||
|
<interface name="com.acme.Coyote">
|
||
|
<method name="Run"/>
|
||
|
<method name="Sleep"/>
|
||
|
<method name="Attack"/>
|
||
|
<signal name="Surprised"/>
|
||
|
<property name="Mood" type="s" access="read"/>
|
||
|
--
|
||
|
2.21.0
|
||
|
|