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