From: Luca Bruno Date: Tue, 3 Jan 2012 16:22:35 +0000 (+0100) Subject: GDBus client transformer X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=998f50aa84b5f5976d922ee46dc181aa26a8f41b;p=thirdparty%2Fvala.git GDBus client transformer --- diff --git a/codegen/Makefile.am b/codegen/Makefile.am index b57dc1e62..49421eb45 100644 --- a/codegen/Makefile.am +++ b/codegen/Makefile.am @@ -40,6 +40,7 @@ libvalaccodegen_la_VALASOURCES = \ valaenumregisterfunction.vala \ valagasyncmodule.vala \ valagdbusclientmodule.vala \ + valagdbusclienttransformer.vala \ valagdbusmodule.vala \ valagdbusservermodule.vala \ valagerrormodule.vala \ diff --git a/codegen/valagdbusclientmodule.vala b/codegen/valagdbusclientmodule.vala index 5303975ea..fa135b07a 100644 --- a/codegen/valagdbusclientmodule.vala +++ b/codegen/valagdbusclientmodule.vala @@ -22,24 +22,8 @@ */ public class Vala.GDBusClientModule : GDBusModule { - enum CallType { - SYNC, - ASYNC, - FINISH, - NO_REPLY - } - - public CCodeConstant get_dbus_timeout (Symbol symbol) { - int timeout = -1; - - var dbus = symbol.get_attribute ("DBus"); - if (dbus != null && dbus.has_argument ("timeout")) { - timeout = dbus.get_integer ("timeout"); - } else if (symbol.parent_symbol != null) { - return get_dbus_timeout (symbol.parent_symbol); - } - - return new CCodeConstant (timeout.to_string ()); + CCodeExpression get_interface_info (ObjectTypeSymbol sym) { + return new CCodeIdentifier ("_" + get_ccode_lower_case_prefix (sym) + "dbus_interface_info"); } public override void generate_dynamic_method_wrapper (DynamicMethod method) { @@ -55,7 +39,7 @@ public class Vala.GDBusClientModule : GDBusModule { push_function (func); if (dynamic_method.dynamic_type.data_type == dbus_proxy_type) { - generate_marshalling (method, CallType.SYNC, null, method.name, -1); + //generate_marshalling (method, CallType.SYNC, null, method.name, -1); } else { Report.error (method.source_reference, "dynamic methods are not supported for `%s'".printf (dynamic_method.dynamic_type.to_string ())); } @@ -66,183 +50,6 @@ public class Vala.GDBusClientModule : GDBusModule { cfile.add_function (func); } - void generate_proxy_interface_init (Interface main_iface, Interface iface) { - // also generate proxy for prerequisites - foreach (var prereq in iface.get_prerequisites ()) { - if (prereq.data_type is Interface) { - generate_proxy_interface_init (main_iface, (Interface) prereq.data_type); - } - } - - string lower_cname = get_ccode_lower_case_prefix (main_iface) + "proxy"; - - var proxy_iface_init = new CCodeFunction (lower_cname + "_" + get_ccode_lower_case_prefix (iface) + "interface_init", "void"); - proxy_iface_init.add_parameter (new CCodeParameter ("iface", get_ccode_name (iface) + "Iface*")); - - push_function (proxy_iface_init); - - foreach (Method m in iface.get_methods ()) { - if (!m.is_abstract) { - continue; - } - - var vfunc_entry = new CCodeMemberAccess.pointer (new CCodeIdentifier ("iface"), get_ccode_vfunc_name (m)); - if (!m.coroutine) { - ccode.add_assignment (vfunc_entry, new CCodeIdentifier (generate_dbus_proxy_method (main_iface, iface, m))); - } else { - ccode.add_assignment (vfunc_entry, new CCodeIdentifier (generate_async_dbus_proxy_method (main_iface, iface, m))); - vfunc_entry = new CCodeMemberAccess.pointer (new CCodeIdentifier ("iface"), get_ccode_finish_vfunc_name (m)); - ccode.add_assignment (vfunc_entry, new CCodeIdentifier (generate_finish_dbus_proxy_method (main_iface, iface, m))); - } - } - - foreach (Property prop in iface.get_properties ()) { - if (!prop.is_abstract) { - continue; - } - - if (prop.get_accessor != null) { - var vfunc_entry = new CCodeMemberAccess.pointer (new CCodeIdentifier ("iface"), "get_" + prop.name); - ccode.add_assignment (vfunc_entry, new CCodeIdentifier (generate_dbus_proxy_property_get (main_iface, iface, prop))); - } - if (prop.set_accessor != null) { - var vfunc_entry = new CCodeMemberAccess.pointer (new CCodeIdentifier ("iface"), "set_" + prop.name); - ccode.add_assignment (vfunc_entry, new CCodeIdentifier (generate_dbus_proxy_property_set (main_iface, iface, prop))); - } - } - - proxy_iface_init.modifiers = CCodeModifiers.STATIC; - pop_function (); - cfile.add_function_declaration (proxy_iface_init); - cfile.add_function (proxy_iface_init); - } - - string implement_interface (CCodeFunctionCall define_type, Interface main_iface, Interface iface) { - string result = ""; - - // also implement prerequisites - foreach (var prereq in iface.get_prerequisites ()) { - if (prereq.data_type is Interface) { - result += implement_interface (define_type, main_iface, (Interface) prereq.data_type); - } - } - - string interface_macro; - - if (in_plugin) { - interface_macro = "G_IMPLEMENT_INTERFACE_DYNAMIC"; - } else { - interface_macro = "G_IMPLEMENT_INTERFACE"; - } - - result += "%s (%s, %sproxy_%sinterface_init) ".printf ( - interface_macro, - get_ccode_upper_case_name (iface, "TYPE_"), - get_ccode_lower_case_prefix (main_iface), - get_ccode_lower_case_prefix (iface)); - return result; - } - - public override void generate_interface_declaration (Interface iface, CCodeFile decl_space) { - base.generate_interface_declaration (iface, decl_space); - - string dbus_iface_name = get_dbus_name (iface); - if (dbus_iface_name == null) { - return; - } - - string get_type_name = "%sproxy_get_type".printf (get_ccode_lower_case_prefix (iface)); - - if (add_symbol_declaration (decl_space, iface, get_type_name)) { - return; - } - - decl_space.add_type_declaration (new CCodeNewline ()); - var macro = "(%s ())".printf (get_type_name); - decl_space.add_type_declaration (new CCodeMacroReplacement ("%s_PROXY".printf (get_ccode_type_id (iface)), macro)); - - // declare proxy_get_type function - var proxy_get_type = new CCodeFunction (get_type_name, "GType"); - proxy_get_type.modifiers = CCodeModifiers.CONST; - decl_space.add_function_declaration (proxy_get_type); - - if (in_plugin) { - var proxy_register_type = new CCodeFunction ("%sproxy_register_dynamic_type".printf (get_ccode_lower_case_prefix (iface))); - proxy_register_type.add_parameter (new CCodeParameter ("module", "GTypeModule*")); - decl_space.add_function_declaration (proxy_register_type); - } - } - - public override void visit_interface (Interface iface) { - base.visit_interface (iface); - - string dbus_iface_name = get_dbus_name (iface); - if (dbus_iface_name == null) { - return; - } - - cfile.add_include ("gio/gio.h"); - - // create proxy class - string cname = get_ccode_name (iface) + "Proxy"; - string lower_cname = get_ccode_lower_case_prefix (iface) + "proxy"; - - cfile.add_type_declaration (new CCodeTypeDefinition ("GDBusProxy", new CCodeVariableDeclarator (cname))); - cfile.add_type_declaration (new CCodeTypeDefinition ("GDBusProxyClass", new CCodeVariableDeclarator (cname + "Class"))); - - string type_macro; - - if (in_plugin) { - type_macro = "G_DEFINE_DYNAMIC_TYPE_EXTENDED"; - } else { - type_macro = "G_DEFINE_TYPE_EXTENDED"; - } - - var define_type = new CCodeFunctionCall (new CCodeIdentifier (type_macro)); - define_type.add_argument (new CCodeIdentifier (cname)); - define_type.add_argument (new CCodeIdentifier (lower_cname)); - define_type.add_argument (new CCodeIdentifier ("G_TYPE_DBUS_PROXY")); - define_type.add_argument (new CCodeConstant ("0")); - define_type.add_argument (new CCodeIdentifier (implement_interface (define_type, iface, iface))); - - cfile.add_type_member_definition (define_type); - - 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")); - pop_function (); - cfile.add_function (proxy_class_init); - - generate_signal_handler_function (iface); - - if (in_plugin) { - var proxy_class_finalize = new CCodeFunction (lower_cname + "_class_finalize", "void"); - proxy_class_finalize.add_parameter (new CCodeParameter ("klass", cname + "Class*")); - proxy_class_finalize.modifiers = CCodeModifiers.STATIC; - cfile.add_function (proxy_class_finalize); - - var proxy_type_init = new CCodeFunction (lower_cname + "_register_dynamic_type", "void"); - proxy_type_init.add_parameter (new CCodeParameter ("module", "GTypeModule*")); - push_function (proxy_type_init); - var call_register_type = new CCodeFunctionCall (new CCodeIdentifier (lower_cname + "_register_type")); - call_register_type.add_argument (new CCodeIdentifier ("module")); - ccode.add_expression (call_register_type); - pop_function (); - cfile.add_function(proxy_type_init); - } - - var proxy_instance_init = new CCodeFunction (lower_cname + "_init", "void"); - proxy_instance_init.add_parameter (new CCodeParameter ("self", cname + "*")); - proxy_instance_init.modifiers = CCodeModifiers.STATIC; - cfile.add_function (proxy_instance_init); - - generate_proxy_interface_init (iface, iface); - } - public override void visit_method_call (MethodCall expr) { var mtype = expr.call.value_type as MethodType; bool bus_get_proxy_async = (mtype != null && get_ccode_name (mtype.method_symbol) == "g_bus_get_proxy"); @@ -435,753 +242,6 @@ public class Vala.GDBusClientModule : GDBusModule { set_cvalue (expr, temp_ref); } - string generate_dbus_signal_handler (Signal sig, ObjectTypeSymbol sym) { - string wrapper_name = "_dbus_handle_%s_%s".printf (get_ccode_lower_case_name (sym), get_ccode_lower_case_name (sig)); - - var function = new CCodeFunction (wrapper_name); - function.modifiers = CCodeModifiers.STATIC; - function.add_parameter (new CCodeParameter ("self", get_ccode_name (sym) + "*")); - function.add_parameter (new CCodeParameter ("parameters", "GVariant*")); - - push_function (function); - - ccode.add_declaration ("GVariantIter", new CCodeVariableDeclarator ("_arguments_iter")); - - var iter_init = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_iter_init")); - iter_init.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_arguments_iter"))); - iter_init.add_argument (new CCodeIdentifier ("parameters")); - ccode.add_expression (iter_init); - - var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_signal_emit_by_name")); - ccall.add_argument (new CCodeIdentifier ("self")); - ccall.add_argument (get_signal_canonical_constant (sig)); - - foreach (Parameter param in sig.get_parameters ()) { - var param_name = get_variable_cname (param.name); - var owned_type = param.variable_type.copy (); - owned_type.value_owned = true; - - ccode.add_declaration (get_ccode_name (owned_type), new CCodeVariableDeclarator.zero (param_name, default_value_for_type (param.variable_type, true))); - - var st = param.variable_type.data_type as Struct; - if (st != null && !st.is_simple_type ()) { - ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (param_name))); - } else { - ccall.add_argument (new CCodeIdentifier (param_name)); - } - - if (param.variable_type is ArrayType) { - var array_type = (ArrayType) param.variable_type; - var length_ctype = get_ccode_array_length_type (array_type); - - for (int dim = 1; dim <= array_type.rank; dim++) { - string length_cname = get_variable_array_length_cname (param, dim); - - ccode.add_declaration (length_ctype, new CCodeVariableDeclarator (length_cname, new CCodeConstant ("0"))); - ccall.add_argument (new CCodeIdentifier (length_cname)); - } - } - - read_expression (param.variable_type, new CCodeIdentifier ("_arguments_iter"), new CCodeIdentifier (param_name), param); - } - - ccode.add_expression (ccall); - - foreach (Parameter param in sig.get_parameters ()) { - var owned_type = param.variable_type.copy (); - owned_type.value_owned = true; - - if (requires_destroy (owned_type)) { - // keep local alive (symbol_reference is weak) - var local = new LocalVariable (owned_type, param.name); - ccode.add_expression (destroy_local (local)); - } - } - - pop_function (); - - cfile.add_function_declaration (function); - cfile.add_function (function); - - return wrapper_name; - } - - 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*")); - cfunc.add_parameter (new CCodeParameter ("sender_name", "const gchar*")); - cfunc.add_parameter (new CCodeParameter ("signal_name", "const gchar*")); - cfunc.add_parameter (new CCodeParameter ("parameters", "GVariant*")); - - cfunc.modifiers |= CCodeModifiers.STATIC; - - cfile.add_function_declaration (cfunc); - - push_function (cfunc); - - bool firstif = true; - - foreach (Signal sig in sym.get_signals ()) { - if (sig.access != SymbolAccessibility.PUBLIC) { - continue; - } - - cfile.add_include ("string.h"); - - var ccheck = new CCodeFunctionCall (new CCodeIdentifier ("strcmp")); - ccheck.add_argument (new CCodeIdentifier ("signal_name")); - ccheck.add_argument (new CCodeConstant ("\"%s\"".printf (get_dbus_name_for_member (sig)))); - - var cond = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, ccheck, new CCodeConstant ("0")); - if (firstif) { - ccode.open_if (cond); - firstif = false; - } else { - ccode.else_if (cond); - } - - var ccall = new CCodeFunctionCall (new CCodeIdentifier (generate_dbus_signal_handler (sig, sym))); - ccall.add_argument (new CCodeCastExpression (new CCodeIdentifier ("proxy"), get_ccode_name (sym) + "*")); - ccall.add_argument (new CCodeIdentifier ("parameters")); - - ccode.add_expression (ccall); - } - if (!firstif) { - 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 *"); - - var connection = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_proxy_get_connection")); - connection.add_argument (gdbusproxy); - - bool uses_fd = dbus_method_uses_file_descriptor (m); - if (uses_fd) { - cfile.add_include ("gio/gunixfdlist.h"); - ccode.add_declaration ("GUnixFDList*", new CCodeVariableDeclarator ("_fd_list")); - } - - bool has_error_argument = m.tree_can_fail; - CCodeExpression error_argument; - if (has_error_argument) { - error_argument = new CCodeIdentifier ("error"); - } else { - error_argument = new CCodeConstant ("NULL"); - } - - if (call_type != CallType.FINISH) { - var destination = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_proxy_get_name")); - destination.add_argument (gdbusproxy); - - var interface_name = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_proxy_get_interface_name")); - interface_name.add_argument (gdbusproxy); - - var object_path = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_proxy_get_object_path")); - object_path.add_argument (gdbusproxy); - - CCodeExpression timeout; - if (method_timeout <= 0) { - timeout = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_proxy_get_default_timeout")); - ((CCodeFunctionCall) timeout).add_argument (gdbusproxy); - } else { - timeout = new CCodeConstant ("%d".printf (method_timeout)); - } - - // register errors - var error_types = new ArrayList (); - m.get_error_types (error_types); - foreach (var error_type in error_types) { - var errtype = (ErrorType) error_type; - if (errtype.error_domain != null) { - ccode.add_expression (new CCodeIdentifier (get_ccode_upper_case_name (errtype.error_domain))); - } - } - - // build D-Bus message - - ccode.add_declaration ("GDBusMessage", new CCodeVariableDeclarator ("*_message")); - - var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_message_new_method_call")); - ccall.add_argument (destination); - ccall.add_argument (object_path); - if (iface_name != null) { - ccall.add_argument (new CCodeConstant ("\"%s\"".printf (iface_name))); - } else { - ccall.add_argument (interface_name); - } - ccall.add_argument (new CCodeConstant ("\"%s\"".printf (method_name))); - ccode.add_assignment (new CCodeIdentifier ("_message"), ccall); - - ccode.add_declaration ("GVariant", new CCodeVariableDeclarator ("*_arguments")); - 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); - - if (uses_fd) { - ccode.add_assignment (new CCodeIdentifier ("_fd_list"), new CCodeFunctionCall (new CCodeIdentifier ("g_unix_fd_list_new"))); - } - - CCodeExpression cancellable = new CCodeConstant ("NULL"); - - foreach (Parameter param in m.get_parameters ()) { - if (param.direction == ParameterDirection.IN) { - CCodeExpression expr = new CCodeIdentifier (get_variable_cname (param.name)); - if (param.variable_type.is_real_struct_type ()) { - expr = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, expr); - } - - if (param.variable_type is ObjectType && param.variable_type.data_type.get_full_name () == "GLib.Cancellable") { - cancellable = expr; - continue; - } - - if (param.variable_type is ObjectType && param.variable_type.data_type.get_full_name () == "GLib.BusName") { - // ignore BusName sender parameters - continue; - } - - send_dbus_value (param.variable_type, new CCodeIdentifier ("_arguments_builder"), expr, param); - } - } - - 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 set_body = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_message_set_body")); - set_body.add_argument (new CCodeIdentifier ("_message")); - set_body.add_argument (new CCodeIdentifier ("_arguments")); - ccode.add_expression (set_body); - - if (uses_fd) { - ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_message_set_unix_fd_list")); - ccall.add_argument (new CCodeIdentifier ("_message")); - ccall.add_argument (new CCodeIdentifier ("_fd_list")); - ccode.add_expression (ccall); - - ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_object_unref")); - ccall.add_argument (new CCodeIdentifier ("_fd_list")); - ccode.add_expression (ccall); - } - - // send D-Bus message - - if (call_type == CallType.SYNC) { - ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_connection_send_message_with_reply_sync")); - ccall.add_argument (connection); - ccall.add_argument (new CCodeIdentifier ("_message")); - ccall.add_argument (new CCodeConstant ("G_DBUS_SEND_MESSAGE_FLAGS_NONE")); - ccall.add_argument (timeout); - ccall.add_argument (new CCodeConstant ("NULL")); - ccall.add_argument (cancellable); - ccall.add_argument (error_argument); - ccode.add_assignment (new CCodeIdentifier ("_reply_message"), ccall); - } else if (call_type == CallType.NO_REPLY) { - var set_flags = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_message_set_flags")); - set_flags.add_argument (new CCodeIdentifier ("_message")); - set_flags.add_argument (new CCodeConstant ("G_DBUS_MESSAGE_FLAGS_NO_REPLY_EXPECTED")); - ccode.add_expression (set_flags); - - ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_connection_send_message")); - ccall.add_argument (connection); - ccall.add_argument (new CCodeIdentifier ("_message")); - ccall.add_argument (new CCodeConstant ("G_DBUS_SEND_MESSAGE_FLAGS_NONE")); - ccall.add_argument (new CCodeConstant ("NULL")); - ccall.add_argument (error_argument); - ccode.add_expression (ccall); - } else if (call_type == CallType.ASYNC) { - ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_connection_send_message_with_reply")); - ccall.add_argument (connection); - ccall.add_argument (new CCodeIdentifier ("_message")); - ccall.add_argument (new CCodeConstant ("G_DBUS_SEND_MESSAGE_FLAGS_NONE")); - ccall.add_argument (timeout); - ccall.add_argument (new CCodeConstant ("NULL")); - ccall.add_argument (cancellable); - - CCodeFunctionCall res_wrapper = null; - - // use wrapper as source_object wouldn't be correct otherwise - ccall.add_argument (new CCodeIdentifier (generate_async_callback_wrapper ())); - res_wrapper = new CCodeFunctionCall (new CCodeIdentifier ("g_task_new")); - res_wrapper.add_argument (new CCodeCastExpression (new CCodeIdentifier ("self"), "GObject *")); - res_wrapper.add_argument (new CCodeConstant ("NULL")); - res_wrapper.add_argument (new CCodeIdentifier ("_callback_")); - res_wrapper.add_argument (new CCodeIdentifier ("_user_data_")); - ccall.add_argument (res_wrapper); - - ccode.add_expression (ccall); - } - - // free D-Bus message - - ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_object_unref")); - ccall.add_argument (new CCodeIdentifier ("_message")); - ccode.add_expression (ccall); - } else { - var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_connection_send_message_with_reply_finish")); - ccall.add_argument (connection); - - // unwrap async result - ccode.add_declaration ("GAsyncResult", new CCodeVariableDeclarator ("*_inner_res")); - - var inner_res = new CCodeFunctionCall (new CCodeIdentifier ("g_task_propagate_pointer")); - inner_res.add_argument (new CCodeCastExpression (new CCodeIdentifier ("_res_"), "GTask *")); - inner_res.add_argument (new CCodeConstant ("NULL")); - ccode.add_assignment (new CCodeIdentifier ("_inner_res"), inner_res); - - ccall.add_argument (new CCodeIdentifier ("_inner_res")); - ccall.add_argument (error_argument); - ccode.add_assignment (new CCodeIdentifier ("_reply_message"), ccall); - - // _inner_res is guaranteed to be non-NULL, so just unref it - var unref_inner_res = new CCodeFunctionCall (new CCodeIdentifier ("g_object_unref")); - unref_inner_res.add_argument (new CCodeIdentifier ("_inner_res")); - ccode.add_expression (unref_inner_res); - } - - if (call_type == CallType.SYNC || call_type == CallType.FINISH) { - ccode.add_declaration ("GDBusMessage", new CCodeVariableDeclarator ("*_reply_message")); - - var unref_reply = new CCodeFunctionCall (new CCodeIdentifier ("g_object_unref")); - unref_reply.add_argument (new CCodeIdentifier ("_reply_message")); - - // return on io error - var reply_is_null = new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, new CCodeIdentifier ("_reply_message")); - ccode.open_if (reply_is_null); - return_default_value (m.return_type); - ccode.close (); - - // return on remote error - var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_message_to_gerror")); - ccall.add_argument (new CCodeIdentifier ("_reply_message")); - ccall.add_argument (error_argument); - ccode.open_if (ccall); - ccode.add_expression (unref_reply); - return_default_value (m.return_type); - ccode.close (); - - bool has_result = !(m.return_type is VoidType); - - if (uses_fd) { - ccode.add_declaration ("gint", new CCodeVariableDeclarator.zero ("_fd_index", new CCodeConstant ("0"))); - ccode.add_declaration ("gint", new CCodeVariableDeclarator ("_fd")); - } - - foreach (Parameter param in m.get_parameters ()) { - if (param.direction == ParameterDirection.OUT) { - has_result = true; - } - } - - if (has_result) { - ccode.add_declaration ("GVariant", new CCodeVariableDeclarator ("*_reply")); - ccode.add_declaration ("GVariantIter", new CCodeVariableDeclarator ("_reply_iter")); - - ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_message_get_body")); - ccall.add_argument (new CCodeIdentifier ("_reply_message")); - ccode.add_assignment (new CCodeIdentifier ("_reply"), ccall); - - var iter_init = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_iter_init")); - iter_init.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_reply_iter"))); - iter_init.add_argument (new CCodeIdentifier ("_reply")); - ccode.add_expression (iter_init); - - foreach (Parameter param in m.get_parameters ()) { - if (param.direction == ParameterDirection.OUT) { - ccode.add_declaration (get_ccode_name (param.variable_type), new CCodeVariableDeclarator.zero ("_vala_%s".printf (param.name), default_value_for_type (param.variable_type, true))); - - var array_type = param.variable_type as ArrayType; - if (array_type != null) { - var length_ctype = get_ccode_array_length_type (array_type); - for (int dim = 1; dim <= array_type.rank; dim++) { - ccode.add_declaration (length_ctype, new CCodeVariableDeclarator ("_vala_%s_length%d".printf (param.name, dim), new CCodeConstant ("0"))); - } - } - - var target = new CCodeIdentifier ("_vala_%s".printf (param.name)); - bool may_fail; - - receive_dbus_value (param.variable_type, new CCodeIdentifier ("_reply_message"), new CCodeIdentifier ("_reply_iter"), target, param, error_argument, out may_fail); - - // TODO check that parameter is not NULL (out parameters are optional) - // free value if parameter is NULL - ccode.add_assignment (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier (get_variable_cname (param.name))), target); - - if (array_type != null) { - for (int dim = 1; dim <= array_type.rank; dim++) { - // TODO check that parameter is not NULL (out parameters are optional) - ccode.add_assignment (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("%s_length%d".printf (param.name, dim))), new CCodeIdentifier ("_vala_%s_length%d".printf (param.name, dim))); - } - } - - if (may_fail && has_error_argument) { - ccode.open_if (new CCodeBinaryExpression (CCodeBinaryOperator.AND, new CCodeIdentifier ("error"), new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("error")))); - ccode.add_expression (unref_reply); - return_default_value (m.return_type); - ccode.close (); - } - } - } - - if (!(m.return_type is VoidType)) { - if (m.return_type.is_real_non_null_struct_type ()) { - var target = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("result")); - receive_dbus_value (m.return_type, new CCodeIdentifier ("_reply_message"), new CCodeIdentifier ("_reply_iter"), target, m); - } else { - ccode.add_declaration (get_ccode_name (m.return_type), new CCodeVariableDeclarator.zero ("_result", default_value_for_type (m.return_type, true))); - - var array_type = m.return_type as ArrayType; - if (array_type != null) { - var length_ctype = get_ccode_array_length_type (array_type); - for (int dim = 1; dim <= array_type.rank; dim++) { - ccode.add_declaration (length_ctype, new CCodeVariableDeclarator ("_result_length%d".printf (dim), new CCodeConstant ("0"))); - } - } - - bool may_fail; - receive_dbus_value (m.return_type, new CCodeIdentifier ("_reply_message"), new CCodeIdentifier ("_reply_iter"), new CCodeIdentifier ("_result"), m, new CCodeIdentifier ("error"), out may_fail); - - if (array_type != null) { - for (int dim = 1; dim <= array_type.rank; dim++) { - // TODO check that parameter is not NULL (out parameters are optional) - ccode.add_assignment (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("result_length%d".printf (dim))), new CCodeIdentifier ("_result_length%d".printf (dim))); - } - } - - if (may_fail) { - ccode.open_if (new CCodeBinaryExpression (CCodeBinaryOperator.AND, new CCodeIdentifier ("error"), new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("error")))); - ccode.add_expression (unref_reply); - return_default_value (m.return_type); - ccode.close (); - } - } - } - } - - ccode.add_expression (unref_reply); - - if (!(m.return_type is VoidType || m.return_type.is_real_non_null_struct_type ())) { - ccode.add_return (new CCodeIdentifier ("_result")); - } - } - } - - string generate_dbus_proxy_method (Interface main_iface, Interface iface, Method m) { - string proxy_name = "%sproxy_%s".printf (get_ccode_lower_case_prefix (main_iface), m.name); - - string dbus_iface_name = get_dbus_name (iface); - - bool no_reply = is_dbus_no_reply (m); - - var function = new CCodeFunction (proxy_name); - function.modifiers = CCodeModifiers.STATIC; - - var cparam_map = new HashMap (direct_hash, direct_equal); - - generate_cparameters (m, cfile, cparam_map, function); - - push_function (function); - - generate_marshalling (m, no_reply ? CallType.NO_REPLY : CallType.SYNC, dbus_iface_name, get_dbus_name_for_member (m), get_dbus_timeout_for_member (m)); - - pop_function (); - - cfile.add_function_declaration (function); - cfile.add_function (function); - - return proxy_name; - } - - string generate_async_dbus_proxy_method (Interface main_iface, Interface iface, Method m) { - string proxy_name = "%sproxy_%s_async".printf (get_ccode_lower_case_prefix (main_iface), m.name); - - string dbus_iface_name = get_dbus_name (iface); - - var function = new CCodeFunction (proxy_name, "void"); - function.modifiers = CCodeModifiers.STATIC; - - var cparam_map = new HashMap (direct_hash, direct_equal); - - cparam_map.set (get_param_pos (-1), new CCodeParameter ("_callback_", "GAsyncReadyCallback")); - cparam_map.set (get_param_pos (-0.9), new CCodeParameter ("_user_data_", "gpointer")); - - generate_cparameters (m, cfile, cparam_map, function, null, null, null, 1); - - push_function (function); - - generate_marshalling (m, CallType.ASYNC, dbus_iface_name, get_dbus_name_for_member (m), get_dbus_timeout_for_member (m)); - - pop_function (); - - cfile.add_function_declaration (function); - cfile.add_function (function); - - return proxy_name; - } - - string generate_finish_dbus_proxy_method (Interface main_iface, Interface iface, Method m) { - string proxy_name = "%sproxy_%s_finish".printf (get_ccode_lower_case_prefix (main_iface), m.name); - - var function = new CCodeFunction (proxy_name); - function.modifiers = CCodeModifiers.STATIC; - - var cparam_map = new HashMap (direct_hash, direct_equal); - - cparam_map.set (get_param_pos (get_ccode_async_result_pos (m)), new CCodeParameter ("_res_", "GAsyncResult*")); - - generate_cparameters (m, cfile, cparam_map, function, null, null, null, 2); - - push_function (function); - - generate_marshalling (m, CallType.FINISH, null, null, -1); - - pop_function (); - - cfile.add_function_declaration (function); - cfile.add_function (function); - - return proxy_name; - } - - string generate_dbus_proxy_property_get (Interface main_iface, Interface iface, Property prop) { - string proxy_name = "%sdbus_proxy_get_%s".printf (get_ccode_lower_case_prefix (main_iface), prop.name); - - string dbus_iface_name = get_dbus_name (iface); - - var owned_type = prop.get_accessor.value_type.copy (); - owned_type.value_owned = true; - if (owned_type.is_disposable () && !prop.get_accessor.value_type.value_owned) { - Report.error (prop.get_accessor.value_type.source_reference, "Properties used in D-Bus clients require owned get accessor"); - } - - var array_type = prop.get_accessor.value_type as ArrayType; - - var function = new CCodeFunction (proxy_name); - function.modifiers = CCodeModifiers.STATIC; - - function.add_parameter (new CCodeParameter ("self", "%s*".printf (get_ccode_name (iface)))); - - if (prop.property_type.is_real_non_null_struct_type ()) { - function.add_parameter (new CCodeParameter ("result", "%s*".printf (get_ccode_name (prop.get_accessor.value_type)))); - } else { - if (array_type != null) { - var length_ctype = get_ccode_array_length_type (array_type) + "*"; - for (int dim = 1; dim <= array_type.rank; dim++) { - function.add_parameter (new CCodeParameter ("result_length%d".printf (dim), length_ctype)); - } - } - - function.return_type = get_ccode_name (prop.get_accessor.value_type); - } - - push_function (function); - - ccode.add_declaration ("GVariant", new CCodeVariableDeclarator ("*_inner_reply")); - - // first try cached value - var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_proxy_get_cached_property")); - ccall.add_argument (new CCodeCastExpression (new CCodeIdentifier ("self"), "GDBusProxy *")); - ccall.add_argument (new CCodeConstant ("\"%s\"".printf (get_dbus_name_for_member (prop)))); - ccode.add_assignment (new CCodeIdentifier ("_inner_reply"), ccall); - - // if not successful, retrieve value via D-Bus - ccode.open_if (new CCodeUnaryExpression (CCodeUnaryOperator.LOGICAL_NEGATION, new CCodeIdentifier ("_inner_reply"))); - - 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); - - 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); - - 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.Get\"")); - 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"))); - return_default_value (prop.property_type); - ccode.close (); - - var get_variant = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_get")); - get_variant.add_argument (new CCodeIdentifier ("_reply")); - get_variant.add_argument (new CCodeConstant ("\"(v)\"")); - get_variant.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("_inner_reply"))); - ccode.add_expression (get_variant); - - var unref_reply = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_unref")); - unref_reply.add_argument (new CCodeIdentifier ("_reply")); - ccode.add_expression (unref_reply); - - ccode.close (); - - if (prop.property_type.is_real_non_null_struct_type ()) { - var target = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("result")); - var result = deserialize_expression (prop.get_accessor.value_type, new CCodeIdentifier ("_inner_reply"), target); - ccode.add_assignment (target, result); - } else { - ccode.add_declaration (get_ccode_name (prop.get_accessor.value_type), new CCodeVariableDeclarator ("_result")); - - if (get_dbus_signature (prop) != null) { - // raw GVariant - ccode.add_assignment (new CCodeIdentifier ("_result"), new CCodeIdentifier("_inner_reply")); - } else { - if (array_type != null) { - var length_ctype = get_ccode_array_length_type (array_type); - for (int dim = 1; dim <= array_type.rank; dim++) { - ccode.add_declaration (length_ctype, new CCodeVariableDeclarator ("_result_length%d".printf (dim), new CCodeConstant ("0"))); - } - } - - var result = deserialize_expression (prop.get_accessor.value_type, new CCodeIdentifier ("_inner_reply"), new CCodeIdentifier ("_result")); - ccode.add_assignment (new CCodeIdentifier ("_result"), result); - - if (array_type != null) { - for (int dim = 1; dim <= array_type.rank; dim++) { - // TODO check that parameter is not NULL (out parameters are optional) - ccode.add_assignment (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("result_length%d".printf (dim))), new CCodeIdentifier ("_result_length%d".printf (dim))); - } - } - } - } - - if (prop.property_type.is_real_non_null_struct_type () || get_dbus_signature (prop) == null) { - unref_reply = new CCodeFunctionCall (new CCodeIdentifier ("g_variant_unref")); - unref_reply.add_argument (new CCodeIdentifier ("_inner_reply")); - ccode.add_expression (unref_reply); - } - - if (prop.property_type.is_real_non_null_struct_type ()) { - ccode.add_return (); - } else { - ccode.add_return (new CCodeIdentifier ("_result")); - } - - pop_function (); - - cfile.add_function_declaration (function); - cfile.add_function (function); - - return proxy_name; - } - - 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); - function.modifiers = CCodeModifiers.STATIC; - - function.add_parameter (new CCodeParameter ("self", "%s*".printf (get_ccode_name (iface)))); - - if (prop.property_type.is_real_non_null_struct_type ()) { - function.add_parameter (new CCodeParameter ("value", "%s*".printf (get_ccode_name (prop.set_accessor.value_type)))); - } else { - function.add_parameter (new CCodeParameter ("value", get_ccode_name (prop.set_accessor.value_type))); - - if (array_type != null) { - var length_ctype = get_ccode_array_length_type (array_type); - for (int dim = 1; dim <= array_type.rank; dim++) { - function.add_parameter (new CCodeParameter ("value_length%d".printf (dim), length_ctype)); - } - } - } - - 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); - - pop_function (); - - cfile.add_function_declaration (function); - cfile.add_function (function); - - return proxy_name; - } - public override void register_dbus_info (CCodeBlock block, ObjectTypeSymbol sym) { if (!(sym is Interface)) { return; diff --git a/codegen/valagdbusclienttransformer.vala b/codegen/valagdbusclienttransformer.vala new file mode 100644 index 000000000..5e8b9da2a --- /dev/null +++ b/codegen/valagdbusclienttransformer.vala @@ -0,0 +1,347 @@ +/* valagdbusclienttransformer.vala + * + * Copyright (C) 2011 Luca Bruno + * + * 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: + * Luca Bruno + */ + +/** + * Code visitor for transforming the code tree related to DBus clients. + */ +public class Vala.GDBusClientTransformer : GVariantTransformer { + public static bool is_dbus_no_reply (Method m) { + return m.get_attribute_bool ("DBus", "no_reply"); + } + + public static string? get_dbus_name (TypeSymbol symbol) { + return symbol.get_attribute_string ("DBus", "name"); + } + + public static string get_dbus_name_for_member (Symbol symbol) { + var dbus_name = symbol.get_attribute_string ("DBus", "name"); + if (dbus_name != null) { + return dbus_name; + } + + return Symbol.lower_case_to_camel_case (symbol.name); + } + + Expression read_dbus_value (DataType type, string iter, string message, ref string? fd_list, ref string? fd_index) { + string? type_name = null; + if (type.data_type != null) { + type_name = type.data_type.get_full_name (); + } + if (type_name == "GLib.UnixInputStream" || type_name == "GLib.UnixOutputStream" || type_name == "GLib.Socket") { + if (fd_list == null) { + fd_list = b.add_temp_declaration (data_type ("GLib.UnixFDList"), null); + fd_index = b.add_temp_declaration (null, expression ("0")); + b.add_expression (expression (@"$fd_list = $message.get_unix_fd_list ()")); + } + b.add_expression (expression (@"$iter.next (\"h\", out $fd_index)")); + if (type_name == "GLib.UnixInputStream") { + return expression (@"new GLib.UnixInputStream ($fd_list.get ($fd_index), true)"); + } else if (type_name == "GLib.UnixOutputStream") { + return expression (@"new GLib.UnixOutputStream ($fd_list.get ($fd_index), true)"); + } else { + // socket + return expression (@"new GLib.Socket.from_fd ($fd_list.get ($fd_index))"); + } + } else { + return expression (@"($(type)) ($iter.next_value ())"); + } + } + + void generate_marshalling (Method m, string? iface_name, string? method_name, int method_timeout) { + var interface_name = iface_name != null ? @"\"$iface_name\"" : "this.get_interface_name ()"; + + // create the message + var reply = b.add_temp_declaration (data_type ("GLib.DBusMessage")); + var message = b.add_temp_declaration (null, expression (@"new GLib.DBusMessage.method_call (this.get_name(), this.get_object_path (), $interface_name, \"$method_name\")")); + var builder = b.add_temp_declaration (null, expression (@"new GLib.VariantBuilder (GLib.VariantType.TUPLE)")); + + // fill the message + bool has_result = m.has_result; + string cancellable = "null"; + string fd_list = null; + foreach (var param in m.get_parameters ()) { + if (param.direction == ParameterDirection.IN) { + string? type_name = null; + if (param.variable_type.data_type != null) { + type_name = param.variable_type.data_type.get_full_name (); + } + if (type_name == "GLib.Cancellable") { + cancellable = param.name; + } else if (type_name == "GLib.BusName") { + // ignore BusName sender + } else if (type_name == "GLib.UnixInputStream" || type_name == "GLib.UnixOutputStream" || type_name == "GLib.Socket") { + if (fd_list == null) { + fd_list = b.add_temp_declaration (null, expression ("new GLib.UnixFDList ()")); + } + b.add_expression (expression (@"$builder.add (\"h\", $fd_list.append ($(param.name).get_fd ()))")); + } else { + b.add_expression (expression (@"$builder.add_value ($(param.name))")); + } + } else if (param.direction == ParameterDirection.OUT) { + has_result = true; + } + } + b.add_expression (expression (@"$message.set_body ($builder.end ())")); + if (fd_list != null) { + b.add_expression (expression (@"$message.set_unix_fd_list ($fd_list)")); + } + + // send the message + if (is_dbus_no_reply (m)) { + b.add_expression (expression (@"this.get_connection().send_message ($message, GLib.DBusSendMessageFlags.NO_REPLY_EXPECTED, null)")); + } else { + var yield_str = m.coroutine ? "yield " : ""; + var method_str = m.coroutine ? "send_message_with_reply" : "send_message_with_reply_sync"; + var timeout_str = method_timeout > 0 ? @"$method_timeout" : "this.get_default_timeout ()"; + b.add_expression (expression (@"$reply = $yield_str this.get_connection().$method_str ($message, GLib.DBusSendMessageFlags.NONE, $timeout_str, null, $cancellable)")); + + b.add_expression (expression (@"$reply.to_gerror ()")); + } + + // deserialize the result + fd_list = null; + string fd_index = null; + if (has_result) { + var iter = b.add_temp_declaration (data_type ("GLib.VariantIter")); + b.add_expression (expression (@"$iter = $reply.get_body().iterator ()")); + foreach (var param in m.get_parameters ()) { + if (param.direction == ParameterDirection.OUT) { + b.add_assignment (expression (param.name), read_dbus_value (param.variable_type, iter, reply, ref fd_list, ref fd_index)); + } + } + if (m.has_result) { + b.add_return (read_dbus_value (m.return_type, iter, reply, ref fd_list, ref fd_index)); + } + } + } + + void generate_dbus_proxy_method (Class proxy_class, Interface iface, Method m) { + var proxy = new Method (m.name, m.return_type, m.source_reference); + foreach (var param in m.get_parameters ()) { + proxy.add_parameter (param.copy ()); + } + proxy.access = m.access; + proxy.binding = m.binding; + proxy.coroutine = m.coroutine; + var error_types = new ArrayList (); + m.get_error_types (error_types); + foreach (var error_type in error_types) { + proxy.add_error_type (error_type); + } + proxy_class.add_method (proxy); + + b = new CodeBuilder.for_subroutine (proxy); + string dbus_iface_name = get_dbus_name (iface); + generate_marshalling (m, dbus_iface_name, get_dbus_name_for_member (m), GDBusModule.get_dbus_timeout_for_member (m)); + } + + void generate_dbus_proxy_methods (Class proxy_class, Interface iface) { + // also generate proxy for prerequisites + foreach (var prereq in iface.get_prerequisites ()) { + if (prereq.data_type is Interface) { + generate_dbus_proxy_methods (proxy_class, (Interface) prereq.data_type); + } + } + + foreach (var m in iface.get_methods ()) { + if (!m.is_abstract) { + continue; + } + + generate_dbus_proxy_method (proxy_class, iface, m); + } + } + + string generate_dbus_proxy_signal (Class proxy_class, Signal sig, ObjectTypeSymbol sym) { + var m = new Method (temp_func_cname (), new VoidType (), sig.source_reference); + m.access = SymbolAccessibility.PRIVATE; + m.add_parameter (new Parameter ("parameters", data_type ("GLib.Variant", false), sig.source_reference)); + proxy_class.add_method (m); + b.push_method (m); + + var iter = b.add_temp_declaration (null, expression ("parameters.iterator ()")); + var call = new MethodCall (expression (sig.name), sig.source_reference); + foreach (var param in sig.get_parameters ()) { + var temp = b.add_temp_declaration (copy_type (param.variable_type, true)); + if (param.variable_type.data_type == context.analyzer.gvariant_type.data_type) { + b.add_expression (expression (@"$temp = $iter.next_value().get_variant ()")); + } else { + b.add_expression (expression (@"$temp = ($(param.variable_type)) ($iter.next_value ())")); + } + call.add_argument (expression (temp)); + } + b.add_expression (call); + + b.pop_method (); + return m.name; + } + + void generate_dbus_proxy_signals (Class proxy_class, ObjectTypeSymbol sym) { + var g_signal = (Signal) symbol_from_string ("GLib.DBusProxy.g_signal"); + var m = new Method ("g_signal", g_signal.return_type, sym.source_reference); + m.overrides = true; + m.access = SymbolAccessibility.PUBLIC; + foreach (var param in g_signal.get_parameters ()) { + m.add_parameter (param.copy ()); + } + proxy_class.add_method (m); + + b = new CodeBuilder.for_subroutine (m); + + b.open_switch (expression ("signal_name"), null); + b.add_expression (expression ("assert_not_reached ()")); + b.add_break (); + foreach (var sig in sym.get_signals ()) { + if (sig.access != SymbolAccessibility.PUBLIC) { + continue; + } + + b.add_section (expression (@"\"$(get_dbus_name_for_member (sig))\"")); + var handler_name = generate_dbus_proxy_signal (proxy_class, sig, sym); + b.add_expression (expression (@"$handler_name (parameters)")); + b.add_break (); + } + b.close (); + } + + public int get_dbus_timeout (Symbol symbol) { + int timeout = -1; + + var dbus = symbol.get_attribute ("DBus"); + if (dbus != null && dbus.has_argument ("timeout")) { + timeout = dbus.get_integer ("timeout"); + } else if (symbol.parent_symbol != null) { + return get_dbus_timeout (symbol.parent_symbol); + } + + return timeout; + } + + void generate_dbus_proxy_property (Class proxy_class, Interface iface, Property prop) { + int timeout = get_dbus_timeout (prop); + var dbus_name = get_dbus_name_for_member (prop); + var dbus_iface_name = get_dbus_name (iface); + + PropertyAccessor proxy_get = null; + if (prop.get_accessor != null) { + var owned_type = copy_type (prop.get_accessor.value_type, true); + if (owned_type.is_disposable () && !prop.get_accessor.value_type.value_owned) { + Report.error (prop.get_accessor.value_type.source_reference, "Properties used in D-Bus clients require owned get accessor"); + return; + } + + proxy_get = new PropertyAccessor (true, false, false, owned_type, null, prop.get_accessor.source_reference); + + b = new CodeBuilder.for_subroutine (proxy_get); + // first try cached value + var result = b.add_temp_declaration (null, expression (@"get_cached_property (\"$dbus_name\")")); + b.open_if (expression (@"$result == null")); + b.add_expression (expression (@"$result = call_sync (\"org.freedesktop.DBus.Properties.Get\", new Variant (\"(ss)\", \"$dbus_iface_name\", \"$dbus_name\"), GLib.DBusCallFlags.NONE, $timeout, null)")); + b.add_expression (expression (@"$result.get (\"(v)\", out $result)")); + b.close (); + + b.add_return (expression (@"($(prop.property_type)) ($result)")); + } + + PropertyAccessor proxy_set = null; + if (prop.set_accessor != null) { + proxy_set = new PropertyAccessor (false, true, false, prop.set_accessor.value_type, null, prop.set_accessor.source_reference); + b = new CodeBuilder.for_subroutine (proxy_set); + var variant = b.add_temp_declaration (data_type ("GLib.Variant"), expression ("value")); + b.add_expression (expression (@"call_sync (\"org.freedesktop.DBus.Properties.Set\", new Variant (\"(ssv)\", \"$dbus_iface_name\", \"$dbus_name\", $variant), GLib.DBusCallFlags.NONE, $timeout, null)")); + } + + Property proxy = new Property (prop.name, prop.property_type, proxy_get, proxy_set, prop.source_reference); + proxy_class.add_property (proxy); + } + + void generate_dbus_proxy_properties (Class proxy_class, Interface iface) { + // also generate proxy for prerequisites + foreach (var prereq in iface.get_prerequisites ()) { + if (prereq.data_type is Interface) { + generate_dbus_proxy_properties (proxy_class, (Interface) prereq.data_type); + } + } + + foreach (var prop in iface.get_properties ()) { + if (!prop.is_abstract) { + continue; + } + + generate_dbus_proxy_property (proxy_class, iface, prop); + } + } + + public override void visit_interface (Interface iface) { + base.visit_interface (iface); + + string dbus_iface_name = get_dbus_name (iface); + if (dbus_iface_name == null) { + return; + } + + if (iface.parent_symbol.scope.lookup (iface.name+"Proxy") != null) { + return; + } + + // create proxy class + var proxy = new Class (iface.name+"Proxy", iface.source_reference, null); + proxy.add_base_type (data_type ("GLib.DBusProxy")); + proxy.add_base_type (context.analyzer.get_data_type_for_symbol (iface)); + proxy.access = iface.access; + iface.parent_symbol.add_class (proxy); + + generate_dbus_proxy_methods (proxy, iface); + generate_dbus_proxy_signals (proxy, iface); + generate_dbus_proxy_properties (proxy, iface); + + check (proxy); + } + + public override void visit_method_call (MethodCall expr) { + var m = expr.call.symbol_reference as DynamicMethod; + if (m == null || m.dynamic_type.data_type != symbol_from_string ("GLib.DBusProxy")) { + // not a dynamic dbus call + base.visit_method_call (expr); + return; + } + + b = new CodeBuilder (context, expr.parent_statement, expr.source_reference); + + Method wrapper; + var cache_key = "gdbus_client_dynamic_method_call "+m.return_type.to_string (); + foreach (var param in m.get_parameters ()) { + cache_key = "%s %s".printf (cache_key, param.variable_type.to_string ()); + } + if (!wrapper_method (m.return_type, cache_key, out wrapper, symbol_from_string ("GLib.DBusProxy"))) { + foreach (var param in m.get_parameters ()) { + wrapper.add_parameter (param.copy ()); + } + b = new CodeBuilder.for_subroutine (wrapper); + generate_marshalling (m, null, m.name, GDBusModule.get_dbus_timeout_for_member (m)); + check (wrapper); + } + + expr.call.symbol_reference = wrapper; + base.visit_method_call (expr); + } +} diff --git a/codegen/valagvariantmodule.vala b/codegen/valagvariantmodule.vala index 5757e3525..b63d596e2 100644 --- a/codegen/valagvariantmodule.vala +++ b/codegen/valagvariantmodule.vala @@ -49,14 +49,6 @@ public class Vala.GVariantModule : GAsyncModule { return false; } - string get_dbus_value (EnumValue value, string default_value) { - var dbus_value = value.get_attribute_string ("DBus", "value"); - if (dbus_value != null) { - return dbus_value;; - } - return default_value; - } - public static string? get_dbus_signature (Symbol symbol) { return symbol.get_attribute_string ("DBus", "signature"); } diff --git a/codegen/valagvarianttransformer.vala b/codegen/valagvarianttransformer.vala index 3d1fad917..81acf5cb7 100644 --- a/codegen/valagvarianttransformer.vala +++ b/codegen/valagvarianttransformer.vala @@ -416,7 +416,7 @@ public class Vala.GVariantTransformer : CodeTransformer { en.add_method (m); m.binding = MemberBinding.STATIC; m.access = SymbolAccessibility.PUBLIC; - b = new CodeBuilder.for_method (m); + b = new CodeBuilder.for_subroutine (m); b.open_switch (expression ("str"), null); b.add_throw (expression ("new GLib.DBusError.INVALID_ARGS (\"Invalid value for enum `%s'\")".printf (get_ccode_name (en)))); @@ -437,7 +437,7 @@ public class Vala.GVariantTransformer : CodeTransformer { var m = new Method ("to_string", data_type ("string", false, true), en.source_reference); en.add_method (m); m.access = SymbolAccessibility.PUBLIC; - b = new CodeBuilder.for_method (m); + b = new CodeBuilder.for_subroutine (m); b.open_switch (expression ("this"), null); b.add_return (expression ("null")); diff --git a/compiler/valacompiler.vala b/compiler/valacompiler.vala index 29e23ff41..8b094f3e7 100644 --- a/compiler/valacompiler.vala +++ b/compiler/valacompiler.vala @@ -403,7 +403,7 @@ class Vala.Compiler { } } - var transformer = new GVariantTransformer (); + var transformer = new GDBusClientTransformer (); transformer.transform (context); if (context.report.get_errors () > 0 || (fatal_warnings && context.report.get_warnings () > 0)) { diff --git a/vala/valacodebuilder.vala b/vala/valacodebuilder.vala index ed52b08c3..fd0fbf8c0 100644 --- a/vala/valacodebuilder.vala +++ b/vala/valacodebuilder.vala @@ -48,7 +48,7 @@ public class Vala.CodeBuilder { build_context.check_nodes.add (build_context.current_block); } - public CodeBuilder.for_method (Method m) { + public CodeBuilder.for_subroutine (Subroutine m) { source_reference = m.source_reference; build_context = new BuildContext (); build_context.insert_block = m.body = new Block (source_reference); diff --git a/vala/valacodetransformer.vala b/vala/valacodetransformer.vala index ff4947f3a..d46c10071 100644 --- a/vala/valacodetransformer.vala +++ b/vala/valacodetransformer.vala @@ -62,16 +62,18 @@ public class Vala.CodeTransformer : CodeVisitor { wrapper_cache.set (key, node); } - public bool wrapper_method (DataType return_type, string cache_key, out Method m) { - CodeNode n; - if (get_cached_wrapper (cache_key, out n)) { + public string temp_func_cname () { + return "_vala_func_"+CodeNode.get_temp_name ().substring (1); + } + + public bool wrapper_method (DataType return_type, string? cache_key, out Method m, Symbol? parent = null) { + CodeNode n = null; + if (cache_key != null && get_cached_wrapper (cache_key, out n)) { m = (Method) n; return true; } - var name = CodeNode.get_temp_name ().replace (".", ""); - name = "_vala_func_"+name; - m = new Method (name, return_type, b.source_reference); - context.root.add_method (m); + m = new Method (temp_func_cname (), return_type, b.source_reference); + (parent == null ? context.root : parent).add_method (m); m.access = SymbolAccessibility.PRIVATE; add_cached_wrapper (cache_key, m); return false; diff --git a/vapi/gio-2.0.vapi b/vapi/gio-2.0.vapi index 0f69608a9..316537801 100644 --- a/vapi/gio-2.0.vapi +++ b/vapi/gio-2.0.vapi @@ -843,7 +843,7 @@ namespace GLib { public DBusMessage.@signal (string path, string interface_, string @signal); [CCode (array_length_pos = 0.5, array_length_type = "gsize")] public uint8[] to_blob (GLib.DBusCapabilityFlags capabilities) throws GLib.Error; - public bool to_gerror () throws GLib.Error; + public bool to_gerror () throws GLib.IOError; public bool locked { get; } } [CCode (cheader_filename = "gio/gio.h", ref_function = "g_dbus_method_info_ref", type_id = "g_dbus_method_info_get_type ()", unref_function = "g_dbus_method_info_unref")] diff --git a/vapi/metadata/Gio-2.0.metadata b/vapi/metadata/Gio-2.0.metadata index 9271e724c..a3e835d4b 100644 --- a/vapi/metadata/Gio-2.0.metadata +++ b/vapi/metadata/Gio-2.0.metadata @@ -102,6 +102,7 @@ DBusMessage .new_method_error printf_format .get_header_fields type="uchar[]" .print.indent default=0 + .to_gerror throws="GLib.IOError" DBus*Info .*#field unowned=false DBus*VTable