1 /*
2  * This file is part of gtkD.
3  *
4  * gtkD is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU Lesser General Public License
6  * as published by the Free Software Foundation; either version 3
7  * of the License, or (at your option) any later version, with
8  * some exceptions, please read the COPYING file.
9  *
10  * gtkD is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public License
16  * along with gtkD; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
18  */
19 
20 module utils.GtkFunction;
21 
22 import std.algorithm: among, startsWith;
23 import std.conv;
24 import std.range;
25 import std.string : chomp, splitLines, strip, removechars;
26 
27 import utils.GtkEnum;
28 import utils.GtkStruct;
29 import utils.GtkType;
30 import utils.GtkWrapper;
31 import utils.XML;
32 
33 enum GtkFunctionType : string
34 {
35 	Constructor = "constructor",
36 	Method = "method",
37 	Function = "function",
38 	Callback = "callback",
39 	Signal = "glib:signal"
40 }
41 
42 enum GtkTransferOwnership : string
43 {
44 	None = "none",          /// Gtk owns the returned reference.
45 	Full = "full",          /// We own the returned reference.
46 	Container = "container" /// The container in which the references reside has ownership.
47 }
48 
49 final class GtkFunction
50 {
51 	string name;
52 	GtkFunctionType type;
53 	string doc;
54 	string cType;
55 	string libVersion;
56 	string movedTo;
57 	bool virtual = false;
58 	bool throws = false;
59 	bool lookupOverride; /// Force marking this function with overrride.
60 	bool noCode; /// Don't generate any class code for this function.
61 
62 	GtkType returnType;
63 	GtkTransferOwnership returnOwnership = GtkTransferOwnership.None;
64 	GtkParam instanceParam;
65 	GtkParam[] params;
66 
67 	GtkWrapper wrapper;
68 	GtkStruct strct;
69 
70 	this (GtkWrapper wrapper, GtkStruct strct)
71 	{
72 		this.wrapper = wrapper;
73 		this.strct = strct;
74 	}
75 
76 	GtkFunction dup()
77 	{
78 		GtkFunction copy = new GtkFunction(wrapper, strct);
79 		
80 		foreach ( i, field; this.tupleof )
81 			copy.tupleof[i] = field;
82 		
83 		return copy;
84 	}
85 
86 	void parse(T)(XMLReader!T reader)
87 	{
88 		name = reader.front.attributes["name"];
89 		// Special case for g_iconv wich doesnt have a name.
90 		if ( name.empty && "moved-to" in reader.front.attributes )
91 			name = reader.front.attributes["moved-to"];
92 
93 		type = cast(GtkFunctionType)reader.front.value;
94 
95 		if ( "c:type" in reader.front.attributes )
96 			cType = reader.front.attributes["c:type"];
97 		if ( "c:identifier" in reader.front.attributes )
98 			cType = reader.front.attributes["c:identifier"];
99 		if ( "version" in reader.front.attributes )
100 			libVersion = reader.front.attributes["version"];
101 		if ( "throws" in reader.front.attributes )
102 			throws = reader.front.attributes["throws"] == "1";
103 		if ( "moved-to" in reader.front.attributes )
104 			movedTo = reader.front.attributes["moved-to"];
105 
106 		reader.popFront();
107 
108 		while( !reader.empty && !reader.endTag("constructor", "method", "function", "callback", "glib:signal") )
109 		{
110 			switch ( reader.front.value )
111 			{
112 				case "doc":
113 					reader.popFront();
114 					doc ~= reader.front.value;
115 					reader.popFront();
116 					break;
117 				case "doc-deprecated":
118 					reader.popFront();
119 					doc ~= "\n\nDeprecated: "~ reader.front.value;
120 					reader.popFront();
121 					break;
122 				case "doc-version":
123 					reader.skipTag();
124 					break;
125 				case "return-value":
126 					if ( "transfer-ownership" in reader.front.attributes )
127 						returnOwnership = cast(GtkTransferOwnership)reader.front.attributes["transfer-ownership"];
128 
129 					returnType = new GtkType(wrapper);
130 					reader.popFront();
131 
132 					while( !reader.empty && !reader.endTag("return-value") )
133 					{
134 						switch ( reader.front.value )
135 						{
136 							case "doc":
137 								reader.popFront();
138 								returnType.doc ~= reader.front.value;
139 								reader.popFront();
140 								break;
141 							case "array":
142 							case "type":
143 								returnType.parse(reader);
144 								break;
145 							default:
146 								throw new XMLException(reader, "Unexpected tag: "~ reader.front.value ~" in GtkFunction: "~ name);
147 						}
148 						reader.popFront();
149 					}
150 					break;
151 				case "parameters":
152 					reader.popFront();
153 					while( !reader.empty && !reader.endTag("parameters") )
154 					{
155 						switch ( reader.front.value )
156 						{
157 							case "instance-parameter":
158 								instanceParam = new GtkParam(wrapper);
159 								instanceParam.parse(reader);
160 								break;
161 							case "parameter":
162 								GtkParam param = new GtkParam(wrapper);
163 								param.parse(reader);
164 								params ~= param;
165 								break;
166 							default:
167 								throw new XMLException(reader, "Unexpected tag: "~ reader.front.value ~" in GtkFunction: "~ name);
168 						}
169 						reader.popFront();
170 					}
171 					break;
172 				default:
173 					throw new XMLException(reader, "Unexpected tag: "~ reader.front.value ~" in GtkFunction: "~ name);
174 			}
175 			reader.popFront();
176 		}
177 
178 		if ( type == GtkFunctionType.Function && name.startsWith("new") && returnType.cType != "void" )
179 			type = GtkFunctionType.Constructor;
180 
181 		if ( cType.among("gst_init", "gst_init_check") )
182 		{
183 			params[1].type.cType = "char***";
184 			params[1].type.elementType.cType = "char**";
185 		}
186 	}
187 
188 	bool isVariadic()
189 	{
190 		if ( params.empty )
191 			return false;
192 		else if ( params[$-1].name == "..." )
193 			return true;
194 
195 		return false;
196 	}
197 
198 	string[] getCallbackDeclaration()
199 	{
200 		string[] buff;
201 
202 		writeDocs(buff);
203 		buff ~= "public alias extern(C) "~ getExternalFunctionType() ~" "~ tokenToGtkD(cType, wrapper.aliasses, localAliases()) ~";";
204 
205 		return buff;
206 	}
207 
208 	string[] getFunctionPointerDecleration()
209 	{
210 		string[] buff;
211 
212 		writeDocs(buff);
213 		buff ~= "extern(C) "~ getExternalFunctionType() ~" "~ tokenToGtkD(name, wrapper.aliasses, localAliases()) ~";";
214 
215 		return buff;
216 	}
217 
218 	string getExternal()
219 	{
220 		assert(type != GtkFunctionType.Callback);
221 		assert(type != GtkFunctionType.Signal);
222 
223 		if (strct.pack.name == "glgdk")
224 			return getExternalFunctionType() ~" glc_"~ cType ~";";
225 		else
226 			return getExternalFunctionType() ~" c_"~ cType ~";";
227 	}
228 
229 	private string getExternalFunctionType()
230 	{
231 		string ext;
232 		string type = stringToGtkD(returnType.cType, wrapper.aliasses, localAliases());
233 
234 		if ( type.startsWith("bool") )
235 			ext ~= type.replaceFirst("bool", "int");
236 		else
237 			ext ~= type;
238 
239 		ext ~= " function(";
240 
241 		if ( instanceParam )
242 		{
243 			ext ~= stringToGtkD(instanceParam.type.cType, wrapper.aliasses, localAliases());
244 			ext ~= " ";
245 			ext ~= tokenToGtkD(instanceParam.name, wrapper.aliasses, localAliases());
246 		}
247 
248 		foreach ( i, param; params )
249 		{
250 			if ( i > 0 || instanceParam )
251 				ext ~= ", ";
252 
253 			type = stringToGtkD(param.type.cType, wrapper.aliasses, localAliases());
254 
255 			if ( type.startsWith("bool") )
256 				ext ~= type.replaceFirst("bool", "int");
257 			else
258 				ext ~= type;
259 
260 			ext ~= " ";
261 			//Both name and type are ... for Variadic functions.
262 			if ( param.name != "..." )
263 				ext ~= tokenToGtkD(param.name, wrapper.aliasses, localAliases());
264 		}
265 
266 		if ( throws )
267 			ext ~= ", GError** err";
268 
269 		ext ~= ")";
270 
271 		return ext;
272 	}
273 
274 	string[] getDeclaration()
275 	{
276 		string[] buff;
277 		string dec = "public ";
278 
279 		resolveLength();
280 		writeDocs(buff);
281 
282 		if ( type == GtkFunctionType.Constructor )
283 		{
284 			dec ~= "this(";
285 		}
286 		else
287 		{
288 			if ( isStatic() )
289 				dec ~= "static ";
290 
291 			if ( lookupOverride || checkOverride() )
292 				dec ~= "override ";
293 
294 			dec ~= getType(returnType) ~" ";
295 			dec ~= tokenToGtkD(name, wrapper.aliasses, localAliases()) ~"(";
296 		}
297 
298 		size_t paramCount;
299 
300 		if ( instanceParam && type == GtkFunctionType.Method && (strct.isNamespace() || strct.noNamespace ) )
301 		{
302 			dec ~= getType(instanceParam.type) ~" "~ tokenToGtkD(instanceParam.name, wrapper.aliasses, localAliases());
303 			paramCount++;
304 		}
305 
306 		foreach( param; params )
307 		{
308 			if ( param.lengthFor )
309 				continue;
310 
311 			if ( returnType.length > -1 && param == params[returnType.length] )
312 				continue;
313 
314 			if ( paramCount == 0 && strct.type == GtkStructType.Record && isInstanceParam(param) )
315 				continue;
316 
317 			if ( paramCount++ > 0 )
318 				dec ~= ", ";
319 
320 			if ( param.direction == GtkParamDirection.Out )
321 				dec ~= "out ";
322 			else if ( param.direction == GtkParamDirection.InOut )
323 				dec ~= "ref ";
324 
325 			dec ~= getType(param.type, param.direction) ~" ";
326 			dec ~= tokenToGtkD(param.name, wrapper.aliasses, localAliases());
327 		}
328 
329 		dec ~= ")";
330 		buff ~= dec;
331 
332 		return buff;
333 	}
334 
335 	string[] getBody()
336 	{
337 		string[] buff;
338 		string[] outToD;
339 		string gtkCall = cType ~"(";
340 
341 		GtkStruct returnDType;
342 
343 		if ( returnType.isArray() )
344 			returnDType = strct.pack.getStruct(returnType.elementType.name);
345 		else
346 			returnDType = strct.pack.getStruct(returnType.name);
347 
348 		if ( instanceParam || ( !params.empty && isInstanceParam(params[0])) )
349 		{
350 			GtkStruct dType;
351 
352 			if ( instanceParam )
353 			{
354 				dType = strct.pack.getStruct(instanceParam.type.name);
355 
356 				if ( dType.cType != instanceParam.type.cType.removechars("*") && !instanceParam.type.cType.among("gpointer", "gconstpointer") )
357 					gtkCall ~= "cast("~ stringToGtkD(instanceParam.type.cType, wrapper.aliasses, localAliases()) ~")";
358 			}
359 			else
360 			{
361 				dType = strct.pack.getStruct(params[0].type.name);
362 
363 				if ( dType.cType != params[0].type.cType.removechars("*") && !params[0].type.cType.among("gpointer", "gconstpointer") )
364 					gtkCall ~= "cast("~ stringToGtkD(params[0].type.cType, wrapper.aliasses, localAliases()) ~")";
365 			}
366 
367 			if ( instanceParam && instanceParam.type.name in strct.structWrap )
368 			{
369 				GtkStruct insType = strct.pack.getStruct(strct.structWrap[instanceParam.type.name]);
370 
371 				if ( insType )
372 					dType = insType;
373 			}
374 
375 			if ( strct.isNamespace() || strct.noNamespace )
376 			{
377 				string id = tokenToGtkD(instanceParam.name, wrapper.aliasses, localAliases());
378 
379 				if ( dType && !(dType.isNamespace() || dType.noNamespace) )
380 					gtkCall ~= "("~ id ~" is null) ? null : "~ id ~"."~ dType.getHandleFunc() ~"()";
381 				else
382 					gtkCall ~= id;
383 			}
384 			else if ( dType.type == GtkStructType.Interface || dType.lookupInterface )
385 			{
386 				gtkCall ~= strct.getHandleFunc() ~"()";
387 			}
388 			else
389 			{
390 				gtkCall ~= strct.getHandleVar();
391 			}
392 		}
393 
394 		foreach( i, param; params )
395 		{
396 			GtkStruct dType;
397 			string id = tokenToGtkD(param.name, wrapper.aliasses, localAliases());
398 
399 			if ( param.type.isArray() )
400 				dType = strct.pack.getStruct(param.type.elementType.name);
401 			else if ( auto dStrct = strct.pack.getStruct(strct.structWrap.get(param.type.name, "")) )
402 				dType = dStrct;
403 			else
404 				dType = strct.pack.getStruct(param.type.name);
405 
406 			if ( i == 0 && isInstanceParam(param) )
407 				continue;
408 
409 			if ( instanceParam || i > 0 )
410 				gtkCall ~= ", ";
411 
412 			if ( isStringType(param.type) )
413 			{
414 				if ( isStringArray(param.type, param.direction) )
415 				{
416 					// out string[], ref string[]
417 					if ( param.direction != GtkParamDirection.Default )
418 					{
419 						buff ~= "char** out"~ id ~" = ";
420 
421 						if ( param.direction == GtkParamDirection.Out )
422 							buff[$-1] ~= "null;";
423 						else
424 							buff[$-1] ~= "Str.toStringzArray("~ id ~");";
425 
426 						string len = lenId(param.type);
427 						if ( !len.empty )
428 							len = ", "~ len;
429 
430 						gtkCall ~= "&out"~ id;
431 						outToD ~= id ~" = Str.toStringArray(out"~ id ~ len ~");";
432 					}
433 					// string[]
434 					else
435 					{
436 						gtkCall ~= "Str.toStringzArray("~ id ~")";
437 					}
438 				}
439 				else
440 				{
441 					if ( param.direction != GtkParamDirection.Default )
442 					{
443 						string len = lenId(param.type);
444 
445 						// A buffer to fill.
446 						if ( !param.type.cType.endsWith("**") )
447 						{
448 							gtkCall ~= id ~".ptr";
449 
450 							if ( !len.empty && params[param.type.length].direction != GtkParamDirection.Default )
451 								outToD ~= id ~" = "~ id ~"[0.."~ len ~"];";
452 						}
453 						// out string, ref string
454 						else
455 						{
456 							buff ~= "char* out"~ id ~" = ";
457 
458 							if ( param.direction == GtkParamDirection.Out )
459 								buff[$-1] ~= "null;";
460 							else
461 								buff[$-1] ~= "Str.toStringz("~ id ~");";
462 
463 							if ( !len.empty )
464 								len = ", "~ len;
465 
466 							gtkCall ~= "&out"~ id;
467 							outToD ~= id ~" = Str.toString(out"~ id ~ len ~");";
468 						}
469 					}
470 					// string
471 					else
472 					{
473 						gtkCall ~= "Str.toStringz("~ id ~")";
474 					}
475 				}
476 			}
477 			else if ( isDType(dType) )
478 			{
479 				if ( param.type.isArray() )
480 				{
481 					GtkType elementType = param.type.elementType;
482 					GtkStruct dElementType = strct.pack.getStruct(elementType.name);
483 
484 					if ( elementType.cType.empty )
485 						elementType.cType = stringToGtkD(param.type.cType, wrapper.aliasses, localAliases())[0 .. $-1];
486 
487 					// out gtkdType[], ref gtkdType[]
488 					if ( param.direction != GtkParamDirection.Default )
489 					{
490 						if ( param.direction == GtkParamDirection.Out )
491 						{
492 							buff ~= elementType.cType ~" out"~ id ~" = null;";
493 						}
494 						else
495 						{
496 							if ( !buff.empty )
497 								buff ~= "";
498 							buff ~= elementType.cType.removechars("*") ~ "**[] inout"~ id ~" = new "~ elementType.cType.removechars("*") ~"*["~ id ~".length];";
499 							buff ~= "for ( int i = 0; i < "~ id ~".length; i++ )";
500 							buff ~= "{";
501 							buff ~= "inout"~ id ~"[i] = "~ id~ "[i]."~ dElementType.getHandleFunc() ~"();";
502 							buff ~= "}";
503 							buff ~= "";
504 							buff ~= elementType.cType.removechars("*") ~ "** out"~ id ~" = inout"~ id ~".ptr;";
505 						}
506 
507 						gtkCall ~= "&out"~ id;
508 
509 						if ( !outToD.empty )
510 							outToD ~= "";
511 						outToD ~= id ~" = new "~ dElementType.name ~"["~ lenId(param.type, "out"~ id) ~"];";
512 						outToD ~= "for(size_t i = 0; i < "~ lenId(param.type, "out"~ id) ~"; i++)";
513 						outToD ~= "{";
514 						if ( elementType.cType.endsWith("**") )
515 							outToD ~= id ~"[i] = " ~ construct(elementType.name) ~ "(cast(" ~ elementType.cType[0..$-1] ~ ") out"~ id ~"[i]);";
516 						else
517 							outToD ~= id ~"[i] = " ~ construct(elementType.name) ~ "(cast(" ~ elementType.cType ~ ") &out"~ id ~"[i]);";
518 						outToD ~= "}";
519 					}
520 					// gtkdType[]
521 					else
522 					{
523 						//TODO: zero-terminated see: g_signal_chain_from_overridden
524 						if ( !buff.empty )
525 							buff ~= "";
526 						buff ~= elementType.cType ~ "[] "~ id ~"Array = new "~ elementType.cType ~"["~ id ~".length];";
527 						buff ~= "for ( int i = 0; i < "~ id ~".length; i++ )";
528 						buff ~= "{";
529 						if ( elementType.cType.endsWith("*") )
530 							buff ~= id ~"Array[i] = "~ id ~"[i]."~ dElementType.getHandleFunc() ~"();";
531 						else
532 							buff ~= id ~"Array[i] = *("~ id ~"[i]."~ dElementType.getHandleFunc() ~"());";
533 						buff ~= "}";
534 						buff ~= "";
535 
536 						gtkCall ~= id ~"Array.ptr";
537 					}
538 				}
539 				else
540 				{
541 					// out gtkdType, ref gtkdType
542 					if ( param.direction != GtkParamDirection.Default && param.type.cType.endsWith("**") )
543 					{
544 						buff ~= param.type.cType.removechars("*") ~"* out"~ id ~" = ";
545 
546 						if ( param.direction == GtkParamDirection.Out )
547 							buff[$-1] ~= "null;";
548 						else
549 							buff[$-1] ~= id ~"."~ dType.getHandleFunc() ~"();";
550 
551 						gtkCall ~= "&out"~ id;
552 
553 						outToD ~= id ~" = "~ construct(param.type.name) ~"(out"~ id ~");";
554 					}
555 					else if ( param.direction == GtkParamDirection.Out )
556 					{
557 						buff ~= param.type.cType.removechars("*") ~"* out"~ id ~" = gMalloc!"~ param.type.cType.removechars("*") ~"();";
558 
559 						gtkCall ~= "out"~ id;
560 
561 						outToD ~= id ~" = "~ construct(param.type.name) ~"(out"~ id ~", true);";
562 					}
563 					// gtkdType
564 					else
565 					{
566 						gtkCall ~= "("~ id ~" is null) ? null : ";
567 						if ( dType.cType != param.type.cType.removechars("*") && !param.type.cType.among("gpointer", "gconstpointer") )
568 							gtkCall ~= "cast("~ stringToGtkD(param.type.cType, wrapper.aliasses, localAliases()) ~")";
569 						gtkCall ~= id ~"."~ dType.getHandleFunc ~"()";
570 					}
571 				}
572 			}
573 			else if ( param.lengthFor || returnType.length == i )
574 			{
575 				string arrId;
576 				string lenType = tokenToGtkD(param.type.cType.removechars("*"), wrapper.aliasses, localAliases());
577 
578 				if ( param.lengthFor )
579 					arrId = tokenToGtkD(param.lengthFor.name, wrapper.aliasses, localAliases());
580 
581 				final switch ( param.direction ) with (GtkParamDirection)
582 				{
583 					case Default:
584 						gtkCall ~= "cast("~ lenType ~")"~ arrId ~".length";
585 						break;
586 					case Out:
587 						buff ~= lenType ~" "~ id ~";";
588 						gtkCall ~= "&"~id;
589 						break;
590 					case InOut:
591 						buff ~= lenType ~" "~ id ~" = cast("~ lenType ~")"~ arrId ~".length;";
592 						gtkCall ~= "&"~id;
593 						break;
594 				}
595 			}
596 			else if ( param.type.name.among("bool", "gboolean") || ( param.type.isArray && param.type.elementType.name.among("bool", "gboolean") ) )
597 			{
598 				if ( param.type.isArray() )
599 				{
600 					// out bool[], ref bool[]
601 					if ( param.direction != GtkParamDirection.Default )
602 					{
603 						if ( param.direction == GtkParamDirection.Out )
604 						{
605 							buff ~= "int* out"~ id ~" = null;";
606 						}
607 						else
608 						{
609 							if ( !buff.empty )
610 								buff ~= "";
611 							buff ~= "int[] inout"~ id ~" = new int["~ id ~".length];";
612 							buff ~= "for ( int i = 0; i < "~ id ~".length; i++ )";
613 							buff ~= "{";
614 							buff ~= "inout"~ id ~"[i] = "~ id~ "[i] ? 1 : 0;";
615 							buff ~= "}";
616 							buff ~= "";
617 							buff ~= "int* out"~ id ~" = inout"~ id ~".ptr;";
618 						}
619 
620 						gtkCall ~= "&out"~ id;
621 
622 						if ( !outToD.empty )
623 							outToD ~= "";
624 						outToD ~= id ~" = new bool["~ lenId(param.type, "out"~ id) ~"];";
625 						outToD ~= "for(size_t i = 0; i < "~ lenId(param.type, "out"~ id) ~"; i++)";
626 						outToD ~= "{";
627 						outToD ~= id ~"[i] = out"~ id ~"[i] != 0);";
628 						outToD ~= "}";
629 					}
630 					// bool[]
631 					else
632 					{
633 						if ( !buff.empty )
634 							buff ~= "";
635 						buff ~= "int[] "~ id ~"Array = new int["~ id ~".length];";
636 						buff ~= "for ( int i = 0; i < "~ id ~".length; i++ )";
637 						buff ~= "{";
638 						buff ~= id ~"Array[i] = "~ id ~"[i] ? 1 : 0;";
639 						buff ~= "}";
640 						buff ~= "";
641 
642 						gtkCall ~= id ~"Array.ptr";
643 					}
644 				}
645 				else
646 				{
647 					// out bool, ref bool
648 					if ( param.direction != GtkParamDirection.Default )
649 					{
650 						buff ~= "int out"~ id;
651 
652 						if ( param.direction == GtkParamDirection.Out )
653 							buff[$-1] ~= ";";
654 						else
655 							buff[$-1] ~= " = ("~ id ~" ? 1 : 0);";
656 
657 						gtkCall ~= "&out"~ id ~"";
658 						outToD ~= id ~" = (out"~ id ~" == 1);";
659 					}
660 					// bool
661 					else
662 					{
663 						gtkCall ~= id;
664 					}
665 				}
666 			}
667 			else
668 			{
669 				if ( param.type.isArray() )
670 				{
671 					// out T[], ref T[]
672 					if ( param.direction != GtkParamDirection.Default )
673 					{
674 						string outType = param.type.elementType.cType;
675 						if ( outType.empty )
676 							outType = param.type.elementType.name ~"*";
677 
678 						buff ~= stringToGtkD(outType, wrapper.aliasses, localAliases) ~" out"~ id ~" = ";
679 
680 						if ( param.direction == GtkParamDirection.Out )
681 							buff[$-1] ~= "null;";
682 						else
683 							buff[$-1] ~= id ~".ptr";
684 
685 						if ( param.type.elementType.cType.empty )
686 							gtkCall ~= "cast("~stringToGtkD(param.type.cType, wrapper.aliasses, localAliases) ~")&out"~ id ~"";
687 						else
688 							gtkCall ~= "&out"~ id ~"";
689 
690 						outToD ~= id ~" = out"~ id ~"[0 .. "~ lenId(param.type, "out"~ id) ~"];";
691 					}
692 					// T[]
693 					else
694 					{
695 						gtkCall ~= id ~".ptr";
696 					}
697 				}
698 				else
699 				{
700 					if ( param.type.name in strct.structWrap )
701 					{
702 						gtkCall ~= "("~ id ~" is null) ? null : "~ id ~".get"~ strct.structWrap[param.type.name] ~"Struct()";
703 					}
704 					else
705 					{
706 						// out T, ref T
707 						if ( param.direction != GtkParamDirection.Default )
708 						{
709 							gtkCall ~= "&"~ id;
710 						}
711 						// T
712 						else
713 						{
714 							gtkCall ~= id;
715 						}
716 					}
717 				}
718 			}
719 		}
720 
721 		if ( throws )
722 		{
723 			buff ~= "GError* err = null;";
724 			gtkCall ~= ", &err";
725 		}
726 
727 		enum throwGException = [
728 			"",
729 			"if (err !is null)",
730 			"{",
731 			"throw new GException( new ErrorG(err) );",
732 			"}"];
733 
734 		gtkCall ~= ")";
735 
736 		if ( !buff.empty && buff[$-1] != "" )
737 			buff ~= "";
738 
739 		if ( returnType.name == "none" )
740 		{
741 			buff ~= gtkCall ~";";
742 
743 			if ( throws )
744 			{
745 				buff ~= throwGException;
746 			}
747 
748 			if ( !outToD.empty )
749 			{
750 				buff ~= "";
751 				buff ~= outToD;
752 			}
753 
754 			return buff;
755 		}
756 		else if ( type == GtkFunctionType.Constructor )
757 		{
758 			buff ~= "auto p = " ~ gtkCall ~";";
759 
760 			if ( throws )
761 			{
762 				buff ~= throwGException;
763 			}
764 
765 			buff ~= "";
766 			buff ~= "if(p is null)";
767 			buff ~= "{";
768 			buff ~= "throw new ConstructionException(\"null returned by " ~ name ~ "\");";
769 			buff ~= "}";
770 			buff ~= "";
771 
772 			if ( !outToD.empty )
773 			{
774 				buff ~= outToD;
775 				buff ~= "";
776 			}
777 
778 			/*
779 			 * Casting is needed because some GTK+ functions
780 			 * can return void pointers or base types.
781 			 */
782 			if ( returnOwnership == GtkTransferOwnership.Full && strct.getAncestor().name == "ObjectG" )
783 				buff ~= "this(cast(" ~ strct.cType ~ "*) p, true);";
784 			else
785 				buff ~= "this(cast(" ~ strct.cType ~ "*) p);";
786 
787 			return buff;
788 		}
789 		else if ( isStringType(returnType) )
790 		{
791 			if ( outToD.empty && !throws && !(returnOwnership == GtkTransferOwnership.Full) )
792 			{
793 				if ( isStringArray(returnType) )
794 					buff ~= "return Str.toStringArray(" ~ gtkCall ~");";
795 				else
796 					buff ~= "return Str.toString(" ~ gtkCall ~");";
797 
798 				return buff;
799 			}
800 
801 			buff ~= "auto retStr = "~ gtkCall ~";";
802 
803 			if ( throws )
804 			{
805 				buff ~= throwGException;
806 			}
807 
808 			buff ~= "";
809 
810 			if ( !outToD.empty )
811 			{
812 				buff ~= outToD;
813 				buff ~= "";
814 			}
815 
816 			if ( returnOwnership == GtkTransferOwnership.Full )
817 			{
818 				if ( isStringArray(returnType) )
819 					buff ~= "scope(exit) Str.freeStringArray(retStr);";
820 				else
821 					buff ~= "scope(exit) Str.freeString(retStr);";
822 			}
823 
824 			string len = lenId(returnType);
825 			if ( !len.empty )
826 				len = ", "~ len;
827 
828 			if ( isStringArray(returnType) )
829 				buff ~= "return Str.toStringArray(retStr"~ len ~");";
830 			else
831 				buff ~= "return Str.toString(retStr"~ len ~");";
832 
833 			return buff;
834 		}
835 		else if ( isDType(returnDType) )
836 		{
837 			buff ~= "auto p = "~ gtkCall ~";";
838 
839 			if ( throws )
840 			{
841 				buff ~= throwGException;
842 			}
843 
844 			if ( !outToD.empty )
845 			{
846 				buff ~= "";
847 				buff ~= outToD;
848 			}
849 
850 			buff ~= "";
851 			buff ~= "if(p is null)";
852 			buff ~= "{";
853 			buff ~= "return null;";
854 			buff ~= "}";
855 			buff ~= "";
856 
857 			if ( returnType.isArray() )
858 			{
859 				buff ~= returnDType.name ~"[] arr = new "~ returnDType.name ~"["~ lenId(returnType) ~"];";
860 				buff ~= "for(int i = 0; i < "~ lenId(returnType) ~"; i++)";
861 				buff ~= "{";
862 				if ( returnType.elementType.cType.endsWith("*") )
863 					buff ~= "\tarr[i] = "~ construct(returnType.elementType.name) ~"(cast("~ returnType.elementType.cType ~") p[i]);";
864 				else
865 					buff ~= "\tarr[i] = "~ construct(returnType.elementType.name) ~"(cast("~ returnType.elementType.cType ~"*) &p[i]);";
866 				buff ~= "}";
867 				buff ~= "";
868 				buff ~= "return arr;";
869 			}
870 			else
871 			{
872 				if ( returnOwnership == GtkTransferOwnership.Full && !(returnDType.pack.name == "cairo") )
873 					buff ~= "return "~ construct(returnType.name) ~"(cast("~ returnDType.cType ~"*) p, true);";
874 				else
875 					buff ~= "return "~ construct(returnType.name) ~"(cast("~ returnDType.cType ~"*) p);";
876 			}
877 
878 			return buff;
879 		}
880 		else
881 		{
882 			if ( returnType.name == "gboolean" )
883 				gtkCall ~= " != 0";
884 
885 			if ( !returnType.isArray && outToD.empty && !throws )
886 			{
887 				buff ~= "return "~ gtkCall ~";";
888 				return buff;
889 			}
890 
891 			buff ~= "auto p = "~ gtkCall ~";";
892 
893 			if ( throws )
894 			{
895 				buff ~= throwGException;
896 			}
897 
898 			if ( !outToD.empty )
899 			{
900 				buff ~= "";
901 				buff ~= outToD;
902 			}
903 
904 			buff ~= "";
905 			if ( returnType.isArray() )
906 			{
907 				if ( returnType.elementType.name == "gboolean" )
908 				{
909 					buff ~= "bool[] r = new bool["~ lenId(returnType) ~"];";
910 					buff ~= "for(size_t i = 0; i < "~ lenId(returnType) ~"; i++)";
911 					buff ~= "{";
912 					buff ~= "r[i] = p[i] != 0;";
913 					buff ~= "}";
914 					buff ~= "return r;";
915 				}
916 				else if ( returnType.elementType.cType.empty && returnType.cType[0..$-1] != returnType.elementType.name )
917 				{
918 					buff ~= "return cast("~ getType(returnType) ~")p[0 .. "~ lenId(returnType) ~"];";
919 				}
920 				else
921 				{
922 					buff ~= "return p[0 .. "~ lenId(returnType) ~"];";
923 				}
924 			}
925 			else
926 				buff ~= "return p;";
927 
928 			return buff;
929 		}
930 
931 		assert(false, "Unexpected function: "~ name);
932 	}
933 
934 	string getSignalName()
935 	{
936 		assert(type == GtkFunctionType.Signal);
937 
938 		char pc;
939 		string signalName;
940 
941 		foreach ( size_t count, char c; name )
942 		{
943 			if ( count == 0 )
944 			{
945 				signalName ~= std.ascii.toUpper(c);
946 			}
947 			else
948 			{
949 				if ( c!='-' && c!='_' )
950 				{
951 					if ( pc=='-' || pc=='_' )
952 						signalName ~= toUpper(c);
953 					else
954 						signalName ~= c;
955 				}
956 			}
957 			pc = c;
958 		}
959 
960 		if ( !signalName.among("MapEvent", "UnmapEvent", "DestroyEvent") &&
961 		    endsWith(signalName, "Event") )
962 		{
963 			signalName = signalName[0..signalName.length-5];
964 		}
965 
966 		return signalName;
967 	}
968 
969 	string getDelegateDecleration()
970 	{
971 		assert(type == GtkFunctionType.Signal);
972 
973 		string buff = getType(returnType) ~ " delegate(";
974 
975 		foreach ( param; params )
976 		{
977 			//TODO: Signals with arrays.
978 			if ( param.type.cType == "gpointer" && param.type.isArray() )
979 				buff ~= "void*, ";
980 			else
981 				buff ~= getType(param.type) ~ ", ";
982 		}
983 
984 		if ( strct.type == GtkStructType.Interface )
985 			buff ~= strct.name ~"IF)";
986 		else
987 			buff ~= strct.name ~")";
988 
989 		return buff;
990 	}
991 
992 	string[] getAddListenerdeclaration()
993 	{
994 		string[] buff;
995 
996 		writeDocs(buff);
997 		buff ~= "void addOn"~ getSignalName() ~"("~ getDelegateDecleration() ~" dlg, ConnectFlags connectFlags=cast(ConnectFlags)0)";
998 
999 		return buff;
1000 	}
1001 
1002 	string[] getAddListenerBody()
1003 	{
1004 		string[] buff;
1005 		string realName = name;
1006 		
1007 		if ( name.endsWith("-generic-event") )
1008 			realName = name[0..$-14];
1009 
1010 		buff ~= "{";
1011 		buff ~= "if ( \""~ name ~"\" !in connectedSignals )";
1012 		buff ~= "{";
1013 
1014 		if ( strct.name != "StatusIcon")
1015 		{
1016 			switch ( realName )
1017 			{
1018 				case  "button-press-event":      buff ~= "addEvents(EventMask.BUTTON_PRESS_MASK);";      break;
1019 				case  "button-release-event":    buff ~= "addEvents(EventMask.BUTTON_RELEASE_MASK);";    break;
1020 				case  "enter-notify-event":      buff ~= "addEvents(EventMask.ENTER_NOTIFY_MASK);";      break;
1021 				case  "focus-in-event":          buff ~= "addEvents(EventMask.FOCUS_CHANGE_MASK);";      break;
1022 				case  "focus-out-event":         buff ~= "addEvents(EventMask.FOCUS_CHANGE_MASK);";      break;
1023 				case  "key-press-event":         buff ~= "addEvents(EventMask.KEY_PRESS_MASK);";         break;
1024 				case  "key-release-event":       buff ~= "addEvents(EventMask.KEY_RELEASE_MASK);";       break;
1025 				case  "leave-notify-event":      buff ~= "addEvents(EventMask.LEAVE_NOTIFY_MASK);";      break;
1026 				case  "motion-notify-event":     buff ~= "addEvents(EventMask.POINTER_MOTION_MASK);";    break;
1027 				case  "property-notify-event":   buff ~= "addEvents(EventMask.PROPERTY_CHANGE_MASK);";   break;
1028 				case  "proximity-in-event":      buff ~= "addEvents(EventMask.PROXIMITY_IN_MASK);";      break;
1029 				case  "proximity-out-event":     buff ~= "addEvents(EventMask.PROXIMITY_OUT_MASK);";     break;
1030 				case  "scroll-event":            buff ~= "addEvents(EventMask.SCROLL_MASK);";            break;
1031 				case  "visibility-notify-event": buff ~= "addEvents(EventMask.VISIBILITY_NOTIFY_MASK);"; break;
1032 
1033 				default: break;
1034 			}
1035 		}
1036 
1037 		buff ~= "Signals.connectData(";
1038 		buff ~= "this,";
1039 		buff ~= "\""~ realName ~"\",";
1040 		buff ~= "cast(GCallback)&callBack"~ getSignalName() ~",";
1041 
1042 		if ( strct.type == GtkStructType.Interface )
1043 			buff ~= "cast(void*)cast("~ strct.name ~"IF)this,";
1044 		else
1045 			buff ~= "cast(void*)this,";
1046 
1047 		buff ~= "null,";
1048 		buff ~= "connectFlags);";
1049 		buff ~= "connectedSignals[\""~ name ~"\"] = 1;";
1050 		buff ~= "}";
1051 
1052 		if ( strct.type == GtkStructType.Interface )
1053 			buff ~= "_on"~ getSignalName() ~"Listeners ~= dlg;";
1054 		else
1055 			buff ~= "on"~ getSignalName() ~"Listeners ~= dlg;";
1056 
1057 		buff ~= "}";
1058 
1059 		return buff;
1060 	}
1061 
1062 	string[] getSignalCallback()
1063 	{
1064 		string[] buff;
1065 		string type = getType(returnType);
1066 		GtkStruct dType = strct.pack.getStruct(returnType.name);
1067 
1068 		if ( dType )
1069 			type = dType.cType ~"*";
1070 
1071 		buff ~= "extern(C) static "~ (type == "bool" ? "int" : type)
1072 			~" callBack"~ getSignalName() ~"("~ getCallbackParams() ~")";
1073 
1074 		buff ~= "{";
1075 
1076 		if ( type == "bool" )
1077 		{
1078 			buff ~= "foreach ( "~ getDelegateDecleration() ~" dlg; _"~ strct.name.toLower() ~".on"~ getSignalName() ~"Listeners )";
1079 			buff ~= "{";
1080 			buff ~= "if ( dlg("~ getCallbackVars() ~") )";
1081 			buff ~= "{";
1082 			buff ~= "return 1;";
1083 			buff ~= "}";
1084 			buff ~= "}";
1085 			buff ~= "";
1086 			buff ~= "return 0;";
1087 		}
1088 		else if ( type == "void" )
1089 		{
1090 			buff ~= "foreach ( "~ getDelegateDecleration() ~" dlg; _"~ strct.name.toLower() ~".on"~ getSignalName() ~"Listeners )";
1091 			buff ~= "{";
1092 			buff ~= "dlg("~ getCallbackVars() ~");";
1093 			buff ~= "}";
1094 		}
1095 		else if ( dType )
1096 		{
1097 			buff ~= "foreach ( "~ getDelegateDecleration() ~" dlg; _"~ strct.name.toLower() ~".on"~ getSignalName() ~"Listeners )";
1098 			buff ~= "{";
1099 			buff ~= "if ( auto r = dlg("~ getCallbackVars() ~") )";
1100 			buff ~= "return r."~ dType.getHandleFunc() ~"();";
1101 			buff ~= "}";
1102 			buff ~= "";
1103 			buff ~= "return null;";
1104 		}
1105 		else
1106 		{
1107 			buff ~= "return _"~ strct.name.toLower() ~".on"~ getSignalName() ~"Listeners[0]("~ getCallbackVars() ~");";
1108 		}
1109 
1110 		buff ~= "}";
1111 
1112 		return buff;
1113 	}
1114 
1115 	void writeDocs(ref string[] buff)
1116 	{
1117 		if ( (doc || returnType.doc) && wrapper.includeComments )
1118 		{
1119 			buff ~= "/**";
1120 			foreach ( line; doc.splitLines() )
1121 				buff ~= " * "~ line.strip();
1122 
1123 			if ( !params.empty )
1124 			{
1125 				buff ~= " *";
1126 				buff ~= " * Params:";
1127 
1128 				foreach ( param; params )
1129 				{
1130 					if ( param.doc.empty )
1131 						continue;
1132 
1133 					if ( returnType.length > -1 && param == params[returnType.length] )
1134 						continue;
1135 
1136 					if ( isInstanceParam(param) )
1137 						continue;
1138 
1139 					string[] lines = param.doc.splitLines();
1140 					buff ~= " *     "~ tokenToGtkD(param.name, wrapper.aliasses, localAliases()) ~" = "~ lines[0];
1141 					foreach( line; lines[1..$] )
1142 						buff ~= " *         "~ line.strip();
1143 				}
1144 
1145 				if ( buff.endsWith(" * Params:") )
1146 					buff = buff[0 .. $-2];
1147 			}
1148 
1149 			if ( returnType.doc )
1150 			{
1151 				string[] lines = returnType.doc.splitLines();
1152 				if ( doc )
1153 					buff ~= " *";
1154 				buff ~= " * Return: "~ lines[0];
1155 
1156 				foreach( line; lines[1..$] )
1157 					buff ~= " *     "~ line.strip();
1158 			}
1159 
1160 			if ( libVersion )
1161 			{
1162 				buff ~= " *";
1163 				buff ~= " * Since: "~ libVersion;
1164 			}
1165 
1166 			if ( throws || type == GtkFunctionType.Constructor )
1167 				buff ~= " *";
1168 
1169 			if ( throws )
1170 				buff ~= " * Throws: GException on failure.";
1171 
1172 			if ( type == GtkFunctionType.Constructor )
1173 				buff ~= " * Throws: ConstructionException GTK+ fails to create the object.";
1174 
1175 			buff ~= " */";
1176 		}
1177 		else if ( wrapper.includeComments )
1178 		{
1179 			buff ~= "/** */\n";
1180 		}
1181 	}
1182 
1183 	private void resolveLength()
1184 	{
1185 		foreach( param; params )
1186 		{
1187 			if ( param.type.length > -1 )
1188 				params[param.type.length].lengthFor = param;
1189 		}
1190 	}
1191 
1192 	private string[string] localAliases()
1193 	{
1194 		if ( strct )
1195 			return strct.aliases;
1196 
1197 		return null;
1198 	}
1199 
1200 	/**
1201 	 * Get an string representation of the type.
1202 	 */
1203 	private string getType(GtkType type, GtkParamDirection direction = GtkParamDirection.Default)
1204 	{
1205 		if ( isStringType(type) )
1206 		{
1207 			if ( direction != GtkParamDirection.Default && !type.cType.endsWith("**") )
1208 				return "char[]";
1209 			else if ( direction == GtkParamDirection.Default && type.cType.endsWith("***") )
1210 				return "string[][]";
1211 			else if ( type.isArray && isStringArray(type.elementType, direction) )
1212 				return getType(type.elementType, direction) ~"[]";
1213 			else if ( isStringArray(type, direction) )
1214 				return "string[]";
1215 
1216 			return "string";
1217 		}
1218 		else if ( type.isArray() )
1219 		{
1220 			string size;
1221 
1222 			//Special case for GBytes and GVariant.
1223 			if ( type.cType == "gconstpointer" && type.elementType.cType == "gconstpointer" )
1224 				return "void[]";
1225 
1226 			if ( type.cType == "guchar*" )
1227 				return "char[]";
1228 
1229 			if ( type.size > -1 )
1230 				size = to!string(type.size);
1231 
1232 			string elmType = getType(type.elementType, direction);
1233 
1234 			if ( elmType == type.cType )
1235 				elmType = elmType[0..$-1];
1236 
1237 			return elmType ~"["~ size ~"]";
1238 		}
1239 		else if ( !type.elementType && type.zeroTerminated )
1240 		{
1241 			return getType(type, GtkParamDirection.Out) ~"[]";
1242 		}
1243 		else
1244 		{
1245 			if ( type is null || type.name == "none" )
1246 				return "void";
1247 			else if ( type.name in strct.structWrap )
1248 				return strct.structWrap[type.name];
1249 			else if ( type.name == type.cType )
1250 				return stringToGtkD(type.name, wrapper.aliasses, localAliases());
1251 
1252 			GtkStruct dType = strct.pack.getStruct(type.name);
1253 
1254 			if ( isDType(dType) )
1255 			{
1256 			    if ( dType.type == GtkStructType.Interface )
1257 					return dType.name ~"IF";
1258 			    else
1259 			    	return dType.name;
1260 			}
1261 			else if ( type.cType.empty && dType && dType.type == GtkStructType.Record )
1262 				return dType.cType ~ "*";
1263 		}
1264 
1265 		if ( type.cType.empty )
1266 		{
1267 			if ( auto enum_ = strct.pack.getEnum(type.name) )
1268 				return enum_.cName;
1269 
1270 			return stringToGtkD(type.name, wrapper.aliasses, localAliases());
1271 		}
1272 
1273 		if ( direction != GtkParamDirection.Default )
1274 			return stringToGtkD(type.cType[0..$-1], wrapper.aliasses, localAliases());
1275 
1276 		return stringToGtkD(type.cType, wrapper.aliasses, localAliases());
1277 	}
1278 
1279 	private bool isDType(GtkStruct dType)
1280 	{
1281 		if ( dType is null )
1282 			return false;
1283 		if ( dType.type.among(GtkStructType.Class, GtkStructType.Interface) )
1284 			return true;
1285 		if ( dType.type == GtkStructType.Record && (dType.lookupClass || dType.lookupInterface) )
1286 			return true;
1287 
1288 		return false;
1289 	}
1290 
1291 	private bool isStringType(GtkType type)
1292 	{
1293 		if ( type.cType.startsWith("gchar*", "char*", "const(char)*") )
1294 			return true;
1295 		if ( type.name.among("utf8", "filename") )
1296 			return true;
1297 		if ( type.isArray() && type.elementType.cType.startsWith("gchar", "char", "const(char)") )
1298 			return true;
1299 
1300 		return false;
1301 	}
1302 
1303 	private bool isStringArray(GtkType type, GtkParamDirection direction = GtkParamDirection.Default)
1304 	{
1305 		if ( direction == GtkParamDirection.Default && type.cType.endsWith("**") )
1306 			return true;
1307 		if ( type.elementType is null )
1308 			return false;
1309 		if ( !type.elementType.cType.endsWith("*") )
1310 			return false;
1311 		if ( direction != GtkParamDirection.Default && type.cType.among("char**", "gchar**", "guchar**") )
1312 			return false;
1313 
1314 		return true;
1315 	}
1316 
1317 	private bool isInstanceParam(GtkParam param)
1318 	{
1319 		if ( param !is params[0] )
1320 			return false;
1321 		if ( strct is null || strct.type != GtkStructType.Record )
1322 			return false;
1323 		if ( !(strct.lookupClass || strct.lookupInterface) )
1324 			return false;
1325 		if ( param.direction != GtkParamDirection.Default )
1326 			return false;
1327 		if ( param.lengthFor !is null )
1328 			return false;
1329 		if ( strct.cType is null )
1330 			return false;
1331 		if ( param.type.cType == strct.cType ~"*" )
1332 			return true;
1333 
1334 		return false;
1335 	}
1336 
1337 	private string lenId(GtkType type, string paramName = "p")
1338 	{
1339 		if ( type.length > -1 )
1340 			return tokenToGtkD(params[type.length].name, wrapper.aliasses, localAliases());
1341 		//The c function returns the length.
1342 		else if ( type.length == -2 )
1343 			return "p";
1344 		else if ( type.size > -1 )
1345 			return to!string(type.size);
1346 
1347 		if ( isStringType(type) )
1348 			return null;
1349 
1350 		return "getArrayLength("~ paramName ~")";
1351 	}
1352 
1353 	/**
1354 	 * Is this function a static function.
1355 	 */
1356 	private bool isStatic()
1357 	{
1358 		if ( strct.noNamespace )
1359 			return false;
1360 
1361 		if ( type == GtkFunctionType.Function && !(!params.empty && isInstanceParam(params[0])) )
1362 			return true;
1363 
1364 		if ( type == GtkFunctionType.Method && strct.isNamespace() )
1365 			return true;
1366 
1367 		return false;
1368 	}
1369 
1370 	/**
1371 	 * Check if any of the ancestors contain the function functionName.
1372 	 */
1373 	private bool checkOverride()
1374 	{
1375 		if ( name == "get_type" )
1376 			return false;
1377 		if ( name == "to_string" && params.empty )
1378 			return true;
1379 
1380 		GtkStruct ancestor = strct.getParent();
1381 
1382 		while(ancestor)
1383 		{
1384 			if ( name in ancestor.functions && name !in strct.aliases )
1385 			{
1386 				GtkFunction func = ancestor.functions[name];
1387 
1388 				if ( !(func.noCode || func.isVariadic() || func.type == GtkFunctionType.Callback) && paramsEqual(func) )
1389 					return true;
1390 			}
1391 
1392 			ancestor = ancestor.getParent();
1393 		}
1394 
1395 		return false;
1396 	}
1397 
1398 	/**
1399 	 * Return true if the params of func match the params of this function.
1400 	 */
1401 	private bool paramsEqual(GtkFunction func)
1402 	{
1403 		if ( params.length != func.params.length )
1404 			return false;
1405 
1406 		foreach ( i, param; params )
1407 		{
1408 			if ( getType(param.type) != getType(func.params[i].type) )
1409 				return false;
1410 		}
1411 
1412 		return true;
1413 	}
1414 
1415 	private string construct(string type)
1416 	{
1417 		GtkStruct dType = strct.pack.getStruct(type);
1418 		debug assert(dType, "Only call construct for valid GtkD types");
1419 		string name = dType.name;
1420 
1421 		if ( type in strct.structWrap )
1422 			name = strct.structWrap[type];
1423 
1424 		if ( dType.pack.name.among("cairo", "glib", "gthread") )
1425 			return "new "~name;
1426 		else if( dType.type == GtkStructType.Interface )
1427 			return "ObjectG.getDObject!("~ name ~", "~ name ~"IF)";
1428 		else
1429 			return "ObjectG.getDObject!("~ name ~")";
1430 	}
1431 
1432 	private string getCallbackParams()
1433 	{
1434 		string buff;
1435 
1436 		buff = strct.cType ~"* "~ strct.name.toLower() ~"Struct";
1437 		foreach( param; params )
1438 		{
1439 			if ( auto par = strct.pack.getStruct(param.type.name) )
1440 				buff ~= stringToGtkD(", "~ par.cType ~"* "~ param.name, wrapper.aliasses, localAliases());
1441 			else if ( auto enum_ = strct.pack.getEnum(param.type.name) )
1442 				buff ~= stringToGtkD(", "~ enum_.cName ~" "~ param.name, wrapper.aliasses, localAliases());
1443 			else if ( !param.type.cType.empty )
1444 				buff ~= stringToGtkD(", "~ param.type.cType ~" "~ param.name, wrapper.aliasses, localAliases());
1445 			else
1446 				buff ~= stringToGtkD(", "~ param.type.name ~" "~ param.name, wrapper.aliasses, localAliases());
1447 		}
1448 
1449 		if ( strct.type == GtkStructType.Interface )
1450 			buff ~= ", "~ strct.name ~"IF _"~ strct.name.toLower();
1451 		else
1452 			buff ~= ", "~ strct.name ~" _"~ strct.name.toLower();
1453 
1454 		return buff;
1455 	}
1456 
1457 	private string getCallbackVars()
1458 	{
1459 		string buff;
1460 
1461 		foreach( i, param; params )
1462 		{
1463 			if ( i > 0 )
1464 				buff ~= ", ";
1465 
1466 			GtkStruct par = strct.pack.getStruct(param.type.name);
1467 
1468 			if ( isDType(par) )
1469 			{
1470 				buff ~= construct(param.type.name) ~"("~ tokenToGtkD(param.name, wrapper.aliasses, localAliases()) ~")";
1471 			}
1472 			else if ( isStringType(param.type) )
1473 			{
1474 				if ( isStringArray(param.type) )
1475 					buff ~= "Str.toStringArray("~ tokenToGtkD(param.name, wrapper.aliasses, localAliases()) ~")";
1476 				else
1477 					buff ~= "Str.toString("~ tokenToGtkD(param.name, wrapper.aliasses, localAliases()) ~")";
1478 			}
1479 			else
1480 			{
1481 				buff ~= tokenToGtkD(param.name, wrapper.aliasses, localAliases());
1482 			}
1483 		}
1484 
1485 		if ( !buff.empty )
1486 			buff ~= ", ";
1487 		buff ~= "_"~ strct.name.toLower();
1488 
1489 		return buff;
1490 	}
1491 }
1492 
1493 enum GtkParamDirection : string
1494 {
1495 	Default = "",
1496 	Out = "out",
1497 	InOut = "inout",
1498 }
1499 
1500 final class GtkParam
1501 {
1502 	string doc;
1503 	string name;
1504 	GtkType type;
1505 	GtkTransferOwnership ownerschip = GtkTransferOwnership.None;
1506 	GtkParamDirection direction = GtkParamDirection.Default;
1507 
1508 	GtkParam lengthFor;
1509 	GtkWrapper wrapper;
1510 
1511 	this(GtkWrapper wrapper)
1512 	{
1513 		this.wrapper = wrapper;
1514 	}
1515 
1516 	void parse(T)(XMLReader!T reader)
1517 	{
1518 		name = reader.front.attributes["name"];
1519 
1520 		if ( "transfer-ownership" in reader.front.attributes )
1521 			ownerschip = cast(GtkTransferOwnership)reader.front.attributes["transfer-ownership"];
1522 		if ( "direction" in reader.front.attributes )
1523 			direction = cast(GtkParamDirection)reader.front.attributes["direction"];
1524 
1525 		reader.popFront();
1526 
1527 		while( !reader.empty && !reader.endTag("parameter", "instance-parameter") )
1528 		{
1529 			if ( reader.front.type == XMLNodeType.EndTag )
1530 			{
1531 				reader.popFront();
1532 				continue;
1533 			}
1534 
1535 			switch(reader.front.value)
1536 			{
1537 				case "doc":
1538 					reader.popFront();
1539 					doc ~= reader.front.value;
1540 					reader.popFront();
1541 					break;
1542 				case "doc-deprecated":
1543 					reader.popFront();
1544 					doc ~= "\n\nDeprecated: "~ reader.front.value;
1545 					reader.popFront();
1546 					break;
1547 				case "array":
1548 				case "type":
1549 					type = new GtkType(wrapper);
1550 					type.parse(reader);
1551 					break;
1552 				case "varargs":
1553 					type = new GtkType(wrapper);
1554 					type.name = "...";
1555 					type.cType = "...";
1556 					break;
1557 				default:
1558 					throw new XMLException(reader, "Unexpected tag: "~ reader.front.value ~" in GtkParam: "~ name);
1559 			}
1560 
1561 			reader.popFront();
1562 		}
1563 	}
1564 }