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