[vala/tintou/gdbus-properties] dbus: Bind properties with the GDBusProxy directly
- From: Corentin Noël <corentinnoel src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [vala/tintou/gdbus-properties] dbus: Bind properties with the GDBusProxy directly
- Date: Sun, 8 Nov 2020 21:56:14 +0000 (UTC)
commit 9a6cc66c8f8630c7711666ccce57562d1b58b557
Author: Corentin Noël <corentin elementary io>
Date: Tue Apr 7 23:50:55 2020 +0200
dbus: Bind properties with the GDBusProxy directly
codegen/valagdbusclientmodule.vala | 414 ++++++++++++++++++++++++++++++++-----
codegen/valagdbusservermodule.vala | 111 ++++++++++
tests/Makefile.am | 1 +
tests/dbus/properties.test | 98 +++++++++
vala/valasemanticanalyzer.vala | 5 -
5 files changed, 567 insertions(+), 62 deletions(-)
---
diff --git a/codegen/valagdbusclientmodule.vala b/codegen/valagdbusclientmodule.vala
index af833f749..3eb55b6ee 100644
--- a/codegen/valagdbusclientmodule.vala
+++ b/codegen/valagdbusclientmodule.vala
@@ -205,17 +205,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");
@@ -501,6 +535,208 @@ 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 ("GVariant *", new CCodeVariableDeclarator ("variant", null));
+ ccode.add_declaration ("const gchar *", new CCodeVariableDeclarator.zero
("dbus_property_name", new CCodeConstant ("NULL")));
+
+ 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);
+ ccode.add_assignment (new CCodeIdentifier ("dbus_property_name"), new
CCodeConstant.string ("\"%s\"".printf (get_dbus_name_for_member (prop))));
+ ccode.add_break ();
+ }
+
+ ccode.add_default ();
+ ccode.add_statement (new CCodeReturnStatement (null));
+ ccode.close ();
+
+ var get_cached_property_function = new CCodeFunctionCall (new CCodeIdentifier
("g_dbus_proxy_get_cached_property"));
+ get_cached_property_function.add_argument (dbus_proxy_cast);
+ get_cached_property_function.add_argument (new CCodeIdentifier ("dbus_property_name"));
+ ccode.add_assignment (new CCodeIdentifier ("variant"), get_cached_property_function);
+
+ ccode.open_if (new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeIdentifier
("variant"), new CCodeConstant ("NULL")));
+
+ var dbus_gvariant_to_gvalue = new CCodeFunctionCall (new CCodeIdentifier
("g_dbus_gvariant_to_gvalue"));
+ dbus_gvariant_to_gvalue.add_argument (new CCodeIdentifier ("variant"));
+ dbus_gvariant_to_gvalue.add_argument (new CCodeIdentifier ("value"));
+ ccode.add_expression (dbus_gvariant_to_gvalue);
+
+ var variant_unref = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_unref"));
+ variant_unref.add_argument (new CCodeIdentifier ("variant"));
+ ccode.add_expression (variant_unref);
+
+ ccode.close ();
+
+ pop_function ();
+
+ cfile.add_function (cfunc);
+ }
+
+ void generate_set_property_function (ObjectTypeSymbol sym) {
+ // Create the async callback
+ var cfunc = new CCodeFunction (get_ccode_lower_case_prefix (sym) + "proxy_set_property_cb",
"void");
+ cfunc.add_parameter (new CCodeParameter ("proxy", "GDBusProxy*"));
+ cfunc.add_parameter (new CCodeParameter ("res", "GAsyncResult*"));
+ cfunc.add_parameter (new CCodeParameter ("user_data", "gpointer"));
+
+ cfunc.modifiers |= CCodeModifiers.STATIC;
+
+ cfile.add_function_declaration (cfunc);
+
+ push_function (cfunc);
+
+ ccode.add_declaration ("GVariant *", new CCodeVariableDeclarator ("_ret", null));
+ ccode.add_declaration ("GError *", new CCodeVariableDeclarator.zero ("error", new
CCodeConstant ("NULL")));
+ ccode.add_declaration ("const gchar *", new CCodeVariableDeclarator.zero
("dbus_property_name", new CCodeIdentifier ("user_data")));
+
+ var ret_variant = new CCodeIdentifier ("_ret");
+ var dbus_proxy_call_finish = new CCodeFunctionCall (new CCodeIdentifier
("g_dbus_proxy_call_finish"));
+ dbus_proxy_call_finish.add_argument (new CCodeIdentifier ("proxy"));
+ dbus_proxy_call_finish.add_argument (new CCodeIdentifier ("res"));
+ dbus_proxy_call_finish.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF,
new CCodeIdentifier ("error")));
+ ccode.add_assignment (ret_variant, dbus_proxy_call_finish);
+
+ ccode.open_if (new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, ret_variant, new
CCodeConstant ("NULL")));
+
+ var quark_to_string = new CCodeFunctionCall (new CCodeIdentifier ("g_quark_to_string"));
+ quark_to_string.add_argument (new CCodeMemberAccess.pointer (new CCodeIdentifier ("error"),
"domain"));
+
+ var warning_call = new CCodeFunctionCall (new CCodeIdentifier ("g_warning"));
+ warning_call.add_argument (new CCodeConstant.string ("\"Error setting property '%%s' on
interface %s: %%s (%%s, %%d)\"".printf (get_dbus_name (sym))));
+ warning_call.add_argument (new CCodeIdentifier ("dbus_property_name"));
+ warning_call.add_argument (new CCodeMemberAccess.pointer (new CCodeIdentifier ("error"),
"message"));
+ warning_call.add_argument (quark_to_string);
+ warning_call.add_argument (new CCodeMemberAccess.pointer (new CCodeIdentifier ("error"),
"code"));
+ ccode.add_expression (warning_call);
+
+ var error_free = new CCodeFunctionCall (new CCodeIdentifier ("g_error_free"));
+ error_free.add_argument (new CCodeIdentifier ("error"));
+ ccode.add_expression (error_free);
+
+ ccode.add_else ();
+ var variant_unref = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_unref"));
+ variant_unref.add_argument (ret_variant);
+ ccode.add_expression (variant_unref);
+ ccode.close ();
+
+ pop_function ();
+
+ cfile.add_function (cfunc);
+
+ // Create the function
+ 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);
+
+ ccode.add_declaration ("GVariant *", new CCodeVariableDeclarator ("variant", null));
+ ccode.add_declaration ("const gchar *", new CCodeVariableDeclarator.zero
("dbus_property_name", new CCodeConstant ("NULL")));
+ ccode.add_declaration ("const GVariantType *", new CCodeVariableDeclarator.zero
("dbus_variant_type", new CCodeConstant ("NULL")));
+
+ 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);
+ ccode.add_assignment (new CCodeIdentifier ("dbus_property_name"), new
CCodeConstant.string ("\"%s\"".printf (get_dbus_name_for_member (prop))));
+ var variant_type_cast = new CCodeFunctionCall (new CCodeIdentifier
("G_VARIANT_TYPE"));
+ variant_type_cast.add_argument (new CCodeConstant.string ("\"%s\"".printf
(prop.property_type.get_type_signature (prop))));
+ ccode.add_assignment (new CCodeIdentifier ("dbus_variant_type"), variant_type_cast);
+ ccode.add_break ();
+ }
+
+ ccode.add_default ();
+ ccode.add_statement (new CCodeReturnStatement (null));
+ ccode.close ();
+
+ var dbus_gvalue_to_gvariant = new CCodeFunctionCall (new CCodeIdentifier
("g_dbus_gvalue_to_gvariant"));
+ dbus_gvalue_to_gvariant.add_argument (new CCodeIdentifier ("value"));
+ dbus_gvalue_to_gvariant.add_argument (new CCodeIdentifier ("dbus_variant_type"));
+ ccode.add_assignment (new CCodeIdentifier ("variant"), dbus_gvalue_to_gvariant);
+
+ var dbus_proxy_cast = new CCodeFunctionCall (new CCodeIdentifier ("G_DBUS_PROXY"));
+ dbus_proxy_cast.add_argument (new CCodeIdentifier ("object"));
+
+ var arg_variant = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_new"));
+ arg_variant.add_argument (new CCodeConstant.string ("\"(ssv)\""));
+ arg_variant.add_argument (new CCodeConstant.string ("\"%s\"".printf (get_dbus_name (sym))));
+ arg_variant.add_argument (new CCodeIdentifier ("dbus_property_name"));
+ arg_variant.add_argument (new CCodeIdentifier ("variant"));
+
+ var callback_cast = new CCodeCastExpression (new CCodeIdentifier (get_ccode_lower_case_prefix
(sym) + "proxy_set_property_cb"), "GAsyncReadyCallback");
+ var dbus_proxy_call = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_proxy_call"));
+ dbus_proxy_call.add_argument (dbus_proxy_cast);
+ dbus_proxy_call.add_argument (new CCodeConstant.string
("\"org.freedesktop.DBus.Properties.Set\""));
+ dbus_proxy_call.add_argument (arg_variant);
+ dbus_proxy_call.add_argument (new CCodeConstant ("G_DBUS_CALL_FLAGS_NONE"));
+ dbus_proxy_call.add_argument (new CCodeConstant ("-1"));
+ dbus_proxy_call.add_argument (new CCodeConstant ("NULL"));
+ dbus_proxy_call.add_argument (callback_cast);
+ dbus_proxy_call.add_argument (new CCodeCastExpression (new CCodeIdentifier
("dbus_property_name"), "gpointer"));
+ ccode.add_expression (dbus_proxy_call);
+
+ variant_unref = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_unref"));
+ variant_unref.add_argument (new CCodeIdentifier ("variant"));
+ ccode.add_expression (variant_unref);
+
+ 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*"));
@@ -550,6 +786,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 *");
@@ -1090,8 +1438,6 @@ public class Vala.GDBusClientModule : GDBusModule {
string generate_dbus_proxy_property_set (Interface main_iface, Interface iface, Property prop) {
string proxy_name = "%sdbus_proxy_set_%s".printf (get_ccode_lower_case_prefix (main_iface),
prop.name);
- string dbus_iface_name = get_dbus_name (iface);
-
var array_type = prop.set_accessor.value_type as ArrayType;
var function = new CCodeFunction (proxy_name);
@@ -1114,60 +1460,14 @@ public class Vala.GDBusClientModule : GDBusModule {
push_function (function);
- ccode.add_declaration ("GVariant", new CCodeVariableDeclarator ("*_arguments"));
- ccode.add_declaration ("GVariant", new CCodeVariableDeclarator ("*_reply"));
-
- ccode.add_declaration ("GVariantBuilder", new CCodeVariableDeclarator ("_arguments_builder"));
-
- var builder_init = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_init"));
- builder_init.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new
CCodeIdentifier ("_arguments_builder")));
- builder_init.add_argument (new CCodeIdentifier ("G_VARIANT_TYPE_TUPLE"));
- ccode.add_expression (builder_init);
-
- // interface name
- write_expression (string_type, new CCodeIdentifier ("_arguments_builder"), new CCodeConstant
("\"%s\"".printf (dbus_iface_name)), null);
- // property name
- write_expression (string_type, new CCodeIdentifier ("_arguments_builder"), new CCodeConstant
("\"%s\"".printf (get_dbus_name_for_member (prop))), null);
-
- // property value (as variant)
- var builder_open = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_open"));
- builder_open.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new
CCodeIdentifier ("_arguments_builder")));
- builder_open.add_argument (new CCodeIdentifier ("G_VARIANT_TYPE_VARIANT"));
- ccode.add_expression (builder_open);
-
- if (prop.property_type.is_real_non_null_struct_type ()) {
- write_expression (prop.set_accessor.value_type, new CCodeIdentifier
("_arguments_builder"), new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier
("value")), prop);
- } else {
- write_expression (prop.set_accessor.value_type, new CCodeIdentifier
("_arguments_builder"), new CCodeIdentifier ("value"), prop);
- }
-
- var builder_close = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_close"));
- builder_close.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new
CCodeIdentifier ("_arguments_builder")));
- ccode.add_expression (builder_close);
-
- var builder_end = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_builder_end"));
- builder_end.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new
CCodeIdentifier ("_arguments_builder")));
- ccode.add_assignment (new CCodeIdentifier ("_arguments"), builder_end);
-
- var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_proxy_call_sync"));
- ccall.add_argument (new CCodeCastExpression (new CCodeIdentifier ("self"), "GDBusProxy *"));
- ccall.add_argument (new CCodeConstant ("\"org.freedesktop.DBus.Properties.Set\""));
- ccall.add_argument (new CCodeIdentifier ("_arguments"));
- ccall.add_argument (new CCodeConstant ("G_DBUS_CALL_FLAGS_NONE"));
- ccall.add_argument (get_dbus_timeout (prop));
- ccall.add_argument (new CCodeConstant ("NULL"));
- ccall.add_argument (new CCodeConstant ("NULL"));
-
- ccode.add_assignment (new CCodeIdentifier ("_reply"), ccall);
-
- // return on error
- ccode.open_if (new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, new
CCodeIdentifier ("_reply")));
- ccode.add_return ();
- ccode.close ();
-
- var unref_reply = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_unref"));
- unref_reply.add_argument (new CCodeIdentifier ("_reply"));
- ccode.add_expression (unref_reply);
+ var object_cast = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT"));
+ object_cast.add_argument (new CCodeIdentifier ("self"));
+ var setter_call = new CCodeFunctionCall (new CCodeIdentifier ("g_object_set"));
+ setter_call.add_argument (object_cast);
+ setter_call.add_argument (get_property_canonical_cconstant (prop));
+ setter_call.add_argument (new CCodeIdentifier ("value"));
+ setter_call.add_argument (new CCodeConstant ("NULL"));
+ ccode.add_expression (setter_call);
pop_function ();
diff --git a/codegen/valagdbusservermodule.vala b/codegen/valagdbusservermodule.vala
index 06166772e..14ec1dae3 100644
--- a/codegen/valagdbusservermodule.vala
+++ b/codegen/valagdbusservermodule.vala
@@ -710,6 +710,115 @@ 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 ("GValue", new CCodeVariableDeclarator.zero ("value", new CCodeConstant
("G_VALUE_INIT")));
+ 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 object_get_property = new CCodeFunctionCall (new CCodeIdentifier
("g_object_get_property"));
+ object_get_property.add_argument (new CCodeIdentifier ("gobject"));
+ object_get_property.add_argument (new CCodeConstant.string ("\"%s\"".printf (get_ccode_name
(prop))));
+ object_get_property.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF,
new CCodeIdentifier ("value")));
+ ccode.add_expression (object_get_property);
+
+ var variant_type_cast = new CCodeFunctionCall (new CCodeIdentifier ("G_VARIANT_TYPE"));
+ variant_type_cast.add_argument (new CCodeConstant.string ("\"%s\"".printf
(prop.property_type.get_type_signature (prop))));
+ var dbus_gvalue_to_gvariant = new CCodeFunctionCall (new CCodeIdentifier
("g_dbus_gvalue_to_gvariant"));
+ dbus_gvalue_to_gvariant.add_argument (new CCodeUnaryExpression
(CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("value")));
+ dbus_gvalue_to_gvariant.add_argument (variant_type_cast);
+ ccode.add_assignment (new CCodeIdentifier ("variant"), dbus_gvalue_to_gvariant);
+
+ 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_unref = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_unref"));
+ variant_unref.add_argument (new CCodeIdentifier ("variant"));
+ ccode.add_expression (variant_unref);
+
+ 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*"));
@@ -1160,6 +1269,7 @@ public class Vala.GDBusServerModule : GDBusClientModule {
ccode.close ();
handle_signals (sym, true);
+ handle_properties (sym, true);
ccode.add_return (new CCodeIdentifier ("result"));
@@ -1176,6 +1286,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 47e9a711b..f1aae0dd8 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -655,6 +655,7 @@ TESTS = \
dbus/connection.test \
dbus/dynamic-method.test \
dbus/enum-string-marshalling.vala \
+ 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..78b2df521
--- /dev/null
+++ b/tests/dbus/properties.test
@@ -0,0 +1,98 @@
+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);
+
+ MainLoop main_loop = new MainLoop ();
+ Test2 test2 = new Test2 ();
+ test.bind_property ("test-property", test2, "test-property",
GLib.BindingFlags.SYNC_CREATE|GLib.BindingFlags.BIDIRECTIONAL);
+ test.bind_property ("test-int-property", test2, "test-int-property",
GLib.BindingFlags.SYNC_CREATE|GLib.BindingFlags.BIDIRECTIONAL);
+
+ assert (test2.test_property == "foo");
+ assert (test2.test_int_property == 17);
+
+ test2.notify["test-int-property"].connect (() => {
+ main_loop.quit ();
+ });
+
+ test.change_everything ();
+ main_loop.run ();
+ assert (test.test_property == "bar");
+ assert (test.test_int_property == 53);
+
+ assert (test2.test_property == "bar");
+ assert (test2.test_int_property == 53);
+
+ test2.test_property = "baz";
+ test2.test_int_property = 765;
+ main_loop = new MainLoop ();
+ main_loop.run ();
+
+ assert (test.test_property == "baz");
+ assert (test.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 2c8db80c0..0232e7abf 100644
--- a/vala/valasemanticanalyzer.vala
+++ b/vala/valasemanticanalyzer.vala
@@ -476,11 +476,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]