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 getDelegateWrapperName() 971 { 972 return "On" ~ getSignalName() ~ "DelegateWrapper"; 973 } 974 975 string getDelegateWrapperArrayName() { 976 return "on" ~ getSignalName() ~ "Listeners"; 977 } 978 979 string[] getDelegateWrapperDeclaration() 980 { 981 assert(type == GtkFunctionType.Signal); 982 983 string[] buff; 984 buff ~= "protected class " ~ getDelegateWrapperName(); 985 buff ~= "{"; 986 buff ~= getDelegateDecleration() ~ " dlg;"; 987 buff ~= "gulong handlerId;"; 988 buff ~= "ConnectFlags flags;"; 989 buff ~= "this(" ~ getDelegateDecleration() ~ " dlg, gulong handlerId, ConnectFlags flags)"; 990 buff ~= " {"; 991 buff ~= "this.dlg = dlg;"; 992 buff ~= "this.handlerId = handlerId;"; 993 buff ~= "this.flags = flags;"; 994 buff ~= "}"; 995 buff ~= "}"; 996 return buff; 997 } 998 999 string getDelegateDecleration() 1000 { 1001 assert(type == GtkFunctionType.Signal); 1002 1003 string buff = getType(returnType) ~ " delegate("; 1004 1005 foreach ( param; params ) 1006 { 1007 //TODO: Signals with arrays. 1008 if ( param.type.cType == "gpointer" && param.type.isArray() ) 1009 buff ~= "void*, "; 1010 else 1011 buff ~= getType(param.type) ~ ", "; 1012 } 1013 1014 if ( strct.type == GtkStructType.Interface ) 1015 buff ~= strct.name ~"IF)"; 1016 else 1017 buff ~= strct.name ~")"; 1018 1019 return buff; 1020 } 1021 1022 string[] getAddListenerDeclaration() 1023 { 1024 string[] buff; 1025 1026 writeDocs(buff); 1027 buff ~= "gulong addOn"~ getSignalName() ~"("~ getDelegateDecleration() ~" dlg, ConnectFlags connectFlags=cast(ConnectFlags)0)"; 1028 1029 return buff; 1030 } 1031 1032 string[] getAddListenerBody() 1033 { 1034 string[] buff; 1035 string realName = name; 1036 1037 if ( name.endsWith("-generic-event") ) 1038 realName = name[0..$-14]; 1039 1040 buff ~= "{"; 1041 1042 if ( strct.name != "StatusIcon") 1043 { 1044 switch ( realName ) 1045 { 1046 case "button-press-event": buff ~= "addEvents(EventMask.BUTTON_PRESS_MASK);"; break; 1047 case "button-release-event": buff ~= "addEvents(EventMask.BUTTON_RELEASE_MASK);"; break; 1048 case "enter-notify-event": buff ~= "addEvents(EventMask.ENTER_NOTIFY_MASK);"; break; 1049 case "focus-in-event": buff ~= "addEvents(EventMask.FOCUS_CHANGE_MASK);"; break; 1050 case "focus-out-event": buff ~= "addEvents(EventMask.FOCUS_CHANGE_MASK);"; break; 1051 case "key-press-event": buff ~= "addEvents(EventMask.KEY_PRESS_MASK);"; break; 1052 case "key-release-event": buff ~= "addEvents(EventMask.KEY_RELEASE_MASK);"; break; 1053 case "leave-notify-event": buff ~= "addEvents(EventMask.LEAVE_NOTIFY_MASK);"; break; 1054 case "motion-notify-event": buff ~= "addEvents(EventMask.POINTER_MOTION_MASK);"; break; 1055 case "property-notify-event": buff ~= "addEvents(EventMask.PROPERTY_CHANGE_MASK);"; break; 1056 case "proximity-in-event": buff ~= "addEvents(EventMask.PROXIMITY_IN_MASK);"; break; 1057 case "proximity-out-event": buff ~= "addEvents(EventMask.PROXIMITY_OUT_MASK);"; break; 1058 case "scroll-event": buff ~= "addEvents(EventMask.SCROLL_MASK);"; break; 1059 case "visibility-notify-event": buff ~= "addEvents(EventMask.VISIBILITY_NOTIFY_MASK);"; break; 1060 1061 default: break; 1062 } 1063 } 1064 1065 string wrapper = getDelegateWrapperArrayName() ~ "[" ~ getDelegateWrapperArrayName() ~ ".length - 1]"; 1066 1067 buff ~= getDelegateWrapperArrayName ~ " ~= new " ~ getDelegateWrapperName ~ "(dlg, 0, connectFlags);"; 1068 buff ~= wrapper ~ ".handlerId = Signals.connectData("; 1069 buff ~= "this,"; 1070 buff ~= "\""~ realName ~"\","; 1071 buff ~= "cast(GCallback)&callBack"~ getSignalName() ~","; 1072 buff ~= "cast(void*)" ~ wrapper ~ ","; 1073 buff ~= "cast(GClosureNotify)&callBack" ~ getSignalName() ~ "Destroy,"; 1074 buff ~= "connectFlags);"; 1075 buff ~= "return " ~ wrapper ~ ".handlerId;"; 1076 buff ~= "}"; 1077 buff ~= "\n"; 1078 1079 return buff; 1080 } 1081 1082 /* 1083 string[] getRemoveListenerDeclaration() { 1084 string[] buff; 1085 // Should we document? 1086 //writeDocs(buff); 1087 buff ~= "void removeOn"~ getSignalName() ~"("~ getDelegateDecleration() ~" dlg, ConnectFlags connectFlags=cast(ConnectFlags)0)"; 1088 return buff; 1089 } 1090 1091 string[] getRemoveListenerBody() 1092 { 1093 string[] buff; 1094 string realName = name; 1095 1096 if ( name.endsWith("-generic-event") ) 1097 realName = name[0..$-14]; 1098 1099 buff ~= "{"; 1100 buff ~= "foreach(index, wrapper; " ~ getDelegateWrapperArrayName() ~ ")"; 1101 buff ~= "if (wrapper.dlg == dlg && wrapper.flags == connectFlags && wrapper.handlerId > 0)"; 1102 buff ~= "Signals.handlerDisconnect(this, wrapper.handlerId);"; 1103 buff ~= "}"; 1104 return buff; 1105 } 1106 */ 1107 1108 string[] getInternalRemoveListenerDeclaration() { 1109 string[] buff; 1110 buff ~= "protected void internalRemoveOn"~ getSignalName() ~"("~ getDelegateWrapperName() ~" source)"; 1111 return buff; 1112 } 1113 1114 string[] getInternalRemoveListenerBody() 1115 { 1116 string[] buff; 1117 string realName = name; 1118 1119 if ( name.endsWith("-generic-event") ) 1120 realName = name[0..$-14]; 1121 buff ~= "{"; 1122 buff ~= "foreach(index, wrapper; " ~ getDelegateWrapperArrayName() ~ ")"; 1123 buff ~= "{"; 1124 buff ~= "if (wrapper.dlg == source.dlg && wrapper.flags == source.flags && wrapper.handlerId == source.handlerId)"; 1125 buff ~= "{"; 1126 buff ~= getDelegateWrapperArrayName() ~ "[index] = null;"; 1127 buff ~= getDelegateWrapperArrayName() ~ " = std.algorithm.remove(" ~ getDelegateWrapperArrayName() ~ ", index);"; 1128 buff ~= "break;"; 1129 buff ~="}"; 1130 buff ~="}"; 1131 buff ~="}"; 1132 buff ~="\n"; 1133 return buff; 1134 } 1135 1136 string[] getSignalCallback() 1137 { 1138 string[] buff; 1139 string type = getType(returnType); 1140 GtkStruct dType = strct.pack.getStruct(returnType.name); 1141 1142 if ( dType ) 1143 type = dType.cType ~"*"; 1144 1145 buff ~= "extern(C) static "~ (type == "bool" ? "int" : type) 1146 ~" callBack"~ getSignalName() ~"("~ getCallbackParams() ~")"; 1147 1148 buff ~= "{"; 1149 1150 if (type == "void") 1151 { 1152 buff ~= "wrapper.dlg("~ getCallbackVars() ~");"; 1153 } 1154 else if (dType) 1155 { 1156 buff ~= "auto r = wrapper.dlg("~ getCallbackVars() ~");"; 1157 buff ~= "return r."~ dType.getHandleFunc() ~"();"; 1158 } 1159 else 1160 { 1161 buff ~= "return wrapper.dlg("~ getCallbackVars() ~");"; 1162 } 1163 1164 buff ~= "}"; 1165 buff ~= "\n"; 1166 return buff; 1167 } 1168 1169 string[] getSignalDestroyCallback() 1170 { 1171 string[] buff; 1172 buff ~= "extern(C) static void callBack"~ getSignalName() ~"Destroy(" ~ getDelegateWrapperName() ~ " wrapper, GClosure* closure)"; 1173 buff ~= "{"; 1174 buff ~= "wrapper.outer.internalRemoveOn" ~ getSignalName() ~ "(wrapper);"; 1175 buff ~= "}"; 1176 return buff; 1177 } 1178 1179 void writeDocs(ref string[] buff) 1180 { 1181 if ( (doc || returnType.doc) && wrapper.includeComments ) 1182 { 1183 buff ~= "/**"; 1184 foreach ( line; doc.splitLines() ) 1185 buff ~= " * "~ line.strip(); 1186 1187 if ( !params.empty ) 1188 { 1189 buff ~= " *"; 1190 buff ~= " * Params:"; 1191 1192 foreach ( param; params ) 1193 { 1194 if ( param.doc.empty ) 1195 continue; 1196 1197 if ( returnType.length > -1 && param == params[returnType.length] ) 1198 continue; 1199 1200 if ( isInstanceParam(param) ) 1201 continue; 1202 1203 string[] lines = param.doc.splitLines(); 1204 buff ~= " * "~ tokenToGtkD(param.name, wrapper.aliasses, localAliases()) ~" = "~ lines[0]; 1205 foreach( line; lines[1..$] ) 1206 buff ~= " * "~ line.strip(); 1207 } 1208 1209 if ( buff.endsWith(" * Params:") ) 1210 buff = buff[0 .. $-2]; 1211 } 1212 1213 if ( returnType.doc ) 1214 { 1215 string[] lines = returnType.doc.splitLines(); 1216 if ( doc ) 1217 buff ~= " *"; 1218 buff ~= " * Return: "~ lines[0]; 1219 1220 foreach( line; lines[1..$] ) 1221 buff ~= " * "~ line.strip(); 1222 } 1223 1224 if ( libVersion ) 1225 { 1226 buff ~= " *"; 1227 buff ~= " * Since: "~ libVersion; 1228 } 1229 1230 if ( throws || type == GtkFunctionType.Constructor ) 1231 buff ~= " *"; 1232 1233 if ( throws ) 1234 buff ~= " * Throws: GException on failure."; 1235 1236 if ( type == GtkFunctionType.Constructor ) 1237 buff ~= " * Throws: ConstructionException GTK+ fails to create the object."; 1238 1239 buff ~= " */"; 1240 } 1241 else if ( wrapper.includeComments ) 1242 { 1243 buff ~= "/** */\n"; 1244 } 1245 } 1246 1247 private void resolveLength() 1248 { 1249 foreach( param; params ) 1250 { 1251 if ( param.type.length > -1 ) 1252 params[param.type.length].lengthFor = param; 1253 } 1254 } 1255 1256 private string[string] localAliases() 1257 { 1258 if ( strct ) 1259 return strct.aliases; 1260 1261 return null; 1262 } 1263 1264 /** 1265 * Get an string representation of the type. 1266 */ 1267 private string getType(GtkType type, GtkParamDirection direction = GtkParamDirection.Default) 1268 { 1269 if ( isStringType(type) ) 1270 { 1271 if ( direction != GtkParamDirection.Default && !type.cType.endsWith("**") ) 1272 return "char[]"; 1273 else if ( direction == GtkParamDirection.Default && type.cType.endsWith("***") ) 1274 return "string[][]"; 1275 else if ( type.isArray && isStringArray(type.elementType, direction) ) 1276 return getType(type.elementType, direction) ~"[]"; 1277 else if ( isStringArray(type, direction) ) 1278 return "string[]"; 1279 1280 return "string"; 1281 } 1282 else if ( type.isArray() ) 1283 { 1284 string size; 1285 1286 //Special case for GBytes and GVariant. 1287 if ( type.cType == "gconstpointer" && type.elementType.cType == "gconstpointer" ) 1288 return "void[]"; 1289 1290 if ( type.cType == "guchar*" ) 1291 return "char[]"; 1292 1293 if ( type.size > -1 ) 1294 size = to!string(type.size); 1295 1296 string elmType = getType(type.elementType, direction); 1297 1298 if ( elmType == type.cType ) 1299 elmType = elmType[0..$-1]; 1300 1301 return elmType ~"["~ size ~"]"; 1302 } 1303 else if ( !type.elementType && type.zeroTerminated ) 1304 { 1305 return getType(type, GtkParamDirection.Out) ~"[]"; 1306 } 1307 else 1308 { 1309 if ( type is null || type.name == "none" ) 1310 return "void"; 1311 else if ( type.name in strct.structWrap ) 1312 return strct.structWrap[type.name]; 1313 else if ( type.name == type.cType ) 1314 return stringToGtkD(type.name, wrapper.aliasses, localAliases()); 1315 1316 GtkStruct dType = strct.pack.getStruct(type.name); 1317 1318 if ( isDType(dType) ) 1319 { 1320 if ( dType.type == GtkStructType.Interface ) 1321 return dType.name ~"IF"; 1322 else 1323 return dType.name; 1324 } 1325 else if ( type.cType.empty && dType && dType.type == GtkStructType.Record ) 1326 return dType.cType ~ "*"; 1327 } 1328 1329 if ( type.cType.empty ) 1330 { 1331 if ( auto enum_ = strct.pack.getEnum(type.name) ) 1332 return enum_.cName; 1333 1334 return stringToGtkD(type.name, wrapper.aliasses, localAliases()); 1335 } 1336 1337 if ( direction != GtkParamDirection.Default ) 1338 return stringToGtkD(type.cType[0..$-1], wrapper.aliasses, localAliases()); 1339 1340 return stringToGtkD(type.cType, wrapper.aliasses, localAliases()); 1341 } 1342 1343 private bool isDType(GtkStruct dType) 1344 { 1345 if ( dType is null ) 1346 return false; 1347 if ( dType.type.among(GtkStructType.Class, GtkStructType.Interface) ) 1348 return true; 1349 if ( dType.type == GtkStructType.Record && (dType.lookupClass || dType.lookupInterface) ) 1350 return true; 1351 1352 return false; 1353 } 1354 1355 private bool isStringType(GtkType type) 1356 { 1357 if ( type.cType.startsWith("gchar*", "char*", "const(char)*") ) 1358 return true; 1359 if ( type.name.among("utf8", "filename") ) 1360 return true; 1361 if ( type.isArray() && type.elementType.cType.startsWith("gchar", "char", "const(char)") ) 1362 return true; 1363 1364 return false; 1365 } 1366 1367 private bool isStringArray(GtkType type, GtkParamDirection direction = GtkParamDirection.Default) 1368 { 1369 if ( direction == GtkParamDirection.Default && type.cType.endsWith("**") ) 1370 return true; 1371 if ( type.elementType is null ) 1372 return false; 1373 if ( !type.elementType.cType.endsWith("*") ) 1374 return false; 1375 if ( direction != GtkParamDirection.Default && type.cType.among("char**", "gchar**", "guchar**") ) 1376 return false; 1377 1378 return true; 1379 } 1380 1381 private bool isInstanceParam(GtkParam param) 1382 { 1383 if ( param !is params[0] ) 1384 return false; 1385 if ( strct is null || strct.type != GtkStructType.Record ) 1386 return false; 1387 if ( !(strct.lookupClass || strct.lookupInterface) ) 1388 return false; 1389 if ( param.direction != GtkParamDirection.Default ) 1390 return false; 1391 if ( param.lengthFor !is null ) 1392 return false; 1393 if ( strct.cType is null ) 1394 return false; 1395 if ( param.type.cType == strct.cType ~"*" ) 1396 return true; 1397 1398 return false; 1399 } 1400 1401 private string lenId(GtkType type, string paramName = "p") 1402 { 1403 if ( type.length > -1 ) 1404 return tokenToGtkD(params[type.length].name, wrapper.aliasses, localAliases()); 1405 //The c function returns the length. 1406 else if ( type.length == -2 ) 1407 return "p"; 1408 else if ( type.size > -1 ) 1409 return to!string(type.size); 1410 1411 if ( isStringType(type) ) 1412 return null; 1413 1414 return "getArrayLength("~ paramName ~")"; 1415 } 1416 1417 /** 1418 * Is this function a static function. 1419 */ 1420 private bool isStatic() 1421 { 1422 if ( strct.noNamespace ) 1423 return false; 1424 1425 if ( type == GtkFunctionType.Function && !(!params.empty && isInstanceParam(params[0])) ) 1426 return true; 1427 1428 if ( type == GtkFunctionType.Method && strct.isNamespace() ) 1429 return true; 1430 1431 return false; 1432 } 1433 1434 /** 1435 * Check if any of the ancestors contain the function functionName. 1436 */ 1437 private bool checkOverride() 1438 { 1439 if ( name == "get_type" ) 1440 return false; 1441 if ( name == "to_string" && params.empty ) 1442 return true; 1443 1444 GtkStruct ancestor = strct.getParent(); 1445 1446 while(ancestor) 1447 { 1448 if ( name in ancestor.functions && name !in strct.aliases ) 1449 { 1450 GtkFunction func = ancestor.functions[name]; 1451 1452 if ( !(func.noCode || func.isVariadic() || func.type == GtkFunctionType.Callback) && paramsEqual(func) ) 1453 return true; 1454 } 1455 1456 ancestor = ancestor.getParent(); 1457 } 1458 1459 return false; 1460 } 1461 1462 /** 1463 * Return true if the params of func match the params of this function. 1464 */ 1465 private bool paramsEqual(GtkFunction func) 1466 { 1467 if ( params.length != func.params.length ) 1468 return false; 1469 1470 foreach ( i, param; params ) 1471 { 1472 if ( getType(param.type) != getType(func.params[i].type) ) 1473 return false; 1474 } 1475 1476 return true; 1477 } 1478 1479 private string construct(string type) 1480 { 1481 GtkStruct dType = strct.pack.getStruct(type); 1482 debug assert(dType, "Only call construct for valid GtkD types"); 1483 string name = dType.name; 1484 1485 if ( type in strct.structWrap ) 1486 name = strct.structWrap[type]; 1487 1488 if ( dType.pack.name.among("cairo", "glib", "gthread") ) 1489 return "new "~name; 1490 else if( dType.type == GtkStructType.Interface ) 1491 return "ObjectG.getDObject!("~ name ~", "~ name ~"IF)"; 1492 else 1493 return "ObjectG.getDObject!("~ name ~")"; 1494 } 1495 1496 private string getCallbackParams() 1497 { 1498 string buff; 1499 1500 buff = strct.cType ~"* "~ strct.name.toLower() ~"Struct"; 1501 foreach( param; params ) 1502 { 1503 if ( auto par = strct.pack.getStruct(param.type.name) ) 1504 buff ~= stringToGtkD(", "~ par.cType ~"* "~ param.name, wrapper.aliasses, localAliases()); 1505 else if ( auto enum_ = strct.pack.getEnum(param.type.name) ) 1506 buff ~= stringToGtkD(", "~ enum_.cName ~" "~ param.name, wrapper.aliasses, localAliases()); 1507 else if ( !param.type.cType.empty ) 1508 buff ~= stringToGtkD(", "~ param.type.cType ~" "~ param.name, wrapper.aliasses, localAliases()); 1509 else 1510 buff ~= stringToGtkD(", "~ param.type.name ~" "~ param.name, wrapper.aliasses, localAliases()); 1511 } 1512 1513 buff ~= "," ~ getDelegateWrapperName() ~ " wrapper"; 1514 return buff; 1515 } 1516 1517 private string getCallbackVars() 1518 { 1519 string buff; 1520 1521 foreach( i, param; params ) 1522 { 1523 if ( i > 0 ) 1524 buff ~= ", "; 1525 1526 GtkStruct par = strct.pack.getStruct(param.type.name); 1527 1528 if ( isDType(par) ) 1529 { 1530 buff ~= construct(param.type.name) ~"("~ tokenToGtkD(param.name, wrapper.aliasses, localAliases()) ~")"; 1531 } 1532 else if ( isStringType(param.type) ) 1533 { 1534 if ( isStringArray(param.type) ) 1535 buff ~= "Str.toStringArray("~ tokenToGtkD(param.name, wrapper.aliasses, localAliases()) ~")"; 1536 else 1537 buff ~= "Str.toString("~ tokenToGtkD(param.name, wrapper.aliasses, localAliases()) ~")"; 1538 } 1539 else 1540 { 1541 buff ~= tokenToGtkD(param.name, wrapper.aliasses, localAliases()); 1542 } 1543 } 1544 1545 if ( !buff.empty ) 1546 buff ~= ", "; 1547 buff ~= "wrapper.outer"; 1548 return buff; 1549 } 1550 } 1551 1552 enum GtkParamDirection : string 1553 { 1554 Default = "", 1555 Out = "out", 1556 InOut = "inout", 1557 } 1558 1559 final class GtkParam 1560 { 1561 string doc; 1562 string name; 1563 GtkType type; 1564 GtkTransferOwnership ownerschip = GtkTransferOwnership.None; 1565 GtkParamDirection direction = GtkParamDirection.Default; 1566 1567 GtkParam lengthFor; 1568 GtkWrapper wrapper; 1569 1570 this(GtkWrapper wrapper) 1571 { 1572 this.wrapper = wrapper; 1573 } 1574 1575 void parse(T)(XMLReader!T reader) 1576 { 1577 name = reader.front.attributes["name"]; 1578 1579 if ( "transfer-ownership" in reader.front.attributes ) 1580 ownerschip = cast(GtkTransferOwnership)reader.front.attributes["transfer-ownership"]; 1581 if ( "direction" in reader.front.attributes ) 1582 direction = cast(GtkParamDirection)reader.front.attributes["direction"]; 1583 1584 reader.popFront(); 1585 1586 while( !reader.empty && !reader.endTag("parameter", "instance-parameter") ) 1587 { 1588 if ( reader.front.type == XMLNodeType.EndTag ) 1589 { 1590 reader.popFront(); 1591 continue; 1592 } 1593 1594 switch(reader.front.value) 1595 { 1596 case "doc": 1597 reader.popFront(); 1598 doc ~= reader.front.value; 1599 reader.popFront(); 1600 break; 1601 case "doc-deprecated": 1602 reader.popFront(); 1603 doc ~= "\n\nDeprecated: "~ reader.front.value; 1604 reader.popFront(); 1605 break; 1606 case "array": 1607 case "type": 1608 type = new GtkType(wrapper); 1609 type.parse(reader); 1610 break; 1611 case "varargs": 1612 type = new GtkType(wrapper); 1613 type.name = "..."; 1614 type.cType = "..."; 1615 break; 1616 default: 1617 throw new XMLException(reader, "Unexpected tag: "~ reader.front.value ~" in GtkParam: "~ name); 1618 } 1619 1620 reader.popFront(); 1621 } 1622 } 1623 }