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 }