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 }