[vala/tintou/gdbus-properties: 227/228] gdbus: Bind properties with the GDBusProxy directly




commit 68e75e6fec05dd8b56462642c4915f0d6b7801c1
Author: Corentin Noël <corentin elementary io>
Date:   Tue Apr 7 23:50:55 2020 +0200

    gdbus: Bind properties with the GDBusProxy directly

 codegen/valagdbusclientmodule.vala | 259 ++++++++++++++++++++++++++++++++++++-
 codegen/valagdbusservermodule.vala | 101 +++++++++++++++
 tests/Makefile.am                  |   1 +
 tests/dbus/properties.test         | 110 ++++++++++++++++
 vala/valasemanticanalyzer.vala     |   5 -
 5 files changed, 470 insertions(+), 6 deletions(-)
---
diff --git a/codegen/valagdbusclientmodule.vala b/codegen/valagdbusclientmodule.vala
index 697b08758..dd39b299d 100644
--- a/codegen/valagdbusclientmodule.vala
+++ b/codegen/valagdbusclientmodule.vala
@@ -210,17 +210,51 @@ public class Vala.GDBusClientModule : GDBusModule {
 
                cfile.add_type_member_definition (define_type);
 
+               generate_properties_enums (iface);
+
                var proxy_class_init = new CCodeFunction (lower_cname + "_class_init", "void");
                proxy_class_init.add_parameter (new CCodeParameter ("klass", cname + "Class*"));
                proxy_class_init.modifiers = CCodeModifiers.STATIC;
                push_function (proxy_class_init);
                var proxy_class = new CCodeFunctionCall (new CCodeIdentifier ("G_DBUS_PROXY_CLASS"));
                proxy_class.add_argument (new CCodeIdentifier ("klass"));
-               ccode.add_assignment (new CCodeMemberAccess.pointer (proxy_class, "g_signal"), new 
CCodeIdentifier (lower_cname + "_g_signal"));
+               ccode.add_declaration ("GDBusProxyClass *", new CCodeVariableDeclarator.zero ("proxy_class", 
proxy_class));
+               var proxy_class_identifier = new CCodeIdentifier ("proxy_class");
+
+               var object_class = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT_CLASS"));
+               object_class.add_argument (new CCodeIdentifier ("klass"));
+               ccode.add_declaration ("GObjectClass *", new CCodeVariableDeclarator.zero ("object_class", 
object_class));
+               var object_class_identifier = new CCodeIdentifier ("object_class");
+
+               ccode.add_assignment (new CCodeMemberAccess.pointer (proxy_class_identifier, "g_signal"), new 
CCodeIdentifier (lower_cname + "_g_signal"));
+               ccode.add_assignment (new CCodeMemberAccess.pointer (proxy_class_identifier, 
"g_properties_changed"), new CCodeIdentifier (lower_cname + "_g_properties_changed"));
+
+               ccode.add_assignment (new CCodeMemberAccess.pointer (object_class_identifier, 
"get_property"), new CCodeIdentifier (lower_cname + "_get_property"));
+               ccode.add_assignment (new CCodeMemberAccess.pointer (object_class_identifier, 
"set_property"), new CCodeIdentifier (lower_cname + "_set_property"));
+
+               var sym_name = get_ccode_upper_case_name (iface) + "_PROXY";
+               var pspecs = new CCodeIdentifier ("%s_proxy_properties".printf (get_ccode_lower_case_name 
(iface)));
+               foreach (Property prop in iface.get_properties ()) {
+                       var upper_identifier = new CCodeIdentifier ("%s_%s_PROPERTY".printf (sym_name, 
Symbol.camel_case_to_lower_case (prop.name).ascii_up ()));
+                       var override_func = new CCodeFunctionCall (new CCodeIdentifier 
("g_object_class_override_property"));
+                       override_func.add_argument (object_class_identifier);
+                       override_func.add_argument (upper_identifier);
+                       override_func.add_argument (get_property_canonical_cconstant (prop));
+                       ccode.add_expression (override_func);
+                       var find_prop = new CCodeFunctionCall (new CCodeIdentifier 
("g_object_class_find_property"));
+                       find_prop.add_argument (object_class_identifier);
+                       find_prop.add_argument (get_property_canonical_cconstant (prop));
+                       ccode.add_assignment (new CCodeElementAccess (pspecs, upper_identifier), find_prop);
+               }
+
                pop_function ();
                cfile.add_function (proxy_class_init);
 
+               generate_pspec_from_dbus_property (iface);
+               generate_get_property_function (iface);
+               generate_set_property_function (iface);
                generate_signal_handler_function (iface);
+               generate_properties_changed_handler_function (iface);
 
                if (in_plugin) {
                        var proxy_class_finalize = new CCodeFunction (lower_cname + "_class_finalize", 
"void");
@@ -506,6 +540,117 @@ public class Vala.GDBusClientModule : GDBusModule {
                return wrapper_name;
        }
 
+       void generate_properties_enums (ObjectTypeSymbol sym) {
+               var prop_enum = new CCodeEnum ();
+               var sym_name = get_ccode_upper_case_name (sym) + "_PROXY";
+               prop_enum.add_value (new CCodeEnumValue ("%s_0_PROPERTY".printf (sym_name)));
+               var properties = sym.get_properties ();
+               foreach (Property prop in properties) {
+                          prop_enum.add_value (new CCodeEnumValue ("%s_%s_PROPERTY".printf (sym_name, 
Symbol.camel_case_to_lower_case (prop.name).ascii_up ())));
+               }
+
+               var last_prop = "%s_NUM_PROPERTIES".printf (sym_name);
+               prop_enum.add_value (new CCodeEnumValue (last_prop));
+               cfile.add_type_declaration (prop_enum);
+
+               var prop_array_decl = new CCodeDeclaration ("GParamSpec*");
+               prop_array_decl.modifiers |= CCodeModifiers.STATIC;
+               prop_array_decl.add_declarator (new CCodeVariableDeclarator ("%s_proxy_properties".printf 
(get_ccode_lower_case_name (sym)), null, new CCodeDeclaratorSuffix.with_array (new CCodeIdentifier 
(last_prop))));
+               cfile.add_type_declaration (prop_array_decl);
+       }
+
+       void generate_get_property_function (ObjectTypeSymbol sym) {
+               var cfunc = new CCodeFunction (get_ccode_lower_case_prefix (sym) + "proxy_get_property", 
"void");
+               cfunc.add_parameter (new CCodeParameter ("object", "GObject*"));
+               cfunc.add_parameter (new CCodeParameter ("property_id", "guint"));
+               cfunc.add_parameter (new CCodeParameter ("value", "GValue*"));
+               cfunc.add_parameter (new CCodeParameter ("pspec", "GParamSpec*"));
+
+               cfunc.modifiers |= CCodeModifiers.STATIC;
+
+               cfile.add_function_declaration (cfunc);
+
+               push_function (cfunc);
+
+               ccode.add_declaration ("%s *".printf (get_ccode_name (sym)), new CCodeVariableDeclarator 
("self"));
+               ccode.add_declaration ("GVariant *", new CCodeVariableDeclarator ("variant", null));
+               ccode.add_declaration ("const gchar *", new CCodeVariableDeclarator.zero 
("dbus_property_name", new CCodeConstant ("NULL")));
+
+               var cast_call = generate_instance_cast (new CCodeIdentifier ("object"), sym);
+               ccode.add_assignment (new CCodeIdentifier ("self"), cast_call);
+
+               ccode.open_switch (new CCodeIdentifier ("property_id"));
+
+               var sym_name = get_ccode_upper_case_name (sym) + "_PROXY";
+               var dbus_proxy_cast = new CCodeFunctionCall (new CCodeIdentifier ("G_DBUS_PROXY"));
+               dbus_proxy_cast.add_argument (new CCodeIdentifier ("object"));
+               foreach (Property prop in sym.get_properties ()) {
+                       if (prop.access != SymbolAccessibility.PUBLIC) {
+                               continue;
+                       }
+
+                       var upper_identifier = new CCodeIdentifier ("%s_%s_PROPERTY".printf (sym_name, 
Symbol.camel_case_to_lower_case (prop.name).ascii_up ()));
+                       ccode.add_case (upper_identifier);
+
+                       string proxy_name = "%sdbus_proxy_get_%s".printf (get_ccode_lower_case_prefix (sym), 
prop.name);
+                       property_to_value (prop, new CCodeIdentifier (proxy_name), new CCodeIdentifier 
("self"));
+
+                       ccode.add_break ();
+               }
+
+               ccode.add_default ();
+               ccode.add_statement (new CCodeReturnStatement (null));
+               ccode.close ();
+
+               pop_function ();
+
+               cfile.add_function (cfunc);
+       }
+
+       void generate_set_property_function (ObjectTypeSymbol sym) {
+               // Create the function
+               var cfunc = new CCodeFunction (get_ccode_lower_case_prefix (sym) + "proxy_set_property", 
"void");
+               cfunc.add_parameter (new CCodeParameter ("object", "GObject*"));
+               cfunc.add_parameter (new CCodeParameter ("property_id", "guint"));
+               cfunc.add_parameter (new CCodeParameter ("value", "const GValue*"));
+               cfunc.add_parameter (new CCodeParameter ("pspec", "GParamSpec*"));
+
+               cfunc.modifiers |= CCodeModifiers.STATIC;
+
+               cfile.add_function_declaration (cfunc);
+
+               push_function (cfunc);
+
+               var cast_call = generate_instance_cast (new CCodeIdentifier ("object"), sym);
+               ccode.add_declaration ("%s *".printf (get_ccode_name (sym)), new CCodeVariableDeclarator 
("self"));
+               ccode.add_assignment (new CCodeIdentifier ("self"), cast_call);
+
+               ccode.open_switch (new CCodeIdentifier ("property_id"));
+
+               var sym_name = get_ccode_upper_case_name (sym) + "_PROXY";
+               foreach (Property prop in sym.get_properties ()) {
+                       if (prop.access != SymbolAccessibility.PUBLIC) {
+                               continue;
+                       }
+
+                       var upper_identifier = new CCodeIdentifier ("%s_%s_PROPERTY".printf (sym_name, 
Symbol.camel_case_to_lower_case (prop.name).ascii_up ()));
+                       ccode.add_case (upper_identifier);
+
+                       string proxy_name = "%sdbus_proxy_set_%s".printf (get_ccode_lower_case_prefix (sym), 
prop.name);
+                       property_from_value (prop, new CCodeIdentifier (proxy_name), new CCodeIdentifier 
("self"));
+
+                       ccode.add_break ();
+               }
+
+               ccode.add_default ();
+               ccode.add_statement (new CCodeReturnStatement (null));
+               ccode.close ();
+
+               pop_function ();
+
+               cfile.add_function (cfunc);
+       }
+
        void generate_signal_handler_function (ObjectTypeSymbol sym) {
                var cfunc = new CCodeFunction (get_ccode_lower_case_prefix (sym) + "proxy_g_signal", "void");
                cfunc.add_parameter (new CCodeParameter ("proxy", "GDBusProxy*"));
@@ -555,6 +700,118 @@ public class Vala.GDBusClientModule : GDBusModule {
                cfile.add_function (cfunc);
        }
 
+       void generate_pspec_from_dbus_property (ObjectTypeSymbol sym) {
+               var cfunc = new CCodeFunction ("_vala_%sfind_property_from_dbus_name".printf 
(get_ccode_lower_case_prefix (sym)), "GParamSpec *");
+               cfunc.add_parameter (new CCodeParameter ("dbus_property_name", "const gchar *"));
+               cfunc.modifiers |= CCodeModifiers.STATIC;
+               
+               cfile.add_function_declaration (cfunc);
+               
+               push_function (cfunc);
+               
+               bool firstif = true;
+
+               var pspecs = new CCodeIdentifier ("%s_proxy_properties".printf (get_ccode_lower_case_name 
(sym)));
+               var sym_name = get_ccode_upper_case_name (sym) + "_PROXY";
+               foreach (Property prop in sym.get_properties ()) {
+                       if (prop.access != SymbolAccessibility.PUBLIC) {
+                               continue;
+                       }
+
+                       var ccheck = new CCodeFunctionCall (new CCodeIdentifier ("g_strcmp0"));
+                       ccheck.add_argument (new CCodeIdentifier ("dbus_property_name"));
+                       ccheck.add_argument (new CCodeConstant ("\"%s\"".printf (get_dbus_name_for_member 
(prop))));
+
+                       var cond = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, ccheck, new 
CCodeConstant ("0"));
+                       if (firstif) {
+                               ccode.open_if (cond);
+                               firstif = false;
+                       } else {
+                               ccode.else_if (cond);
+                       }
+
+                       var upper_identifier = new CCodeIdentifier ("%s_%s_PROPERTY".printf (sym_name, 
Symbol.camel_case_to_lower_case (prop.name).ascii_up ()));
+                       ccode.add_statement (new CCodeReturnStatement (new CCodeElementAccess (pspecs, 
upper_identifier)));
+               }
+
+               if (!firstif) {
+                       ccode.close ();
+               }
+
+               ccode.add_statement (new CCodeReturnStatement (new CCodeConstant ("NULL")));
+               
+               pop_function ();
+               cfile.add_function (cfunc);
+       }
+
+       void generate_properties_changed_handler_function (ObjectTypeSymbol sym) {
+               var cfunc = new CCodeFunction (get_ccode_lower_case_prefix (sym) + 
"proxy_g_properties_changed", "void");
+               cfunc.add_parameter (new CCodeParameter ("proxy", "GDBusProxy*"));
+               cfunc.add_parameter (new CCodeParameter ("changed_properties", "GVariant*"));
+               cfunc.add_parameter (new CCodeParameter ("invalidated_properties", "const gchar* const*"));
+
+               cfunc.modifiers |= CCodeModifiers.STATIC;
+
+               cfile.add_function_declaration (cfunc);
+
+               push_function (cfunc);
+
+               ccode.add_declaration ("GVariantIter *", new CCodeVariableDeclarator ("iter", null));
+               ccode.add_declaration ("const gchar *", new CCodeVariableDeclarator ("key", null));
+               ccode.add_declaration ("GParamSpec *", new CCodeVariableDeclarator ("pspec", null));
+               ccode.add_declaration ("guint", new CCodeVariableDeclarator ("n", null));
+               var pspec_identifier = new CCodeIdentifier ("pspec");
+               var n_identifier = new CCodeIdentifier ("n");
+               var variant_get = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_get"));
+               variant_get.add_argument (new CCodeIdentifier ("changed_properties"));
+               variant_get.add_argument (new CCodeConstant.string ("\"a{sv}\""));
+               variant_get.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new 
CCodeIdentifier ("iter")));
+               ccode.add_expression (variant_get);
+
+               var variant_iter_next = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_iter_next"));
+               variant_iter_next.add_argument (new CCodeIdentifier ("iter"));
+               variant_iter_next.add_argument (new CCodeConstant.string ("\"{&sv}\""));
+               variant_iter_next.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new 
CCodeIdentifier ("key")));
+               variant_iter_next.add_argument (new CCodeConstant ("NULL"));
+
+               ccode.open_while (variant_iter_next);
+               var find_property_from_dbus_name = new CCodeFunctionCall (new CCodeIdentifier 
("_vala_%sfind_property_from_dbus_name".printf (get_ccode_lower_case_prefix (sym))));
+               find_property_from_dbus_name.add_argument (new CCodeIdentifier ("key"));
+               ccode.add_assignment (pspec_identifier, find_property_from_dbus_name);
+
+               ccode.open_if (new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, pspec_identifier, 
new CCodeConstant ("NULL")));
+
+               var notify_by_pspec = new CCodeFunctionCall (new CCodeIdentifier 
("g_object_notify_by_pspec"));
+               notify_by_pspec.add_argument (new CCodeCastExpression (new CCodeIdentifier ("proxy"), 
"GObject *"));
+               notify_by_pspec.add_argument (pspec_identifier);
+               ccode.add_expression (notify_by_pspec);
+
+               ccode.close ();
+               ccode.close ();
+
+               var variant_iter_free = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_iter_free"));
+               variant_iter_free.add_argument (new CCodeIdentifier ("iter"));
+               ccode.add_expression (variant_iter_free);
+
+               var for_init = new CCodeAssignment (n_identifier, new CCodeConstant ("0"));
+               var for_increment = new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, 
n_identifier);
+               var for_condition = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new 
CCodeElementAccess (new CCodeIdentifier ("invalidated_properties"), n_identifier), new CCodeConstant 
("NULL"));
+               ccode.open_for (for_init, for_condition, for_increment);
+               var find_invalidated_property_from_dbus_name = new CCodeFunctionCall (new CCodeIdentifier 
("_vala_%sfind_property_from_dbus_name".printf (get_ccode_lower_case_prefix (sym))));
+               find_invalidated_property_from_dbus_name.add_argument (new CCodeElementAccess (new 
CCodeIdentifier ("invalidated_properties"), n_identifier));
+               ccode.add_assignment (pspec_identifier, find_invalidated_property_from_dbus_name);
+
+               ccode.open_if (new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, pspec_identifier, 
new CCodeConstant ("NULL")));
+               ccode.add_expression (notify_by_pspec);
+               ccode.close ();
+               ccode.close ();
+
+               pop_function ();
+
+               cfile.add_function (cfunc);
+       }
+
+
        void generate_marshalling (Method m, CallType call_type, string? iface_name, string? method_name, int 
method_timeout) {
                var gdbusproxy = new CCodeCastExpression (new CCodeIdentifier ("self"), "GDBusProxy *");
 
diff --git a/codegen/valagdbusservermodule.vala b/codegen/valagdbusservermodule.vala
index e6f379c9f..99f1812e5 100644
--- a/codegen/valagdbusservermodule.vala
+++ b/codegen/valagdbusservermodule.vala
@@ -712,6 +712,105 @@ public class Vala.GDBusServerModule : GDBusClientModule {
                }
        }
 
