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 ~");"; 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 ) 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 p = "~ 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 string len = lenId(returnType); 817 if ( !len.empty ) 818 len = ", "~ len; 819 820 if ( isStringArray(returnType) ) 821 buff ~= "return Str.toStringArray(p"~ len ~");"; 822 else 823 buff ~= "return Str.toString(p"~ len ~");"; 824 825 return buff; 826 } 827 else if ( isDType(returnDType) ) 828 { 829 buff ~= "auto p = "~ gtkCall ~";"; 830 831 if ( throws ) 832 { 833 buff ~= throwGException; 834 } 835 836 if ( !outToD.empty ) 837 { 838 buff ~= ""; 839 buff ~= outToD; 840 } 841 842 buff ~= ""; 843 buff ~= "if(p is null)"; 844 buff ~= "{"; 845 buff ~= "return null;"; 846 buff ~= "}"; 847 buff ~= ""; 848 849 if ( returnType.isArray() ) 850 { 851 buff ~= returnDType.name ~"[] arr = new "~ returnDType.name ~"["~ lenId(returnType) ~"];"; 852 buff ~= "for(int i = 0; i < "~ lenId(returnType) ~"; i++)"; 853 buff ~= "{"; 854 if ( returnType.elementType.cType.endsWith("*") ) 855 buff ~= "\tarr[i] = "~ construct(returnType.elementType.name) ~"(cast("~ returnType.elementType.cType ~") p[i]);"; 856 else 857 buff ~= "\tarr[i] = "~ construct(returnType.elementType.name) ~"(cast("~ returnType.elementType.cType ~"*) &p[i]);"; 858 buff ~= "}"; 859 buff ~= ""; 860 buff ~= "return arr;"; 861 } 862 else 863 { 864 if ( returnOwnership == GtkTransferOwnership.Full && returnDType.getAncestor().name == "ObjectG" ) 865 buff ~= "return "~ construct(returnType.name) ~"(cast("~ returnDType.cType ~"*) p, true);"; 866 else 867 buff ~= "return "~ construct(returnType.name) ~"(cast("~ returnDType.cType ~"*) p);"; 868 } 869 870 return buff; 871 } 872 else 873 { 874 if ( returnType.name == "gboolean" ) 875 gtkCall ~= " != 0"; 876 877 if ( !returnType.isArray && outToD.empty && !throws ) 878 { 879 buff ~= "return "~ gtkCall ~";"; 880 return buff; 881 } 882 883 buff ~= "auto p = "~ gtkCall ~";"; 884 885 if ( throws ) 886 { 887 buff ~= throwGException; 888 } 889 890 if ( !outToD.empty ) 891 { 892 buff ~= ""; 893 buff ~= outToD; 894 } 895 896 buff ~= ""; 897 if ( returnType.isArray() ) 898 { 899 if ( returnType.elementType.name == "gboolean" ) 900 { 901 buff ~= "bool[] r = new bool["~ lenId(returnType) ~"];"; 902 buff ~= "for(size_t i = 0; i < "~ lenId(returnType) ~"; i++)"; 903 buff ~= "{"; 904 buff ~= "r[i] = p[i] != 0;"; 905 buff ~= "}"; 906 buff ~= "return r;"; 907 } 908 else 909 { 910 buff ~= "return p[0 .. "~ lenId(returnType) ~"];"; 911 } 912 } 913 else 914 buff ~= "return p;"; 915 916 return buff; 917 } 918 919 assert(false, "Unexpected function: "~ name); 920 } 921 922 string getSignalName() 923 { 924 assert(type == GtkFunctionType.Signal); 925 926 char pc; 927 string signalName; 928 929 foreach ( size_t count, char c; name ) 930 { 931 if ( count == 0 ) 932 { 933 signalName ~= std.ascii.toUpper(c); 934 } 935 else 936 { 937 if ( c!='-' && c!='_' ) 938 { 939 if ( pc=='-' || pc=='_' ) 940 signalName ~= toUpper(c); 941 else 942 signalName ~= c; 943 } 944 } 945 pc = c; 946 } 947 948 if ( !signalName.among("MapEvent", "UnmapEvent", "DestroyEvent") && 949 endsWith(signalName, "Event") ) 950 { 951 signalName = signalName[0..signalName.length-5]; 952 } 953 954 return signalName; 955 } 956 957 string getDelegateDecleration() 958 { 959 assert(type == GtkFunctionType.Signal); 960 961 string buff = getType(returnType) ~ " delegate("; 962 963 foreach ( param; params ) 964 { 965 //TODO: Signals with arrays. 966 if ( param.type.cType == "gpointer" && param.type.isArray() ) 967 buff ~= "void*, "; 968 else 969 buff ~= getType(param.type) ~ ", "; 970 } 971 972 if ( strct.type == GtkStructType.Interface ) 973 buff ~= strct.name ~"IF)"; 974 else 975 buff ~= strct.name ~")"; 976 977 return buff; 978 } 979 980 string[] getAddListenerdeclaration() 981 { 982 string[] buff; 983 984 writeDocs(buff); 985 buff ~= "void addOn"~ getSignalName() ~"("~ getDelegateDecleration() ~" dlg, ConnectFlags connectFlags=cast(ConnectFlags)0)"; 986 987 return buff; 988 } 989 990 string[] getAddListenerBody() 991 { 992 string[] buff; 993 string realName = name; 994 995 if ( name.endsWith("-generic-event") ) 996 realName = name[0..$-14]; 997 998 buff ~= "{"; 999 buff ~= "if ( \""~ name ~"\" !in connectedSignals )"; 1000 buff ~= "{"; 1001 1002 if ( strct.name != "StatusIcon") 1003 { 1004 switch ( realName ) 1005 { 1006 case "button-press-event": buff ~= "addEvents(EventMask.BUTTON_PRESS_MASK);"; break; 1007 case "button-release-event": buff ~= "addEvents(EventMask.BUTTON_RELEASE_MASK);"; break; 1008 case "enter-notify-event": buff ~= "addEvents(EventMask.ENTER_NOTIFY_MASK);"; break; 1009 case "focus-in-event": buff ~= "addEvents(EventMask.FOCUS_CHANGE_MASK);"; break; 1010 case "focus-out-event": buff ~= "addEvents(EventMask.FOCUS_CHANGE_MASK);"; break; 1011 case "key-press-event": buff ~= "addEvents(EventMask.KEY_PRESS_MASK);"; break; 1012 case "key-release-event": buff ~= "addEvents(EventMask.KEY_RELEASE_MASK);"; break; 1013 case "leave-notify-event": buff ~= "addEvents(EventMask.LEAVE_NOTIFY_MASK);"; break; 1014 case "motion-notify-event": buff ~= "addEvents(EventMask.POINTER_MOTION_MASK);"; break; 1015 case "property-notify-event": buff ~= "addEvents(EventMask.PROPERTY_CHANGE_MASK);"; break; 1016 case "proximity-in-event": buff ~= "addEvents(EventMask.PROXIMITY_IN_MASK);"; break; 1017 case "proximity-out-event": buff ~= "addEvents(EventMask.PROXIMITY_OUT_MASK);"; break; 1018 case "scroll-event": buff ~= "addEvents(EventMask.SCROLL_MASK);"; break; 1019 case "visibility-notify-event": buff ~= "addEvents(EventMask.VISIBILITY_NOTIFY_MASK);"; break; 1020 1021 default: break; 1022 } 1023 } 1024 1025 buff ~= "Signals.connectData("; 1026 buff ~= "this,"; 1027 buff ~= "\""~ realName ~"\","; 1028 buff ~= "cast(GCallback)&callBack"~ getSignalName() ~","; 1029 1030 if ( strct.type == GtkStructType.Interface ) 1031 buff ~= "cast(void*)cast("~ strct.name ~"IF)this,"; 1032 else 1033 buff ~= "cast(void*)this,"; 1034 1035 buff ~= "null,"; 1036 buff ~= "connectFlags);"; 1037 buff ~= "connectedSignals[\""~ name ~"\"] = 1;"; 1038 buff ~= "}"; 1039 1040 if ( strct.type == GtkStructType.Interface ) 1041 buff ~= "_on"~ getSignalName() ~"Listeners ~= dlg;"; 1042 else 1043 buff ~= "on"~ getSignalName() ~"Listeners ~= dlg;"; 1044 1045 buff ~= "}"; 1046 1047 return buff; 1048 } 1049 1050 string[] getSignalCallback() 1051 { 1052 string[] buff; 1053 string type = getType(returnType); 1054 GtkStruct dType = strct.pack.getStruct(returnType.name); 1055 1056 if ( dType ) 1057 type = dType.cType ~"*"; 1058 1059 buff ~= "extern(C) static "~ (type == "bool" ? "int" : type) 1060 ~" callBack"~ getSignalName() ~"("~ getCallbackParams() ~")"; 1061 1062 buff ~= "{"; 1063 1064 if ( type == "bool" ) 1065 { 1066 buff ~= "foreach ( "~ getDelegateDecleration() ~" dlg; _"~ strct.name.toLower() ~".on"~ getSignalName() ~"Listeners )"; 1067 buff ~= "{"; 1068 buff ~= "if ( dlg("~ getCallbackVars() ~") )"; 1069 buff ~= "{"; 1070 buff ~= "return 1;"; 1071 buff ~= "}"; 1072 buff ~= "}"; 1073 buff ~= ""; 1074 buff ~= "return 0;"; 1075 } 1076 else if ( type == "void" ) 1077 { 1078 buff ~= "foreach ( "~ getDelegateDecleration() ~" dlg; _"~ strct.name.toLower() ~".on"~ getSignalName() ~"Listeners )"; 1079 buff ~= "{"; 1080 buff ~= "dlg("~ getCallbackVars() ~");"; 1081 buff ~= "}"; 1082 } 1083 else if ( dType ) 1084 { 1085 buff ~= "foreach ( "~ getDelegateDecleration() ~" dlg; _"~ strct.name.toLower() ~".on"~ getSignalName() ~"Listeners )"; 1086 buff ~= "{"; 1087 buff ~= "if ( auto r = dlg("~ getCallbackVars() ~") )"; 1088 buff ~= "return r."~ dType.getHandleFunc() ~"();"; 1089 buff ~= "}"; 1090 buff ~= ""; 1091 buff ~= "return null;"; 1092 } 1093 else 1094 { 1095 buff ~= "return _"~ strct.name.toLower() ~".on"~ getSignalName() ~"Listeners[0]("~ getCallbackVars() ~");"; 1096 } 1097 1098 buff ~= "}"; 1099 1100 return buff; 1101 } 1102 1103 void writeDocs(ref string[] buff) 1104 { 1105 if ( (doc || returnType.doc) && wrapper.includeComments ) 1106 { 1107 buff ~= "/**"; 1108 foreach ( line; doc.splitLines() ) 1109 buff ~= " * "~ line.strip(); 1110 1111 if ( !params.empty ) 1112 { 1113 buff ~= " *"; 1114 buff ~= " * Params:"; 1115 1116 foreach ( param; params ) 1117 { 1118 if ( param.doc.empty ) 1119 continue; 1120 1121 if ( returnType.length > -1 && param == params[returnType.length] ) 1122 continue; 1123 1124 if ( isInstanceParam(param) ) 1125 continue; 1126 1127 string[] lines = param.doc.splitLines(); 1128 buff ~= " * "~ tokenToGtkD(param.name, wrapper.aliasses, localAliases()) ~" = "~ lines[0]; 1129 foreach( line; lines[1..$] ) 1130 buff ~= " * "~ line.strip(); 1131 } 1132 1133 if ( buff.endsWith(" * Params:") ) 1134 buff = buff[0 .. $-2]; 1135 } 1136 1137 if ( returnType.doc ) 1138 { 1139 string[] lines = returnType.doc.splitLines(); 1140 if ( doc ) 1141 buff ~= " *"; 1142 buff ~= " * Return: "~ lines[0]; 1143 1144 foreach( line; lines[1..$] ) 1145 buff ~= " * "~ line.strip(); 1146 } 1147 1148 if ( libVersion ) 1149 { 1150 buff ~= " *"; 1151 buff ~= " * Since: "~ libVersion; 1152 } 1153 1154 if ( throws || type == GtkFunctionType.Constructor ) 1155 buff ~= " *"; 1156 1157 if ( throws ) 1158 buff ~= " * Throws: GException on failure."; 1159 1160 if ( type == GtkFunctionType.Constructor ) 1161 buff ~= " * Throws: ConstructionException GTK+ fails to create the object."; 1162 1163 buff ~= " */"; 1164 } 1165 else if ( wrapper.includeComments ) 1166 { 1167 buff ~= "/** */\n"; 1168 } 1169 } 1170 1171 private void resolveLength() 1172 { 1173 foreach( param; params ) 1174 { 1175 if ( param.type.length > -1 ) 1176 params[param.type.length].lengthFor = param; 1177 } 1178 } 1179 1180 private string[string] localAliases() 1181 { 1182 if ( strct ) 1183 return strct.aliases; 1184 1185 return null; 1186 } 1187 1188 /** 1189 * Get an string representation of the type. 1190 */ 1191 private string getType(GtkType type, GtkParamDirection direction = GtkParamDirection.Default) 1192 { 1193 if ( isStringType(type) ) 1194 { 1195 if ( direction != GtkParamDirection.Default && !type.cType.endsWith("**") ) 1196 return "char[]"; 1197 else if ( direction == GtkParamDirection.Default && type.cType.endsWith("***") ) 1198 return "string[][]"; 1199 else if ( type.isArray && isStringArray(type.elementType, direction) ) 1200 return getType(type.elementType, direction) ~"[]"; 1201 else if ( isStringArray(type, direction) ) 1202 return "string[]"; 1203 1204 return "string"; 1205 } 1206 else if ( type.isArray() ) 1207 { 1208 string size; 1209 1210 //Special case for GBytes and GVariant. 1211 if ( type.cType == "gconstpointer" && type.elementType.cType == "gconstpointer" ) 1212 return "void[]"; 1213 1214 if ( type.cType == "guchar*" ) 1215 return "char[]"; 1216 1217 if ( type.size > -1 ) 1218 size = to!string(type.size); 1219 1220 string elmType = getType(type.elementType, direction); 1221 1222 if ( elmType == type.cType ) 1223 elmType = elmType[0..$-1]; 1224 1225 return elmType ~"["~ size ~"]"; 1226 } 1227 else if ( !type.elementType && type.zeroTerminated ) 1228 { 1229 return getType(type, GtkParamDirection.Out) ~"[]"; 1230 } 1231 else 1232 { 1233 if ( type is null || type.name == "none" ) 1234 return "void"; 1235 else if ( type.name in strct.structWrap ) 1236 return strct.structWrap[type.name]; 1237 else if ( type.name == type.cType ) 1238 return stringToGtkD(type.name, wrapper.aliasses, localAliases()); 1239 1240 GtkStruct dType = strct.pack.getStruct(type.name); 1241 1242 if ( isDType(dType) ) 1243 { 1244 if ( dType.type == GtkStructType.Interface ) 1245 return dType.name ~"IF"; 1246 else 1247 return dType.name; 1248 } 1249 else if ( type.cType.empty && dType && dType.type == GtkStructType.Record ) 1250 return dType.cType ~ "*"; 1251 } 1252 1253 if ( type.cType.empty ) 1254 { 1255 if ( auto enum_ = strct.pack.getEnum(type.name) ) 1256 return enum_.cName; 1257 1258 return stringToGtkD(type.name, wrapper.aliasses, localAliases()); 1259 } 1260 1261 if ( direction != GtkParamDirection.Default ) 1262 return stringToGtkD(type.cType[0..$-1], wrapper.aliasses, localAliases()); 1263 1264 return stringToGtkD(type.cType, wrapper.aliasses, localAliases()); 1265 } 1266 1267 private bool isDType(GtkStruct dType) 1268 { 1269 if ( dType is null ) 1270 return false; 1271 if ( dType.type.among(GtkStructType.Class, GtkStructType.Interface) ) 1272 return true; 1273 if ( dType.type == GtkStructType.Record && (dType.lookupClass || dType.lookupInterface) ) 1274 return true; 1275 1276 return false; 1277 } 1278 1279 private bool isStringType(GtkType type) 1280 { 1281 if ( type.cType.startsWith("gchar*", "char*", "const(char)*") ) 1282 return true; 1283 if ( type.name.among("utf8", "filename") ) 1284 return true; 1285 if ( type.isArray() && type.elementType.cType.startsWith("gchar", "char", "const(char)") ) 1286 return true; 1287 1288 return false; 1289 } 1290 1291 private bool isStringArray(GtkType type, GtkParamDirection direction = GtkParamDirection.Default) 1292 { 1293 if ( direction == GtkParamDirection.Default && type.cType.endsWith("**") ) 1294 return true; 1295 if ( type.elementType is null ) 1296 return false; 1297 if ( !type.elementType.cType.endsWith("*") ) 1298 return false; 1299 if ( direction != GtkParamDirection.Default && type.cType.among("char**", "gchar**", "guchar**") ) 1300 return false; 1301 1302 return true; 1303 } 1304 1305 private bool isInstanceParam(GtkParam param) 1306 { 1307 if ( param !is params[0] ) 1308 return false; 1309 if ( strct is null || strct.type != GtkStructType.Record ) 1310 return false; 1311 if ( !(strct.lookupClass || strct.lookupInterface) ) 1312 return false; 1313 if ( param.direction != GtkParamDirection.Default ) 1314 return false; 1315 if ( param.lengthFor !is null ) 1316 return false; 1317 if ( strct.cType is null ) 1318 return false; 1319 if ( param.type.cType == strct.cType ~"*" ) 1320 return true; 1321 1322 return false; 1323 } 1324 1325 private string lenId(GtkType type, string paramName = "p") 1326 { 1327 if ( type.length > -1 ) 1328 return tokenToGtkD(params[type.length].name, wrapper.aliasses, localAliases()); 1329 //The c function returns the length. 1330 else if ( type.length == -2 ) 1331 return "p"; 1332 else if ( type.size > -1 ) 1333 return to!string(type.size); 1334 1335 if ( isStringType(type) ) 1336 return null; 1337 1338 return "getArrayLength("~ paramName ~")"; 1339 } 1340 1341 /** 1342 * Is this function a static function. 1343 */ 1344 private bool isStatic() 1345 { 1346 if ( strct.noNamespace ) 1347 return false; 1348 1349 if ( type == GtkFunctionType.Function && !(!params.empty && isInstanceParam(params[0])) ) 1350 return true; 1351 1352 if ( type == GtkFunctionType.Method && strct.isNamespace() ) 1353 return true; 1354 1355 return false; 1356 } 1357 1358 /** 1359 * Check if any of the ancestors contain the function functionName. 1360 */ 1361 private bool checkOverride() 1362 { 1363 if ( name == "get_type" ) 1364 return false; 1365 if ( name == "to_string" ) 1366 return true; 1367 1368 GtkStruct ancestor = strct.parentStruct; 1369 1370 while(ancestor) 1371 { 1372 if ( name in ancestor.functions && name !in strct.aliases ) 1373 { 1374 GtkFunction func = ancestor.functions[name]; 1375 1376 if ( !(func.noCode || func.isVariadic() || func.type == GtkFunctionType.Callback) && paramsEqual(func) ) 1377 return true; 1378 } 1379 1380 ancestor = ancestor.parentStruct; 1381 } 1382 1383 return false; 1384 } 1385 1386 /** 1387 * Return true if the params of func match the params of this function. 1388 */ 1389 private bool paramsEqual(GtkFunction func) 1390 { 1391 if ( params.length != func.params.length ) 1392 return false; 1393 1394 foreach ( i, param; params ) 1395 { 1396 if ( getType(param.type) != getType(func.params[i].type) ) 1397 return false; 1398 } 1399 1400 return true; 1401 } 1402 1403 private string construct(string type) 1404 { 1405 GtkStruct dType = strct.pack.getStruct(type); 1406 debug assert(dType, "Only call construct for valid GtkD types"); 1407 string name = dType.name; 1408 1409 if ( type in strct.structWrap ) 1410 name = strct.structWrap[type]; 1411 1412 if ( dType.pack.name.among("cairo", "glib", "gthread") ) 1413 return "new "~name; 1414 else if( dType.type == GtkStructType.Interface ) 1415 return "ObjectG.getDObject!("~ name ~", "~ name ~"IF)"; 1416 else 1417 return "ObjectG.getDObject!("~ name ~")"; 1418 } 1419 1420 private string getCallbackParams() 1421 { 1422 string buff; 1423 1424 buff = strct.cType ~"* "~ strct.name.toLower() ~"Struct"; 1425 foreach( param; params ) 1426 { 1427 if ( auto par = strct.pack.getStruct(param.type.name) ) 1428 buff ~= stringToGtkD(", "~ par.cType ~"* "~ param.name, wrapper.aliasses, localAliases()); 1429 else if ( auto enum_ = strct.pack.getEnum(param.type.name) ) 1430 buff ~= stringToGtkD(", "~ enum_.cName ~" "~ param.name, wrapper.aliasses, localAliases()); 1431 else if ( !param.type.cType.empty ) 1432 buff ~= stringToGtkD(", "~ param.type.cType ~" "~ param.name, wrapper.aliasses, localAliases()); 1433 else 1434 buff ~= stringToGtkD(", "~ param.type.name ~" "~ param.name, wrapper.aliasses, localAliases()); 1435 } 1436 1437 if ( strct.type == GtkStructType.Interface ) 1438 buff ~= ", "~ strct.name ~"IF _"~ strct.name.toLower(); 1439 else 1440 buff ~= ", "~ strct.name ~" _"~ strct.name.toLower(); 1441 1442 return buff; 1443 } 1444 1445 private string getCallbackVars() 1446 { 1447 string buff; 1448 1449 foreach( i, param; params ) 1450 { 1451 if ( i > 0 ) 1452 buff ~= ", "; 1453 1454 GtkStruct par = strct.pack.getStruct(param.type.name); 1455 1456 if ( isDType(par) ) 1457 { 1458 buff ~= construct(param.type.name) ~"("~ tokenToGtkD(param.name, wrapper.aliasses, localAliases()) ~")"; 1459 } 1460 else if ( isStringType(param.type) ) 1461 { 1462 if ( isStringArray(param.type) ) 1463 buff ~= "Str.toStringArray("~ tokenToGtkD(param.name, wrapper.aliasses, localAliases()) ~")"; 1464 else 1465 buff ~= "Str.toString("~ tokenToGtkD(param.name, wrapper.aliasses, localAliases()) ~")"; 1466 } 1467 else 1468 { 1469 buff ~= tokenToGtkD(param.name, wrapper.aliasses, localAliases()); 1470 } 1471 } 1472 1473 if ( !buff.empty ) 1474 buff ~= ", "; 1475 buff ~= "_"~ strct.name.toLower(); 1476 1477 return buff; 1478 } 1479 } 1480 1481 enum GtkParamDirection : string 1482 { 1483 Default = "", 1484 Out = "out", 1485 InOut = "inout", 1486 } 1487 1488 final class GtkParam 1489 { 1490 string doc; 1491 string name; 1492 GtkType type; 1493 GtkTransferOwnership ownerschip = GtkTransferOwnership.None; 1494 GtkParamDirection direction = GtkParamDirection.Default; 1495 1496 GtkParam lengthFor; 1497 GtkWrapper wrapper; 1498 1499 this(GtkWrapper wrapper) 1500 { 1501 this.wrapper = wrapper; 1502 } 1503 1504 void parse(T)(XMLReader!T reader) 1505 { 1506 name = reader.front.attributes["name"]; 1507 1508 if ( "transfer-ownership" in reader.front.attributes ) 1509 ownerschip = cast(GtkTransferOwnership)reader.front.attributes["transfer-ownership"]; 1510 if ( "direction" in reader.front.attributes ) 1511 direction = cast(GtkParamDirection)reader.front.attributes["direction"]; 1512 1513 reader.popFront(); 1514 1515 while( !reader.empty && !reader.endTag("parameter", "instance-parameter") ) 1516 { 1517 if ( reader.front.type == XMLNodeType.EndTag ) 1518 { 1519 reader.popFront(); 1520 continue; 1521 } 1522 1523 switch(reader.front.value) 1524 { 1525 case "doc": 1526 reader.popFront(); 1527 doc ~= reader.front.value; 1528 reader.popFront(); 1529 break; 1530 case "doc-deprecated": 1531 reader.popFront(); 1532 doc ~= "\n\nDeprecated: "~ reader.front.value; 1533 reader.popFront(); 1534 break; 1535 case "array": 1536 case "type": 1537 type = new GtkType(wrapper); 1538 type.parse(reader); 1539 break; 1540 case "varargs": 1541 type = new GtkType(wrapper); 1542 type.name = "..."; 1543 type.cType = "..."; 1544 break; 1545 default: 1546 throw new XMLException(reader, "Unexpected tag: "~ reader.front.value ~" in GtkParam: "~ name); 1547 } 1548 1549 reader.popFront(); 1550 } 1551 } 1552 }