private static void WriteRequest(Interface iface, Message r, int opcode, CSharpWriter w, CSharpWriter hlw) { WriteDescription(r.Element, w); WriteArgsDescription(r.Element, w); var parameters = new List <string>(); var argsString = opcode.ToString(); var args = new List <string>(); var before = new List <string>(); var after = new List <string>(); var ifaceArg = string.Empty; var ret = "void"; var hlwRet = "void"; var newId = false; var generic = false; foreach (var arg in r.Arguments) { if (arg.Type == ArgType.New_id) { newId = true; if (arg.Interface == null) { parameters.Add("wl_interface* iface"); parameters.Add("uint version"); ifaceArg = ", iface"; args.Add("iface->Name"); args.Add("version"); ret = "wl_proxy*"; hlwRet = "T*"; generic = true; } else { ifaceArg = $", {arg.Interface}.Interface"; ret = arg.Interface + '*'; hlwRet = Util.ToPascalCase(arg.Interface); // use implicit cast e.g. wl_display* => WlDisplay } // we just pass 0 because we don't care about the id // I didn't find this in the documentation, but the example // in the wayland client lib passes 0 so that's fine I guess? args.Add("0"); } else if (arg.Type == ArgType.String) { // TODO should this be in the low-level API? before.Add($"var {arg.Name}ByteCount = System.Text.Encoding.UTF8.GetByteCount({arg.Name});"); before.Add($"var {arg.Name}Bytes = stackalloc byte[{arg.Name}ByteCount + 1];"); before.Add($"Util.StringToUtf8({arg.Name}, {arg.Name}Bytes, {arg.Name}ByteCount);"); before.Add($"{arg.Name}Bytes[{arg.Name}ByteCount] = 0;"); parameters.Add(arg.ParamType + " " + arg.Name); args.Add(arg.Name + "Bytes"); } else { if (arg.IsEnumType) { // enum type can be with interface qualified or not; if not qualified it's an enum of this requests interface var type = arg.EnumType.Contains('.') ? arg.EnumType.Replace('.', '_') : $"{iface.RawName}_{arg.EnumType}"; parameters.Add($"{type} {arg.Name}"); args.Add("(int) " + arg.Name); } else { parameters.Add(arg.ParamType + " " + arg.Name); args.Add(arg.Name); } } } var paramsString = parameters.Any() ? parameters.Aggregate((s1, s2) => s1 + ", " + s2) : string.Empty; var paramsString2 = paramsString == string.Empty ? string.Empty : ", " + paramsString; // replace unsafe pointers with managed variants var hlParams = parameters.Select(p => MakeManagedParam(p)); var hlParamsString = hlParams.Any() ? hlParams.Aggregate((s1, s2) => s1 + ", " + s2) : string.Empty; // extract names from parameters var hlParamNames = hlParams.Select(p => p.Split(' ')) .Select(ptv => (ptv[0].Equals("IntPtr") ? "(wl_interface*) " : "") + ptv[ptv.Length - 1] + (ptv.Length == 3 ? ".Pointer" : "")); var hlArgs = hlParamNames.Any() ? ", " + hlParamNames.Aggregate((s1, s2) => s1 + ", " + s2) : string.Empty; var genericStr = generic ? "<T>" : ""; var genericConstrStr = generic ? " where T : unmanaged" : ""; var castStr = generic ? "(T*) " : ""; hlw.Append($"public {hlwRet} {r.NiceName}{genericStr}({hlParamsString}){genericConstrStr} => "); hlw.Line($"{castStr}{_protocolClassName}.{iface.RawName}_{r.RawName}(Pointer{hlArgs});"); w.Line($"public static {ret} {iface.RawName}_{r.RawName}({iface.RawName}* pointer{paramsString2})"); w.OpenBlock(); var createReturn = $"return ({ret}) ptr;"; foreach (var line in before) { w.Line(line); } var methodName = "WaylandClient.wl_proxy_marshal"; var array = args.Count > 0 && !(args.Count == 1 && newId); if (array) { methodName += "_array"; w.Line($"var args = stackalloc wl_argument[{args.Count()}];"); for (int i = 0; i < args.Count; i++) { var arg = (string)args[i]; w.Line($"args[{i}] = {arg};"); } argsString += ", args"; argsString += ifaceArg; } else { argsString += ifaceArg; if (newId) { argsString += ", null"; } } if (newId) { methodName += "_constructor"; } var newPtr = ret != "void" ? "var ptr = " : string.Empty; w.Line($"{newPtr}{methodName}((wl_proxy*) pointer, {argsString});"); foreach (var line in after) { w.Line(line); } if (ret != "void") { w.Line(createReturn); } w.CloseBlock(); }
private static void WriteEvents(Interface iface, CSharpWriter w, CSharpWriter hlw) { var events = iface.Events; foreach (var ev in events) { if (GenerateComments) { WriteDescription(ev.Element, w); } w.Line(GetEventDelegate(iface, ev)); w.Line(); } if (events.Length > 0) { w.Line($"internal struct {iface.RawName}_listener"); w.OpenBlock(); foreach (var ev in events) { w.Line($"public IntPtr {ev.RawName};"); } w.Line(); w.Line($"public static {iface.RawName}_listener* Alloc("); for (int i = 0; i < events.Length; i++) { var ev = events[i]; if (i != 0) { w.Line(","); } w.AppendIndented($"{GetDelegateName(iface, ev)} {ev.RawName}"); } w.Line(")"); w.OpenBlock(); w.Line($"var ret = ({iface.RawName}_listener*) Marshal.AllocHGlobal(sizeof({iface.RawName}_listener));"); w.Line($"Set(ret, {string.Join(",", events.Select(ev => ev.RawName))});"); w.Line("return ret;"); w.CloseBlock(); w.Line(); w.Line($"public static void Set({iface.RawName}_listener* listener"); foreach (var ev in events) { w.Line(","); w.AppendIndented($"{GetDelegateName(iface, ev)} {ev.RawName}"); } w.Line(")"); w.OpenBlock(); foreach (var ev in events) { w.Append($"if ({ev.RawName} != null) "); w.Line($"listener->{ev.RawName} = Marshal.GetFunctionPointerForDelegate<{GetDelegateName(iface, ev)}>({ev.RawName});"); } w.CloseBlock(); w.CloseBlock(); // struct listener w.Line(); if (GenerateComments) { w.DocSummary($"Set the callbacks for the given <see cref=\"{iface.RawName}\"/>."); foreach (var ev in events) { WriteArgsDescription(ev.Element, w); } } w.Line($"public static int {iface.RawName}_add_listener({iface.RawName}* iface, {iface.RawName}_listener* listener)"); w.OpenBlock(); w.Line("return WaylandClient.wl_proxy_add_listener((wl_proxy*) iface, listener, null);"); w.CloseBlock(); hlw.Append("public void SetListener("); for (var i = 0; i < events.Length; i++) { var ev = events[i]; hlw.Line(i == 0 ? "" : ","); hlw.AppendIndented($"{_protocolClassName}.{GetDelegateName(iface, ev)} {ev.RawName}"); } hlw.Line(")"); hlw.OpenBlock(); foreach (var ev in events) { hlw.Line($"_{ev.RawName} = {ev.RawName};"); } hlw.Line($"_listener = {_protocolClassName}.{iface.RawName}_listener.Alloc({string.Join(", ", events.Select(e => e.RawName))});"); hlw.Line($"{_protocolClassName}.{iface.RawName}_add_listener(Pointer, _listener);"); hlw.CloseBlock(); hlw.Line("public void FreeListener() { if (_listener != null) Marshal.FreeHGlobal((IntPtr) _listener); }"); } }