+       void generate_property_notify (ObjectTypeSymbol sym, Property prop) {
+               var cfunc = new CCodeFunction ("_%snotify_%s".printf (get_ccode_lower_case_prefix (sym), 
prop.name), "void");
+               cfunc.add_parameter (new CCodeParameter ("gobject", "GObject *"));
+               cfunc.add_parameter (new CCodeParameter ("pspec", "GParamSpec *"));
+               cfunc.add_parameter (new CCodeParameter ("user_data", "gpointer"));
+
+               cfunc.modifiers |= CCodeModifiers.STATIC;
+
+               push_function (cfunc);
+
+               ccode.add_declaration ("gpointer*", new CCodeVariableDeclarator.zero ("data", new 
CCodeIdentifier ("user_data")));
+               ccode.add_declaration ("GError*", new CCodeVariableDeclarator.zero ("error", new 
CCodeConstant ("NULL")));
+               ccode.add_declaration ("GVariant*", new CCodeVariableDeclarator.zero ("parameters", new 
CCodeConstant ("NULL")));
+               ccode.add_declaration ("GVariant*", new CCodeVariableDeclarator.zero ("variant", new 
CCodeConstant ("NULL")));
+               ccode.add_declaration ("GVariantBuilder", new CCodeVariableDeclarator ("changed_builder", 
null));
+               ccode.add_declaration ("GVariantBuilder", new CCodeVariableDeclarator ("invalidated_builder", 
null));
+
+               var variant_builder_init = new CCodeFunctionCall (new CCodeIdentifier 
("g_variant_builder_init"));
+               variant_builder_init.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, 
new CCodeIdentifier ("changed_builder")));
+               variant_builder_init.add_argument (new CCodeConstant ("G_VARIANT_TYPE_VARDICT"));
+               ccode.add_expression (variant_builder_init);
+
+               var variant_builder_init2 = new CCodeFunctionCall (new CCodeIdentifier 
("g_variant_builder_init"));
+               variant_builder_init2.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, 
new CCodeIdentifier ("invalidated_builder")));
+               variant_builder_init2.add_argument (new CCodeConstant ("G_VARIANT_TYPE_STRING_ARRAY"));
+               ccode.add_expression (variant_builder_init2);
+
+               var cast_call = generate_instance_cast (new CCodeIdentifier ("gobject"), sym);
+               ccode.add_declaration ("%s *".printf (get_ccode_name (sym)), new CCodeVariableDeclarator 
("self"));
+               ccode.add_assignment (new CCodeIdentifier ("self"), cast_call);
+
+               var dbus_get_property = new CCodeFunctionCall (new CCodeIdentifier ("_dbus_%s".printf 
(get_ccode_name (prop.get_accessor))));
+               dbus_get_property.add_argument (new CCodeIdentifier ("self"));
+               ccode.add_assignment (new CCodeIdentifier ("variant"), dbus_get_property);
+
+               var variant_builder_add = new CCodeFunctionCall (new CCodeIdentifier 
("g_variant_builder_add"));
+               variant_builder_add.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, 
new CCodeIdentifier ("changed_builder")));
+               variant_builder_add.add_argument (new CCodeConstant.string ("\"{sv}\""));
+               variant_builder_add.add_argument (new CCodeConstant.string ("\"%s\"".printf 
(get_dbus_name_for_member (prop))));
+               variant_builder_add.add_argument (new CCodeIdentifier ("variant"));
+               ccode.add_expression (variant_builder_add);
+
+               var variant_new = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_new"));
+               variant_new.add_argument (new CCodeConstant.string ("\"(sa{sv}as)\""));
+               variant_new.add_argument (new CCodeConstant.string ("\"%s\"".printf (get_dbus_name (sym))));
+               variant_new.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new 
CCodeIdentifier ("changed_builder")));
+               variant_new.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new 
CCodeIdentifier ("invalidated_builder")));
+               ccode.add_assignment (new CCodeIdentifier ("parameters"), variant_new);
+
+               var disconnect_call = new CCodeFunctionCall (new CCodeIdentifier 
("g_dbus_connection_emit_signal"));
+               disconnect_call.add_argument (new CCodeCastExpression (new CCodeElementAccess (new 
CCodeIdentifier ("data"), new CCodeConstant ("1")), "GDBusConnection *"));
+               disconnect_call.add_argument (new CCodeConstant ("NULL"));
+               disconnect_call.add_argument (new CCodeCastExpression (new CCodeElementAccess (new 
CCodeIdentifier ("data"), new CCodeConstant ("2")), "const gchar *"));
+               disconnect_call.add_argument (new CCodeConstant.string 
("\"org.freedesktop.DBus.Properties\""));
+               disconnect_call.add_argument (new CCodeConstant.string ("\"PropertiesChanged\""));
+               disconnect_call.add_argument (new CCodeIdentifier ("parameters"));
+               disconnect_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new 
CCodeIdentifier ("error")));
+               ccode.add_expression (disconnect_call);
+
+               pop_function ();
+
+               cfile.add_function_declaration (cfunc);
+               cfile.add_function (cfunc);
+       }
+
+       void handle_properties (ObjectTypeSymbol sym, bool connect) {
+               string dbus_iface_name = get_dbus_name (sym);
+               if (dbus_iface_name == null) {
+                       return;
+               }
+
+               foreach (Property prop in sym.get_properties ()) {
+                       if (prop.access != SymbolAccessibility.PUBLIC) {
+                               continue;
+                       }
+                       if (!is_dbus_visible (prop)) {
+                               continue;
+                       }
+
+                       var notify_name = "_%snotify_%s".printf (get_ccode_lower_case_prefix (sym), 
prop.name);
+                       if (connect) {
+                               generate_property_notify (sym, prop);
+                               var connect_call = new CCodeFunctionCall (new CCodeIdentifier 
("g_signal_connect"));
+                               connect_call.add_argument (new CCodeIdentifier ("object"));
+                               connect_call.add_argument (new CCodeConstant.string ("\"notify::%s\"".printf 
(get_ccode_name (prop))));
+                               connect_call.add_argument (new CCodeCastExpression (new CCodeIdentifier 
(notify_name), "GCallback"));
+                               connect_call.add_argument (new CCodeIdentifier ("data"));
+                               ccode.add_expression (connect_call);
+                       } else {
+                               // disconnect the signals
+                               var disconnect_call = new CCodeFunctionCall (new CCodeIdentifier 
("g_signal_handlers_disconnect_by_func"));
+                               disconnect_call.add_argument (new CCodeElementAccess (new CCodeIdentifier 
("data"), new CCodeConstant ("0")));
+                               disconnect_call.add_argument (new CCodeIdentifier (notify_name));
+                               disconnect_call.add_argument (new CCodeIdentifier ("data"));
+                               ccode.add_expression (disconnect_call);
+                       }
+               }
+       }
+
        void generate_interface_method_call_function (ObjectTypeSymbol sym) {
                var cfunc = new CCodeFunction (get_ccode_lower_case_prefix (sym) + 
"dbus_interface_method_call", "void");
                cfunc.add_parameter (new CCodeParameter ("connection", "GDBusConnection*"));
@@ -1165,6 +1264,7 @@ public class Vala.GDBusServerModule : GDBusClientModule {
                ccode.close ();
 
                handle_signals (sym, true);
+               handle_properties (sym, true);
 
                ccode.add_return (new CCodeIdentifier ("result"));
 
@@ -1181,6 +1281,7 @@ public class Vala.GDBusServerModule : GDBusClientModule {
                ccode.add_declaration ("gpointer*", new CCodeVariableDeclarator ("data", new CCodeIdentifier 
("user_data")));
 
                handle_signals (sym, false);
+               handle_properties (sym, false);
 
                var unref_object = new CCodeFunctionCall (new CCodeIdentifier (get_ccode_unref_function 
(sym)));
                unref_object.add_argument (new CCodeElementAccess (new CCodeIdentifier ("data"), new 
CCodeConstant ("0")));
diff --git a/tests/Makefile.am b/tests/Makefile.am
index f0ec0e9c4..2ead6682e 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -730,6 +730,7 @@ TESTS = \
        dbus/enum-string-marshalling.vala \
        dbus/generics.test \
        dbus/no-reply.test \
+       dbus/properties.test \
        dbus/signals.test \
        dbus/filedescriptor.test \
        dbus/filedescriptor-async.test \
diff --git a/tests/dbus/properties.test b/tests/dbus/properties.test
new file mode 100644
index 000000000..46358a34b
--- /dev/null
+++ b/tests/dbus/properties.test
@@ -0,0 +1,110 @@
+Packages: gio-2.0
+D-Bus
+
+Program: client
+
+[DBus (name = "org.example.Test")]
+interface Test : Object {
+       public abstract string test_property { owned get; set; }
+       public abstract int test_int_property { get; set; }
+       public abstract void change_everything () throws GLib.Error;
+       public abstract void check_everything () throws GLib.Error;
+}
+
+class Test2 : Object {
+       public string test_property { get; set; }
+       public int test_int_property { get; set; }
+}
+
+void main () {
+       // client
+       Test test = Bus.get_proxy_sync (BusType.SESSION, "org.example.Test", "/org/example/test", 
DBusProxyFlags.NONE);
+       assert (test.test_property == "foo");
+       assert (test.test_int_property == 17);
+
+       Test2 test2 = new Test2 ();
+       test.bind_property ("test-property", test2, "test-property", BindingFlags.SYNC_CREATE | 
BindingFlags.BIDIRECTIONAL);
+       test.bind_property ("test-int-property", test2, "test-int-property", BindingFlags.SYNC_CREATE | 
BindingFlags.BIDIRECTIONAL);
+
+       {
+               MainLoop main_loop = new MainLoop ();
+
+               assert (test2.test_property == "foo");
+               assert (test2.test_int_property == 17);
+
+               test2.notify["test-int-property"].connect ((p) => {
+                       assert (((ParamSpecInt) p).name == "test-int-property");
+                       main_loop.quit ();
+               });
+
+               test.change_everything ();
+               main_loop.run ();
+
+               assert (test.test_property == "bar");
+               assert (test.test_int_property == 53);
+       }
+       {
+               MainLoop main_loop2 = new MainLoop ();
+
+               assert (test2.test_property == "bar");
+               assert (test2.test_int_property == 53);
+
+               test.notify["test-property"].connect ((p) => {
+                       assert (((ParamSpecString) p).name == "test-property");
+                       main_loop2.quit ();
+               });
+
+               test2.test_property = "baz";
+               test2.test_int_property = 765;
+               main_loop2.run ();
+
+               assert (test2.test_property == "baz");
+               assert (test2.test_int_property == 765);
+
+               test.check_everything ();
+       }
+}
+
+Program: server
+
+[DBus (name = "org.example.Test")]
+class Test : Object {
+       public string test_property { owned get; set; default = "foo";}
+       public int test_int_property { get; set; default = 17; }
+
+       public void change_everything () throws GLib.Error {
+               test_property = "bar";
+               test_int_property = 53;
+       }
+
+       public void check_everything () throws GLib.Error {
+               assert (test_property == "baz");
+               assert (test_int_property == 765);
+       }
+}
+
+MainLoop main_loop;
+
+void client_exit (Pid pid, int status) {
+       // client finished, terminate server
+       assert (status == 0);
+       main_loop.quit ();
+}
+
+void main () {
+       var conn = Bus.get_sync (BusType.SESSION);
+       conn.register_object ("/org/example/test", new Test ());
+
+       // try to register service in session bus
+       var request_result = conn.call_sync ("org.freedesktop.DBus", "/org/freedesktop/DBus", 
"org.freedesktop.DBus", "RequestName",
+                                             new Variant ("(su)", "org.example.Test", 0x4), null, 0, -1);
+       assert ((uint) request_result.get_child_value (0) == 1);
+
+       // server ready, spawn client
+       Pid client_pid;
+       Process.spawn_async (null, { "dbus_properties_client" }, null, SpawnFlags.DO_NOT_REAP_CHILD, null, 
out client_pid);
+       ChildWatch.add (client_pid, client_exit);
+
+       main_loop = new MainLoop ();
+       main_loop.run ();
+}
diff --git a/vala/valasemanticanalyzer.vala b/vala/valasemanticanalyzer.vala
index 553695568..c18304457 100644
--- a/vala/valasemanticanalyzer.vala
+++ b/vala/valasemanticanalyzer.vala
@@ -473,11 +473,6 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
                        return false;
                }
 
-               if (type_sym is Interface && type_sym.get_attribute ("DBus") != null) {
-                       // GObject properties not currently supported in D-Bus interfaces
-                       return false;
-               }
-
                return true;
        }
 


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