From: Jürg Billeter Date: Fri, 21 Nov 2008 17:04:02 +0000 (+0000) Subject: Add partial static D-Bus client support without dbus-glib marshalling X-Git-Tag: VALA_0_5_2~61 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=2e199eda13c0673d51cdead9721d2516384703fc;p=thirdparty%2Fvala.git Add partial static D-Bus client support without dbus-glib marshalling 2008-11-21 Jürg Billeter * gobject/Makefile.am: * gobject/valaccodebasemodule.vala: * gobject/valadbusclientmodule.vala: * gobject/valadbusmodule.vala: * vapi/dbus-glib-1.vapi: Add partial static D-Bus client support without dbus-glib marshalling svn path=/trunk/; revision=2050 --- diff --git a/ChangeLog b/ChangeLog index 9eed02e71..21acd3b9a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +2008-11-21 Jürg Billeter + + * gobject/Makefile.am: + * gobject/valaccodebasemodule.vala: + * gobject/valadbusclientmodule.vala: + * gobject/valadbusmodule.vala: + * vapi/dbus-glib-1.vapi: + + Add partial static D-Bus client support without dbus-glib + marshalling + 2008-11-21 Jürg Billeter * vapi/glib-2.0.vapi: diff --git a/gobject/Makefile.am b/gobject/Makefile.am index 9f6bc18ae..1770ed36f 100644 --- a/gobject/Makefile.am +++ b/gobject/Makefile.am @@ -26,6 +26,7 @@ libvala_la_VALASOURCES = \ valaccodestructmodule.vala \ valaclassregisterfunction.vala \ valadbusclientmodule.vala \ + valadbusmodule.vala \ valadbusservermodule.vala \ valagerrormodule.vala \ valagirwriter.vala \ diff --git a/gobject/valaccodebasemodule.vala b/gobject/valaccodebasemodule.vala index 2026f167a..752671bde 100644 --- a/gobject/valaccodebasemodule.vala +++ b/gobject/valaccodebasemodule.vala @@ -133,6 +133,7 @@ public class Vala.CCodeBaseModule : CCodeModule { public bool requires_array_move; public bool requires_strcmp0; public bool dbus_glib_h_needed; + public bool dbus_glib_h_needed_in_header; public Set wrappers; @@ -282,6 +283,7 @@ public class Vala.CCodeBaseModule : CCodeModule { gvaluecollector_h_needed = false; gio_h_needed = false; dbus_glib_h_needed = false; + dbus_glib_h_needed_in_header = false; requires_free_checked = false; requires_array_free = false; requires_array_move = false; @@ -384,7 +386,9 @@ public class Vala.CCodeBaseModule : CCodeModule { header_begin.append (new CCodeIncludeDirective ("gio/gio.h")); } - if (dbus_glib_h_needed) { + if (dbus_glib_h_needed_in_header) { + header_begin.append (new CCodeIncludeDirective ("dbus/dbus-glib.h")); + } else if (dbus_glib_h_needed) { source_include_directives.append (new CCodeIncludeDirective ("dbus/dbus-glib.h")); } diff --git a/gobject/valadbusclientmodule.vala b/gobject/valadbusclientmodule.vala index 753806855..45dffb57b 100644 --- a/gobject/valadbusclientmodule.vala +++ b/gobject/valadbusclientmodule.vala @@ -28,7 +28,7 @@ using Gee; /** * The link between a dynamic method and generated code. */ -public class Vala.DBusClientModule : GAsyncModule { +public class Vala.DBusClientModule : DBusModule { int dynamic_property_id; public DBusClientModule (CCodeGenerator codegen, CCodeModule? next) { @@ -821,4 +821,264 @@ public class Vala.DBusClientModule : GAsyncModule { call.add_argument (new CCodeIdentifier ("data")); block.add_statement (new CCodeExpressionStatement (call)); } + + public override void visit_cast_expression (CastExpression expr) { + // handles casting DBus.Object instances to DBus interfaces + + var type = expr.type_reference as ObjectType; + var call = expr.inner as MethodCall; + if (type == null || !(type.type_symbol is Interface) + || type.type_symbol.get_attribute ("DBus") == null || call == null) { + base.visit_cast_expression (expr); + return; + } + + var mtype = call.call.value_type as MethodType; + if (mtype == null || mtype.method_symbol.get_cname () != "dbus_g_proxy_new_for_name") { + base.visit_cast_expression (expr); + return; + } + + var args = call.get_argument_list (); + Expression connection = ((MemberAccess) call.call).inner; + Expression bus_name = args.get (0); + Expression object_path = args.get (1); + + var ccall = new CCodeFunctionCall (new CCodeIdentifier (type.type_symbol.get_lower_case_cprefix () + "dbus_proxy_new")); + connection.accept (codegen); + ccall.add_argument ((CCodeExpression) connection.ccodenode); + bus_name.accept (codegen); + ccall.add_argument ((CCodeExpression) bus_name.ccodenode); + object_path.accept (codegen); + ccall.add_argument ((CCodeExpression) object_path.ccodenode); + expr.ccodenode = ccall; + } + + public override void visit_interface (Interface iface) { + base.visit_interface (iface); + + var dbus = iface.get_attribute ("DBus"); + if (dbus == null) { + return; + } + string dbus_iface_name = dbus.get_string ("name"); + if (dbus_iface_name == null) { + return; + } + + // create proxy class + string cname = iface.get_cname () + "DBusProxy"; + string lower_cname = iface.get_lower_case_cprefix () + "dbus_proxy"; + + CCodeFragment decl_frag; + CCodeFragment def_frag; + CCodeFragment member_decl_frag; + if (iface.access != SymbolAccessibility.PRIVATE) { + decl_frag = header_type_declaration; + def_frag = header_type_definition; + member_decl_frag = header_type_member_declaration; + dbus_glib_h_needed_in_header = true; + } else { + decl_frag = source_type_declaration; + def_frag = source_type_definition; + member_decl_frag = source_type_member_declaration; + dbus_glib_h_needed = true; + } + + source_type_declaration.append (new CCodeTypeDefinition ("DBusGProxy", new CCodeVariableDeclarator (cname))); + source_type_declaration.append (new CCodeTypeDefinition ("DBusGProxyClass", new CCodeVariableDeclarator (cname + "Class"))); + + var implement = new CCodeFunctionCall (new CCodeIdentifier ("G_IMPLEMENT_INTERFACE")); + implement.add_argument (new CCodeIdentifier (iface.get_upper_case_cname ("TYPE_"))); + implement.add_argument (new CCodeIdentifier (lower_cname + "_interface_init")); + + var define_type = new CCodeFunctionCall (new CCodeIdentifier ("G_DEFINE_TYPE_EXTENDED")); + define_type.add_argument (new CCodeIdentifier (cname)); + define_type.add_argument (new CCodeIdentifier (lower_cname)); + define_type.add_argument (new CCodeIdentifier ("DBUS_TYPE_G_PROXY")); + define_type.add_argument (new CCodeConstant ("0")); + define_type.add_argument (implement); + + source_type_member_definition.append (new CCodeExpressionStatement (define_type)); + + var proxy_new = new CCodeFunction (lower_cname + "_new", iface.get_cname () + "*"); + proxy_new.add_parameter (new CCodeFormalParameter ("connection", "DBusGConnection*")); + proxy_new.add_parameter (new CCodeFormalParameter ("name", "const char*")); + proxy_new.add_parameter (new CCodeFormalParameter ("path", "const char*")); + + var new_block = new CCodeBlock (); + + var new_call = new CCodeFunctionCall (new CCodeIdentifier ("g_object_new")); + new_call.add_argument (new CCodeFunctionCall (new CCodeIdentifier (lower_cname + "_get_type"))); + new_call.add_argument (new CCodeConstant ("\"connection\"")); + new_call.add_argument (new CCodeIdentifier ("connection")); + new_call.add_argument (new CCodeConstant ("\"name\"")); + new_call.add_argument (new CCodeIdentifier ("name")); + new_call.add_argument (new CCodeConstant ("\"path\"")); + new_call.add_argument (new CCodeIdentifier ("path")); + new_call.add_argument (new CCodeConstant ("\"interface\"")); + new_call.add_argument (new CCodeConstant ("\"%s\"".printf (dbus_iface_name))); + new_call.add_argument (new CCodeConstant ("NULL")); + + new_block.add_statement (new CCodeReturnStatement (new_call)); + + member_decl_frag.append (proxy_new.copy ()); + proxy_new.block = new_block; + source_type_member_definition.append (proxy_new); + + var proxy_class_init = new CCodeFunction (lower_cname + "_class_init", "void"); + proxy_class_init.add_parameter (new CCodeFormalParameter ("klass", cname + "Class*")); + proxy_class_init.modifiers = CCodeModifiers.STATIC; + proxy_class_init.block = new CCodeBlock (); + source_type_member_definition.append (proxy_class_init); + + var proxy_instance_init = new CCodeFunction (lower_cname + "_init", "void"); + proxy_instance_init.add_parameter (new CCodeFormalParameter ("self", cname + "*")); + proxy_instance_init.modifiers = CCodeModifiers.STATIC; + proxy_instance_init.block = new CCodeBlock (); + source_type_member_definition.append (proxy_instance_init); + + var proxy_iface_init = new CCodeFunction (lower_cname + "_interface_init", "void"); + proxy_iface_init.add_parameter (new CCodeFormalParameter ("iface", iface.get_cname () + "Iface*")); + + var iface_block = new CCodeBlock (); + + foreach (Method m in iface.get_methods ()) { + var vfunc_entry = new CCodeMemberAccess.pointer (new CCodeIdentifier ("iface"), m.vfunc_name); + iface_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (vfunc_entry, new CCodeIdentifier (generate_dbus_proxy_method (iface, m))))); + } + + proxy_iface_init.modifiers = CCodeModifiers.STATIC; + source_type_member_declaration.append (proxy_iface_init.copy ()); + proxy_iface_init.block = iface_block; + source_type_member_definition.append (proxy_iface_init); + } + + string generate_dbus_proxy_method (Interface iface, Method m) { + string proxy_name = "%sdbus_proxy_%s".printf (iface.get_lower_case_cprefix (), m.name); + + string dbus_iface_name = iface.get_attribute ("DBus").get_string ("name"); + + CCodeDeclaration cdecl; + + var function = new CCodeFunction (proxy_name, m.return_type.get_cname ()); + function.modifiers = CCodeModifiers.STATIC; + + var cparam_map = new HashMap (direct_hash, direct_equal); + + var instance_param = new CCodeFormalParameter ("self", iface.get_cname () + "*"); + cparam_map.set (get_param_pos (m.cinstance_parameter_position), instance_param); + + generate_cparameters (m, m.return_type, false, cparam_map, function); + + var block = new CCodeBlock (); + var prefragment = new CCodeFragment (); + var postfragment = new CCodeFragment (); + + cdecl = new CCodeDeclaration ("DBusGConnection"); + cdecl.add_declarator (new CCodeVariableDeclarator ("*_connection")); + block.add_statement (cdecl); + + cdecl = new CCodeDeclaration ("DBusMessage"); + cdecl.add_declarator (new CCodeVariableDeclarator ("*_message")); + cdecl.add_declarator (new CCodeVariableDeclarator ("*_reply")); + block.add_statement (cdecl); + + cdecl = new CCodeDeclaration ("DBusMessageIter"); + cdecl.add_declarator (new CCodeVariableDeclarator ("_iter")); + block.add_statement (cdecl); + + block.add_statement (prefragment); + + var destination = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_proxy_get_bus_name")); + destination.add_argument (new CCodeCastExpression (new CCodeIdentifier ("self"), "DBusGProxy*")); + var path = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_proxy_get_path")); + path.add_argument (new CCodeCastExpression (new CCodeIdentifier ("self"), "DBusGProxy*")); + + var msgcall = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_new_method_call")); + msgcall.add_argument (destination); + msgcall.add_argument (path); + msgcall.add_argument (new CCodeConstant ("\"%s\"".printf (dbus_iface_name))); + msgcall.add_argument (new CCodeConstant ("\"%s\"".printf (Symbol.lower_case_to_camel_case (m.name)))); + prefragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("_message"), msgcall))); + + var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_init_append")); + iter_call.add_argument (new CCodeIdentifier ("_message")); + iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_iter"))); + prefragment.append (new CCodeExpressionStatement (iter_call)); + + iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_init")); + iter_call.add_argument (new CCodeIdentifier ("_reply")); + iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_iter"))); + postfragment.append (new CCodeExpressionStatement (iter_call)); + + foreach (FormalParameter param in m.get_parameters ()) { + if (param.direction == ParameterDirection.IN) { + write_expression (prefragment, param.parameter_type, new CCodeIdentifier ("_iter"), new CCodeIdentifier (param.name)); + } else { + cdecl = new CCodeDeclaration (m.return_type.get_cname ()); + cdecl.add_declarator (new CCodeVariableDeclarator ("_" + param.name)); + block.add_statement (cdecl); + + var target = new CCodeIdentifier ("_" + param.name); + var expr = read_expression (postfragment, param.parameter_type, new CCodeIdentifier ("_iter"), target); + postfragment.append (new CCodeExpressionStatement (new CCodeAssignment (target, expr))); + + // TODO check that parameter is not NULL (out parameters are optional) + // free value if parameter is NULL + postfragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier (param.name)), target))); + } + } + + if (!(m.return_type is VoidType)) { + cdecl = new CCodeDeclaration (m.return_type.get_cname ()); + cdecl.add_declarator (new CCodeVariableDeclarator ("_result")); + block.add_statement (cdecl); + + var target = new CCodeIdentifier ("_result"); + var expr = read_expression (postfragment, m.return_type, new CCodeIdentifier ("_iter"), target); + postfragment.append (new CCodeExpressionStatement (new CCodeAssignment (target, expr))); + } + + var gconnection = new CCodeFunctionCall (new CCodeIdentifier ("g_object_get")); + gconnection.add_argument (new CCodeIdentifier ("self")); + gconnection.add_argument (new CCodeConstant ("\"connection\"")); + gconnection.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_connection"))); + gconnection.add_argument (new CCodeConstant ("NULL")); + block.add_statement (new CCodeExpressionStatement (gconnection)); + + var connection = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_connection_get_connection")); + connection.add_argument (new CCodeIdentifier ("_connection")); + + var ccall = new CCodeFunctionCall (new CCodeIdentifier ("dbus_connection_send_with_reply_and_block")); + ccall.add_argument (connection); + ccall.add_argument (new CCodeIdentifier ("_message")); + ccall.add_argument (new CCodeConstant ("-1")); + ccall.add_argument (new CCodeConstant ("NULL")); + block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("_reply"), ccall))); + + var conn_unref = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_connection_unref")); + conn_unref.add_argument (new CCodeIdentifier ("_connection")); + block.add_statement (new CCodeExpressionStatement (conn_unref)); + + var message_unref = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_unref")); + message_unref.add_argument (new CCodeIdentifier ("_message")); + block.add_statement (new CCodeExpressionStatement (message_unref)); + + block.add_statement (postfragment); + + var reply_unref = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_unref")); + reply_unref.add_argument (new CCodeIdentifier ("_reply")); + block.add_statement (new CCodeExpressionStatement (reply_unref)); + + if (!(m.return_type is VoidType)) { + block.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("_result"))); + } + + source_type_member_declaration.append (function.copy ()); + function.block = block; + source_type_member_definition.append (function); + + return proxy_name; + } } diff --git a/gobject/valadbusmodule.vala b/gobject/valadbusmodule.vala new file mode 100644 index 000000000..d28b34f1f --- /dev/null +++ b/gobject/valadbusmodule.vala @@ -0,0 +1,128 @@ +/* valadbusmodule.vala + * + * Copyright (C) 2008 Jürg Billeter + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Author: + * Jürg Billeter + */ + +public class Vala.DBusModule : GAsyncModule { + struct BasicTypeInfo { + public weak string signature; + public weak string type_name; + public weak string cname; + public weak string gtype; + public weak string? get_value_function; + public weak string set_value_function; + } + + const BasicTypeInfo[] basic_types = { + { "y", "BYTE", "guint8", "G_TYPE_UCHAR", "g_value_get_uchar", "g_value_set_uchar" }, + { "b", "BOOLEAN", "dbus_bool_t", "G_TYPE_BOOLEAN", "g_value_get_boolean", "g_value_set_boolean" }, + { "n", "INT16", "dbus_int16_t", "G_TYPE_INT", null, "g_value_set_int" }, + { "q", "UINT16", "dbus_uint16_t", "G_TYPE_UINT", null, "g_value_set_uint" }, + { "i", "INT32", "dbus_int32_t", "G_TYPE_INT", "g_value_get_int", "g_value_set_int" }, + { "u", "UINT32", "dbus_uint32_t", "G_TYPE_UINT", "g_value_get_uint", "g_value_set_uint" }, + { "x", "INT64", "dbus_int64_t", "G_TYPE_INT64", "g_value_get_int64", "g_value_set_int64" }, + { "t", "UINT64", "dbus_uint64_t", "G_TYPE_UINT64", "g_value_get_uint64", "g_value_set_uint64" }, + { "d", "DOUBLE", "double", "G_TYPE_DOUBLE", "g_value_get_double", "g_value_set_double" }, + { "s", "STRING", "const char*", "G_TYPE_STRING", "g_value_get_string", "g_value_set_string" }, + { "o", "OBJECT_PATH", "const char*", "G_TYPE_STRING", null, "g_value_set_string" }, + { "g", "SIGNATURE", "const char*", "G_TYPE_STRING", null, "g_value_set_string" } + }; + + public DBusModule (CCodeGenerator codegen, CCodeModule? next) { + base (codegen, next); + } + + bool get_basic_type_info (string signature, out BasicTypeInfo basic_type) { + foreach (BasicTypeInfo info in basic_types) { + if (info.signature == signature) { + basic_type = info; + return true; + } + } + return false; + } + + CCodeExpression read_basic (CCodeFragment fragment, BasicTypeInfo basic_type, CCodeExpression iter_expr) { + string temp_name = "_tmp%d".printf (next_temp_var_id++); + + var cdecl = new CCodeDeclaration (basic_type.cname); + cdecl.add_declarator (new CCodeVariableDeclarator (temp_name)); + fragment.append (cdecl); + + var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_get_basic")); + iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, iter_expr)); + iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (temp_name))); + fragment.append (new CCodeExpressionStatement (iter_call)); + + var temp_result = new CCodeIdentifier (temp_name); + + if (basic_type.signature == "s" + || basic_type.signature == "o" + || basic_type.signature == "g") { + var dup_call = new CCodeFunctionCall (new CCodeIdentifier ("g_strdup")); + dup_call.add_argument (temp_result); + return dup_call; + } else { + return temp_result; + } + } + + public CCodeExpression? read_expression (CCodeFragment fragment, DataType type, CCodeExpression iter_expr, CCodeExpression? expr) { + BasicTypeInfo basic_type; + CCodeExpression result = null; + if (get_basic_type_info (type.get_type_signature (), out basic_type)) { + result = read_basic (fragment, basic_type, iter_expr); + } else { + Report.error (type.source_reference, "D-Bus deserialization of type `%s' is not supported".printf (type.to_string ())); + return null; + } + + var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_next")); + iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, iter_expr)); + fragment.append (new CCodeExpressionStatement (iter_call)); + + return result; + } + + void write_basic (CCodeFragment fragment, BasicTypeInfo basic_type, CCodeExpression iter_expr, CCodeExpression expr) { + string temp_name = "_tmp%d".printf (next_temp_var_id++); + + var cdecl = new CCodeDeclaration (basic_type.cname); + cdecl.add_declarator (new CCodeVariableDeclarator (temp_name)); + fragment.append (cdecl); + + fragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier (temp_name), expr))); + + var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_append_basic")); + iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, iter_expr)); + iter_call.add_argument (new CCodeIdentifier ("DBUS_TYPE_" + basic_type.type_name)); + iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (temp_name))); + fragment.append (new CCodeExpressionStatement (iter_call)); + } + + public void write_expression (CCodeFragment fragment, DataType type, CCodeExpression iter_expr, CCodeExpression expr) { + BasicTypeInfo basic_type; + if (get_basic_type_info (type.get_type_signature (), out basic_type)) { + write_basic (fragment, basic_type, iter_expr, expr); + } else { + Report.error (type.source_reference, "D-Bus serialization of type `%s' is not supported".printf (type.to_string ())); + } + } +} diff --git a/vapi/dbus-glib-1.vapi b/vapi/dbus-glib-1.vapi index a333a9754..00901344c 100644 --- a/vapi/dbus-glib-1.vapi +++ b/vapi/dbus-glib-1.vapi @@ -99,7 +99,7 @@ namespace DBus { [CCode (ref_function = "dbus_g_connection_ref", unref_function = "dbus_g_connection_unref", cname = "DBusGConnection")] public class Connection { [CCode (cname = "dbus_g_proxy_new_for_name")] - public Object get_object (string name, string path, string interface_); + public Object get_object (string name, string path, string? interface_ = null); [CCode (cname = "dbus_g_connection_register_g_object")] public void register_object (string at_path, GLib.Object object); [CCode (cname = "dbus_g_connection_lookup_g_object")]