1#!/usr/bin/env python
2
3"""
4Parse a .gir file for any of the gtk+ libraries (gtk+, glib,...)
5and generate Ada bindings.
6"""
7
8# Issues:
9#   - Missing handling of <field> nodes (see GtkArrow for instance)
10# - Some comments contain xref like "#GtkMisc". Not sure what to do with
11#     those. Likewise for names of subprograms in comments.
12#
13# Backward incompatibility:
14#   - Missing documentation for some properties.
15#     SOLVE: we could point to the corresponding Set_* and Get_* subprograms,
16#            or simply ignore the missing doc
17
18from xml.etree.cElementTree import parse, Element, QName, tostring, fromstring
19from adaformat import *
20import copy
21from binding_gtkada import GtkAda
22from data import enums, interfaces, binding, user_data_params
23from data import destroy_data_params
24
25# Unfortunately, generating the slot marshallers in a separate package
26# does not work since we end up with circularities in a number of
27# cases. For now, we simply duplicate them as needed
28SHARED_SLOT_MARSHALLERS = False
29
30# For parsing command line options
31from optparse import OptionParser
32
33# Python interpreter version check: this script does not work with Python
34# version 2.6 or earlier!
35from sys import version_info
36version_string = '.'.join(map(str, version_info[0:3]))
37if version_info[0] < 2:
38    print('Need at least Python 2.7, got version ' + version_string)
39    quit(1)
40if version_info[0] == 2 and version_info[1] < 7:
41    print('Need at least Python 2.7, got version ' + version_string)
42    quit(1)
43
44uri = "http://www.gtk.org/introspection/core/1.0"
45glib_uri = "http://www.gtk.org/introspection/glib/1.0"
46c_uri = "http://www.gtk.org/introspection/c/1.0"
47
48cidentifier = QName(c_uri, "identifier").text
49cidentifier_prefix = QName(c_uri, "identifier-prefixes").text
50ctype_qname = QName(c_uri, "type").text
51ggettype = QName(glib_uri, "get-type").text
52gsignal = QName(glib_uri, "signal").text
53glib_type_struct = QName(glib_uri, "type-struct").text
54glib_type_name = QName(glib_uri, "type-name").text
55namespace = QName(uri, "namespace").text
56narray = QName(uri, "array").text
57nbitfield = QName(uri, "bitfield").text
58ncallback = QName(uri, "callback").text
59nclass = QName(uri, "class").text
60ndoc = QName(uri, "doc").text
61nenumeration = QName(uri, "enumeration").text
62nfield = QName(uri, "field").text
63nfunction = QName(uri, "function").text
64nimplements = QName(uri, "implements").text
65ninterface = QName(uri, "interface").text
66nmember = QName(uri, "member").text
67nmethod = QName(uri, "method").text
68nvirtualmethod = QName(uri, "virtual-method").text
69nparam = QName(uri, "parameter").text
70nparams = QName(uri, "parameters").text
71nrecord = QName(uri, "record").text
72nunion = QName(uri, "union").text
73nreturn = QName(uri, "return-value").text
74ntype = QName(uri, "type").text
75nvalue = QName(uri, "value").text
76nvarargs = QName(uri, "varargs").text
77nconstant = QName(uri, "constant").text
78ninstanceparam = QName(uri, "instance-parameter").text
79
80
81class GIR(object):
82
83    def __init__(self, files):
84        """Parse filename and initializes SELF"""
85
86        self.packages = dict()  # Ada name (lower case) -> Package instance
87        self.ccode = ""
88        self.classes = dict()  # Maps C name to a GIRClass instance
89        self.interfaces = dict()  # Maps GIR's "name" to an interface
90        self.ctype_interfaces = dict()  # Maps GIR's c:type to an interface
91        self.callbacks = dict()  # Ada name to GIR XML node
92        self.enums = dict()  # Maps C "name" to a GIR XML node
93        self.globals = GlobalsBinder(self)  # global vars
94        self.records = dict()  # Maps C "name" to a GIR XML node
95        # Maps C "name" to a GIR XML node for constants
96        self.constants = dict()
97
98        self.bound = set()  # C names for the entities that have an Ada binding
99
100        # The marshallers that have been generated when we use a slot object.
101        # These can be shared among all packages, since the profiles of the
102        # handlers are the same.
103        if SHARED_SLOT_MARSHALLERS:
104            self.slot_marshallers = set()
105            self.slot_marshaller_pkg = self.get_package(
106                name="Gtkada.Marshallers",
107                ctype=None,
108                doc="Automatically generated, used internally by GtkAda")
109            self.slot_marshaller_section = self.slot_marshaller_pkg.section("")
110
111        for filename in files:
112            _tree = parse(filename)
113            root = _tree.getroot()
114
115            identifier_prefix = root.find(namespace).get(cidentifier_prefix)
116
117            k = "%s/%s" % (namespace, ncallback)
118            for cl in root.findall(k):
119                ct = cl.get(ctype_qname)
120                type = Callback(naming.case(ct))
121                naming.add_type_exception(cname=ct, type=type)
122                ct = naming.type(ct).ada
123                self.callbacks[ct] = cl
124
125            k = "%s/%s" % (namespace, ninterface)
126            for cl in root.findall(k):
127                self.ctype_interfaces[cl.get(ctype_qname)] = \
128                    self.interfaces[cl.get("name")] = \
129                    self._create_class(
130                    root, cl, is_interface=True, is_gobject=False,
131                    identifier_prefix=identifier_prefix)
132
133            k = "%s/%s" % (namespace, nclass)
134            for cl in root.findall(k):
135                self.classes[cl.get(ctype_qname)] = self._create_class(
136                    root, cl, is_interface=False,
137                    identifier_prefix=identifier_prefix)
138
139            k = "%s/%s" % (namespace, nconstant)
140            for cl in root.findall(k):
141                self.constants[cl.get(ctype_qname)] = cl
142
143            # Some <record> are defined with methods. They are bound the same
144            # way in GtkAda, except that they do not derive from GObject
145
146            k = "%s/%s" % (namespace, nrecord)
147            for cl in root.findall(k):
148                if cl.findall(nmethod):
149                    self.classes[cl.get(ctype_qname)] = self._create_class(
150                        root, cl, is_interface=False, is_gobject=False,
151                        identifier_prefix=identifier_prefix)
152                self.records[cl.get(ctype_qname)] = cl
153
154            k = "%s/%s" % (namespace, nunion)
155            for cl in root.findall(k):
156                if cl.findall(nmethod):
157                    self.classes[cl.get(ctype_qname)] = self._create_class(
158                        root, cl, is_interface=False, is_gobject=False,
159                        identifier_prefix=identifier_prefix)
160                self.records[cl.get(ctype_qname)] = cl
161
162            for enums in (nenumeration, nbitfield):
163                k = "%s/%s" % (namespace, enums)
164                for cl in root.findall(k):
165                    self.enums[cl.get(ctype_qname)] = cl
166
167            self.globals.add(root)
168
169    def show_unbound(self):
170        """Display the list of entities known in the GIR files, but that have
171           no Ada binding.
172        """
173
174        print "Missing bindings:"
175        count = 0
176        for name in sorted(gir.interfaces.iterkeys()):
177            if name not in self.bound:
178                sys.stdout.write("%-28s" % (name + "(intf)", ))
179                count += 1
180                if (count % 4) == 0:
181                    sys.stdout.write("\n")
182
183        for name in sorted(gir.classes.iterkeys()):
184            if name not in self.bound:
185                sys.stdout.write("%-28s" % name)
186                # print '    "--%s", # Not tested yet, from Gio' % name
187                count += 1
188                if (count % 4) == 0:
189                    sys.stdout.write("\n")
190
191        print
192
193    def _get_class_node(self, rootNode, girname):
194        """Find the <class> node in the same XML document as node that matches
195           [girname].
196        """
197        k = "{%(uri)s}namespace/{%(uri)s}class" % {"uri": uri}
198        for cl in rootNode.findall(k):
199            if cl.get("name") == girname:
200                return cl
201        return None
202
203    def _create_class(self, rootNode, node, is_interface,
204                      identifier_prefix, is_gobject=True,
205                      has_toplevel_type=True):
206        return GIRClass(self, rootNode=rootNode, node=node,
207                        is_interface=is_interface,
208                        is_gobject=is_gobject,
209                        identifier_prefix=identifier_prefix,
210                        has_toplevel_type=has_toplevel_type)
211
212    def debug(self, element):
213        """A debug form of element"""
214        return tostring(element)
215
216    def get_package(self, name, ctype, doc=""):
217        """Return a handle to an Ada package"""
218        if not name.lower() in self.packages:
219            pkg = self.packages[name.lower()] = Package(
220                name=name,
221                doc=gtkada.get_pkg(ctype).get_doc())
222        else:
223            pkg = self.packages[name.lower()]
224
225        if doc:
226            pkg.doc = ["<description>", doc, "</description>"] + pkg.doc
227
228        return pkg
229
230    def generate(self, out, cout):
231        """Generate Ada code for all packages"""
232        for pkg in self.packages.itervalues():
233            out.write(pkg.spec().encode('UTF-8'))
234            out.write("\n")
235            out.write(pkg.body().encode('UTF-8'))
236            out.write("\n")
237
238        cout.write(self.ccode)
239
240
241class GlobalsBinder(object):
242
243    def __init__(self, gir):
244        self.gir = gir
245        self.globals = dict()
246
247    def add(self, node):
248        k = "{%(uri)s}namespace/{%(uri)s}function" % {"uri": uri}
249        all = node.findall(k)
250        if all is not None:
251            for c in all:
252                id = c.get(cidentifier)
253                self.globals[id] = c
254
255    def get_function(self, id):
256        """Return the XML node corresponding to a global function"""
257        return self.globals[id]
258
259
260def _get_clean_doc(node):
261    """
262    Get the <doc> child node, and replace common unicode characters by their
263    ASCII equivalent to keep the Ada specs more readable in a terminal.
264    """
265
266    doc = node.findtext(ndoc, "")
267    if doc:
268        doc = doc.replace(u"\u2019", "'").replace(
269            u"\u201c", '"').replace(u"\u201d", '"')
270    return doc
271
272
273def _get_type(nodeOrType, allow_access=True, allow_none=False,
274              transfer_ownership=False, userecord=True, pkg=None):
275    """Return the type of the GIR XML node.
276       nodeOrType can be one of:
277          * a string, given the name of the C type
278          * an instance of CType, which is returned as is.
279          * An XML node from which the information is gathered.
280
281       `allow_access' should be False if "access Type" parameters should
282       not be allowed, and an explicit type is needed instead.
283       `allow_none': see doc for CType.
284       `pkg' is used to add with statements, if specified
285    """
286    if isinstance(nodeOrType, CType):
287        return nodeOrType
288
289    elif isinstance(nodeOrType, str):
290        return naming.type(name=nodeOrType,
291                           cname=nodeOrType,
292                           userecord=userecord,
293                           transfer_ownership=transfer_ownership,
294                           allow_access=allow_access,
295                           allow_none=allow_none, pkg=pkg)
296
297    else:
298        t = nodeOrType.find(ntype)
299        if t is not None:
300            if t.get("name") == "none":
301                return None
302
303            ctype_name = t.get(ctype_qname)
304            if ctype_name:
305                ctype_name = ctype_name.replace("const ", "")
306            return naming.type(name=t.get("name"),
307                               cname=ctype_name,
308                               userecord=userecord,
309                               transfer_ownership=transfer_ownership,
310                               allow_access=allow_access,
311                               allow_none=allow_none, pkg=pkg)
312
313        a = nodeOrType.find(narray)
314        if a is not None:
315            t = a.find(ntype)
316            if a:
317                type = t.get(ctype_qname)
318                name = t.get("name") or type  # Sometimes name is not set
319
320                size = a.get("fixed-size", None)
321
322                if type:
323                    type = "array_of_%s" % (type, )
324
325                return naming.type(name="array_of_%s" % name,
326                                   cname=type,
327                                   pkg=pkg, isArray=True,
328                                   array_fixed_size=size,
329                                   transfer_ownership=transfer_ownership,
330                                   allow_none=allow_none,
331                                   userecord=userecord,
332                                   allow_access=allow_access)
333
334        a = nodeOrType.find(nvarargs)
335        if a is not None:
336            # A function with multiple arguments cannot be bound
337            # No need for an error message, we will already let the user know
338            # that the function is not bound.
339            return None
340
341    print("Error: XML Node has unknown type: %s (%s)" % (nodeOrType, nodeOrType.attrib))
342    return None
343
344
345class SubprogramProfile(object):
346
347    """A class that groups info on the parameters of a function and
348       its return type.
349    """
350
351    def __init__(self):
352        self.node = None    # the XML node for this profile
353        self.gtkmethod = None
354        self.params = None  # list of parameters (None if we have varargs)
355        self.returns = None  # return value (None for a procedure)
356        self.returns_doc = ""  # documentation for returned value
357        self.doc = ""       # documentation for the subprogram
358
359        # The following fields are used to handle callback parameters
360        # and generate an Ada generic
361
362        self.callback_param = []  # indexes of the callback parameter
363        self.user_data_param = -1  # index of the "user data" parameter
364        self.destroy_param = -1   # index of the parameter to destroy data
365
366    def __repr__(self):
367        return "<SubprogramProfile %s>" % self.node
368
369    @staticmethod
370    def parse(node, gtkmethod, pkg=None, ignore_return=False):
371        """Parse the parameter info and return type info from the XML
372           GIR node, overriding with binding.xml.
373           gtkmethod is the GtkAdaMethod that contains the overriding for the
374           various method attributes.
375           If pkg is specified, with statements are added as necessary.
376
377           If ignore_return is True, the return type is not parsed. This is
378           used for constructors, so that we do not end up adding extra 'with'
379           statements in the generated package.
380        """
381        profile = SubprogramProfile()
382        profile.node = node
383        profile.gtkmethod = gtkmethod
384
385        # make sure to init the 'returns' field before the parameters, to be
386        # able to correctly set the parameters direction ('in out' or 'out'
387        # case)
388        if not ignore_return:
389            profile.returns = profile._returns(node, gtkmethod, pkg=pkg)
390
391        profile.params = profile._parameters(node, gtkmethod, pkg=pkg)
392
393        profile.doc = profile._getdoc(gtkmethod, node)
394        return profile
395
396    @staticmethod
397    def setter(node, pkg=None):
398        """Create a new SubprogramProfile for a getter"""
399        profile = SubprogramProfile()
400        profile.node = node
401        profile.params = [Parameter("Value", _get_type(node, pkg))]
402        return profile
403
404    def callback_param_info(self):
405        """If there is one or more callback parameters in this profile, return
406           them so that we can generate the appropriate function.  Returns None
407           if there are no such parameters.
408        """
409        if not self.callback_param:
410            return None
411        return [self.params[p] for p in self.callback_param]
412
413    def callback_destroy(self):
414        if self.destroy_param < 0:
415            return None
416        return self.params[self.destroy_param]
417
418    def callback_user_data(self):
419        """Returns the name of the "user_data" parameter"""
420
421        if self.user_data_param == -1:
422            return None
423        return self.params[self.user_data_param].name
424
425    def has_varargs(self):
426        return self.params is None
427
428    def direct_c_map(self):
429        """Wether all parameters and return value can be mapped directly from
430           C to Ada.
431        """
432        for p in self.params:
433            # If a parameter is not mapped in Ada, we need an actual body
434            if not p.direct_c_map() or not p.ada_binding:
435                return False
436        return self.returns is None or self.returns.direct_c_map()
437
438    def c_params(self, localvars, code):
439        """Returns the list of parameters for an Ada function that would be
440           a direct pragma Import. local variables or additional code will
441           be extended as needed to handle conversions.
442        """
443        assert(isinstance(localvars, list))
444        assert(isinstance(code, list))
445
446        result = []
447        for p in self.params:
448            n = p.name
449            is_temporary = False
450
451            if self.returns is not None and p.mode != "in" and p.ada_binding:
452                n = "Acc_%s" % p.name
453                var = Local_Var(
454                    name=n,
455                    aliased=True,
456                    default="" if p.mode != "in out" else p.name,
457                    type=p.type)
458                var.type.userecord = False
459                localvars.append(var)
460
461                if p.mode == "access":
462                    if p.type.allow_none:
463                        code.append(
464                            "if %s /= null then %s.all := %s; end if;"
465                            % (p.name, p.name, var.name))
466                    else:
467                        code.append("%s.all := %s;" % (p.name, var.name))
468                else:
469                    is_temporary = p.mode != "out"
470                    code.append("%s := %s;" % (p.name, var.name))
471
472            # If we do not bind the parameter in the Ada profile, we will need
473            # to substitute its default value instead. But we don't want to
474            # systematically put the default value, which is in Ada. We would
475            # end up with Interfaces.C.Strings.chars_ptr=""
476
477            result.append(Parameter(
478                name=n, mode=p.mode, type=p.type,
479                for_function=self.returns is not None,
480                default=p.default if not p.ada_binding else None,
481                is_temporary_variable=is_temporary,
482                ada_binding=p.ada_binding))
483
484        return result
485
486    def set_class_wide(self):
487        """This profile is not for a primitive operation, but for a class-wide
488           operation.
489        """
490        if isinstance(self.params[0].type, GObject):
491            self.params[0].type.classwide = True
492
493    def add_param(self, pos, param):
494        """Add a new parameter in the list, at the given position"""
495        self.params.insert(pos, param)
496        if self.callback_param:
497            self.callback_param = [p + 1 if p >= pos else p
498                                   for p in self.callback_param]
499        if self.user_data_param >= 0 and self.user_data_param >= pos:
500            self.user_data_param += 1
501        if self.destroy_param >= 0 and self.destroy_param >= pos:
502            self.destroy_param += 1
503
504    def replace_param(self, name_or_index, type):
505        """Overrides the type of a parameter"""
506        if name_or_index is None:
507            return
508
509        if isinstance(name_or_index, int):
510            self.params[name_or_index].set_type(type)
511        else:
512            for idx, p in enumerate(self.params):
513                if p.name.lower() == name_or_index.lower():
514                    self.params[idx].set_type(type)
515                    return
516
517    def remove_param(self, names):
518        """Remove the parameter with the given names from the list"""
519        assert(isinstance(names, list))
520
521        for n in names:
522            if n is not None:
523                n = n.lower()
524                for p in self.params:
525                    if p.name.lower() == n:
526                        self.params.remove(p)
527                        break
528
529    def find_param(self, names):
530        """Return the first name for which there is a parameter"""
531        for n in names:
532            lo = n.lower()
533            for p in self.params:
534                if p.name.lower() == lo:
535                    return n
536        return None
537
538    def unset_default_values(self):
539        """Remove the default values for the parameters"""
540        for p in self.params:
541            p.default = None
542
543    def subprogram(self, name, showdoc=True, local_vars=[], code=[],
544                   convention=None, lang="ada"):
545        """Return an instance of Subprogram with the corresponding profile.
546           lang is one of "ada", "c->ada" or "ada->c".
547        """
548
549        params = self.params
550        if lang == "ada":
551            params = [p for p in self.params if p.ada_binding]
552
553        subp = Subprogram(
554            name=name,
555            plist=params,
556            returns=self.returns,
557            showdoc=showdoc,
558            doc=self.doc,
559            lang=lang,
560            local_vars=local_vars,
561            code=code)
562        subp.convention = convention or self.gtkmethod.convention()
563
564        if name != "":
565            depr = self.node.get("deprecated")
566            if depr is not None:
567                subp.mark_deprecated(
568                    "\nDeprecated since %s, %s"
569                    % (self.node.get("deprecated-version"), depr))
570            elif self.gtkmethod and self.gtkmethod.is_obsolete():
571                subp.mark_deprecated("Deprecated")
572
573        return subp
574
575    def _getdoc(self, gtkmethod, node):
576        doc = gtkmethod.get_doc(default=_get_clean_doc(node))
577        if node.get("version"):
578            doc.append("Since: gtk+ %s" % node.get("version"))
579        return doc
580
581    def _parameters(self, c, gtkmethod, pkg):
582        """Parse the <parameters> child node of c"""
583        if c is None:
584            return []
585
586        params = c.find(nparams)
587        if params is None:
588            return []
589
590        # Check whether we'll bind to a procedure or to a function
591        is_function = self.returns and not gtkmethod.return_as_param()
592
593        result = []
594
595        for p_index, p in enumerate(params.findall(nparam)):
596            name = p.get("name")
597            if name == "...":
598                name = "varargs"
599
600            gtkparam = gtkmethod.get_param(name=name)
601            adan = gtkparam.ada_name()
602
603            ada_binding = adan is None or adan != ""
604            name = adan or name  # override default computed name
605
606            default = gtkparam.get_default()
607            allow_access = not default
608            allow_none = gtkparam.allow_none(girnode=p) or default == 'null'
609            nodeOrType = gtkparam.get_type(pkg=pkg) or p
610
611            type = _get_type(
612                nodeOrType=nodeOrType,
613                allow_none=allow_none,
614                userecord=default != 'null',
615                allow_access=allow_access,
616                pkg=pkg)
617
618            if type is None:
619                if nodeOrType.find(nvarargs) is not None:
620                    type = gtkmethod.get_param("varargs").get_type(pkg=pkg)
621                else:
622                    type = gtkmethod.get_param(name).get_type(pkg=pkg)
623                if type is None:
624                    return None
625                type = _get_type(type)
626
627            if not default and allow_none and isinstance(type, UTF8):
628                default = '""'
629
630            if (p.get("scope", "") in ("notified", "call", "async")
631                    or p.get("closure", "") != ""):
632
633                # "async" means a callback with no closure. As a special case,
634                # we ignore it for destroy callbacks, since they are already
635                # handled specially.
636
637                if p.get("scope") != "async" \
638                        or type.ada != "Glib.G_Destroy_Notify_Address":
639                    self.callback_param.append(p_index)
640                    self.user_data_param = int(p.get("closure", "-1"))
641                    self.destroy_param = int(p.get("destroy", "-1")) - 1
642
643            direction = gtkparam.get_direction() or p.get("direction", "in")
644            assert direction in ("in", "out", "inout", "access"), \
645                "Invalid value for direction: '%s'" % direction
646
647            if direction == "inout":
648                mode = "in out"
649            elif direction in ("out", "access"):
650                mode = direction
651            elif type.is_ptr:
652                mode = "in out"
653            else:
654                mode = "in"
655
656            if is_function and direction not in ("in", "access"):
657                mode = "access"
658
659            doc = _get_clean_doc(p)
660            if doc:
661                doc = '"%s": %s' % (name, doc)
662
663            result.append(
664                Parameter(name=naming.case(name),
665                          type=type,
666                          mode=mode,
667                          default=default,
668                          ada_binding=ada_binding,
669                          doc=doc))
670
671        return result
672
673    def _returns(self, node, gtkmethod, pkg):
674        """Parse the method's return type"""
675
676        returns = gtkmethod.returned_c_type()
677        if returns is None:
678            ret = node.find(nreturn)
679            if ret is None:
680                # For a <field>, the method's return value will be the type
681                # of the field itself
682                ret = node
683            else:
684                self.returns_doc = _get_clean_doc(ret)
685                if self.returns_doc:
686                    self.returns_doc = "Returns %s" % self.returns_doc
687
688            return _get_type(
689                ret, allow_access=False, pkg=pkg,
690                transfer_ownership=gtkmethod.transfer_ownership(ret))
691        else:
692            return naming.type(name=None, cname=returns, pkg=pkg)
693
694
695class GIRClass(object):
696
697    """Represents a gtk class"""
698
699    def __init__(self, gir, rootNode, node, identifier_prefix,
700                 is_interface=False, is_gobject=True, has_toplevel_type=True):
701        """If has_toplevel_type is False, no widget type is generated"""
702
703        self.gir = gir
704        self.node = node
705        self.rootNode = rootNode
706        self.ctype = self.node.get(ctype_qname)
707        if not self.ctype:
708            print("no c:type defined for %s" % (self.node.get(glib_type_name, )))
709            return
710
711        self._private = ""
712        self._generated = False
713        self.identifier_prefix = identifier_prefix
714        self.implements = dict()  # Implemented interfaces
715        self.is_gobject = is_gobject
716        self.is_interface = is_interface
717        self.has_toplevel_type = has_toplevel_type
718        self.callbacks = set()  # The callback functions
719        self.pkg = None  # Instance of Package(), that we are generating
720
721        # List of Convert(...) functions that were implemented
722        self.conversions = dict()
723
724        self.__marshallers = set()  # The generated marshallers
725
726        # Search for the GtkAda binding information
727
728        self.gtkpkg = gtkada.get_pkg(self.ctype)
729        if not self.gtkpkg.bindtype:
730            self.has_toplevel_type = False
731            self.is_gobject = False
732
733        # Is this a binding for an opaque C record (not a GObject). In this
734        # case, we bind it as an Ada tagged type so that we can use the
735        # convenient dot notation for primitive operations. This is only doable
736        # if there is no public field that should be user visible in the
737        # record. Otherwise, we'll map to a standard Ada record
738        # (self.is_record)
739
740        self.is_proxy = False
741        self.is_boxed = (self.node.tag == nrecord
742                         and (not self.node.findall(nfield)
743                              or self.node.get("introspectable", "1") == "0"))
744        self.is_record = self.node.tag == nrecord and not self.is_boxed
745
746        if (self.is_boxed
747                and naming.type_exceptions.get(self.ctype) is not None
748                and isinstance(naming.type_exceptions.get(self.ctype), Proxy)):
749            self.is_proxy = True
750            self.is_boxed = False
751
752        # Register naming exceptions for this class
753
754        n = naming.case(self.ctype)
755
756        into = self.gtkpkg.into()
757        ada = self.gtkpkg.ada_name()
758        if ada:
759            pkg = ada
760        elif into:
761            into = naming.case(into)
762            pkg = naming.protect_keywords(into.replace("_", ".", 1))
763        else:
764            pkg = naming.protect_keywords(n.replace("_", ".", 1))
765
766        pkg = "%s.%s" % (pkg, n)
767        naming.add_girname(girname=n, ctype=self.ctype)
768
769        if has_toplevel_type:
770            ctype = node.get(ctype_qname)
771            if is_interface:
772                t = Interface(pkg)
773            elif is_gobject:
774                t = GObject(pkg)
775            elif self.is_proxy:
776                t = Proxy(pkg)
777            elif self.is_boxed:
778                t = Tagged(pkg)
779            else:
780                t = Record(pkg)
781
782            naming.add_type_exception(cname=ctype, type=t)
783            classtype = naming.type(name=self.ctype)
784            typename = classtype.ada
785            self.name = package_name(typename)
786            if ada is not None:
787                self.name = ada
788
789            self.ada_package_name = self.name
790
791            if not self.has_toplevel_type:
792                # Compute the package name ignoring the type_exceptions. For
793                # instance, we have defined that GdkWindow is mapped to
794                # Gdk.Gdk_Window, but the operations should go into the package
795                # Gdk.Window.Gdk_Window.
796                self.ada_package_name = package_name(pkg)
797
798        else:
799            typename = ""
800            self.name = package_name(pkg)
801            self.ada_package_name = self.name
802
803        self.gtkpkg.register_types(adapkg=self.ada_package_name)
804
805        # Compute information that will be used for the binding
806
807        self._subst = {  # for substitution in string templates
808            "name": self.name,
809            "typename": base_name(typename),
810            "cname": self.ctype or ""}
811
812    def _handle_function(self, section, c, ismethod=False, gtkmethod=None,
813                         showdoc=True, isinherited=False):
814        cname = c.get(cidentifier)
815
816        if gtkmethod is None:
817            gtkmethod = self.gtkpkg.get_method(cname=cname)
818
819        if gtkmethod.bind():
820            profile = SubprogramProfile.parse(
821                node=c, gtkmethod=gtkmethod, pkg=self.pkg)
822            self._handle_function_internal(
823                section, node=c, cname=cname,
824                gtkmethod=gtkmethod,
825                profile=profile,
826                showdoc=showdoc,
827                ismethod=ismethod,
828                isinherited=isinherited)
829        else:
830            naming.add_cmethod(
831                cname, gtkmethod.ada_name() or cname)  # Avoid warning later on
832
833    def _func_is_direct_import(self, profile):
834        """Whether a function with this profile
835           should be implemented directly as a pragma Import, rather than
836           require its own body.
837        """
838        return not self.is_gobject \
839            and not self.is_boxed \
840            and profile.direct_c_map()
841
842    def _add_self_param(self, adaname, node, gtkmethod, profile, inherited):
843        """Add a Self parameter to the list of parameters in profile.
844           The exact type of the parameter depends on several criteria.
845
846           :param bool inherited: should be true if this is for a subprogram
847             inherited from an interface (in which case we force the type of
848             Self to be that of the child, not the interface type as described
849             in the gir file)
850        """
851
852        # Try to extract the type of the parameter from the instance-parameter
853        # node.
854        t = None
855        if not inherited:
856            try:
857                ip = node.iter(ninstanceparam).next()
858                ipt = ip.find(ntype)
859                if ipt is not None:
860                    ctype_name = ipt.get(ctype_qname)
861                    if ctype_name:
862                        ctype_name = ctype_name.replace('const ', '')
863                    t = naming.type(name=ipt.get('name'),
864                                    cname=ctype_name,
865                                    useclass=gtkmethod.is_class_wide())
866            except StopIteration:
867                t = None
868
869        # There was no instance-parameter node, guess the type from the
870        # package name
871
872        if t is None:
873            t = naming.type(self._subst["cname"],
874                            cname=self._subst["cname"],
875                            useclass=gtkmethod.is_class_wide())
876
877        gtkparam = gtkmethod.get_param("self")
878        pname = gtkparam.ada_name() or "Self"
879
880        direction = gtkparam.get_direction() or "in"
881        if direction in ("out", "access"):
882            mode = direction
883        elif direction == "inout":
884            mode = "in out"
885        else:
886            mode = "in"
887
888        profile.add_param(0, Parameter(name=pname, type=t, mode=mode))
889
890    def _handle_function_internal(self, section, node, cname,
891                                  gtkmethod,
892                                  profile=None,
893                                  showdoc=True,
894                                  adaname=None,
895                                  ismethod=False,
896                                  isinherited=False):
897        """Generate a binding for a function.,
898           This returns None if no binding was made, an instance of Subprogram
899           otherwise.
900           `adaname' is the name of the generated Ada subprograms. By default,
901           it is computed automatically from either binding.xml or the "name"
902           attribute of `node'.
903           `profile' is an instance of SubprogramProfile
904        """
905        assert(profile is None or isinstance(profile, SubprogramProfile))
906
907        if profile.has_varargs() \
908                and gtkmethod.get_param("varargs").node is None:
909            naming.add_cmethod(cname, cname)  # Avoid warning later on.
910            print "No binding for %s: varargs" % cname
911            return None
912
913        is_import = self._func_is_direct_import(profile) \
914            and not gtkmethod.get_body() \
915            and not gtkmethod.return_as_param()
916        adaname = adaname or gtkmethod.ada_name() or node.get("name").title()
917        adaname = naming.protect_keywords(adaname)
918
919        if not isinherited:
920            naming.add_cmethod(cname, "%s.%s" % (self.pkg.name, adaname))
921
922        if ismethod:
923            self._add_self_param(
924                adaname, node, gtkmethod, profile, inherited=isinherited)
925
926        if adaname.startswith("Gtk_New"):
927            # Overrides the GIR file even if it reported a function or method
928            self._handle_constructor(
929                node, gtkmethod=gtkmethod, cname=cname, profile=profile)
930            return
931
932        local_vars = []
933        call = ""
934
935        body = gtkmethod.get_body()
936        if not is_import:
937            # Prepare the Internal C function
938
939            internal_call = []
940            internal = Subprogram(
941                name="Internal",
942                returns=profile.returns,
943                lang="ada->c",
944                plist=profile.c_params(local_vars, internal_call)
945            ).import_c(cname)
946
947            # Should we transform the return value into a parameter ?
948
949            ret_as_param = gtkmethod.return_as_param()
950            if ret_as_param is not None:
951                profile.params.append(
952                    Parameter(name=ret_as_param,
953                              type=profile.returns, mode="out"))
954                profile.returns = None
955
956            # Is this a function that takes a callback parameter ?
957
958            cb = profile.callback_param_info()
959            if cb is not None:
960                if ret_as_param:
961                    # ??? We would need to change _callback_support to
962                    # have additional code to set the return value. One
963                    # issue is that the profile has already been changed
964                    raise Exception("Cannot bind function with callback"
965                                    + " and return value as parameter: %s"
966                                    % cname)
967
968                return self._callback_support(adaname, cname, profile, cb)
969
970            execute = internal.call(
971                in_pkg=self.pkg, extra_postcall="".join(internal_call))
972
973            if ret_as_param is not None:
974                assert execute[1] is not None, \
975                    "Must have a return value in %s => %s" % (cname, execute)
976                call = "%s%s := %s;" % (execute[0], ret_as_param, execute[1])
977
978            else:
979                if execute[1]:  # A function, with a standard "return"
980                    call = "%sreturn %s;" % (execute[0], execute[1])
981                else:
982                    call = execute[0]
983
984            local_vars += execute[2]
985
986        subp = profile.subprogram(name=adaname, showdoc=showdoc,
987                                  local_vars=local_vars, code=call)
988
989        if is_import:
990            subp.import_c(cname)
991        else:
992            subp.add_nested(internal)
993            if body:
994                subp.set_body("   " + body.strip() + "\n")
995
996        section.add(subp)
997        return subp
998
999    def _callback_support(self, adaname, cname, profile, cb):
1000        """Add support for a function with a callback parameter and user data.
1001           We generate multiple bindings for such a function:
1002           * One version that doesn't take a user_data. This looks like:
1003                type My_Callback is access function (Self, other_params);
1004                procedure Gtk_Func (Self : ...; Cb : My_Callback);
1005
1006             since My_Callback doesn't have exactly the same profile as
1007             required by gtk+, we in fact go through an intermediate function
1008             in the body, to which we pass, as user_data, a pointer to the
1009             user's callback:
1010
1011                 function Internal_Callback (same_profile_as_c, user_data) is
1012                    User_Func : My_Callback := convert (user_data);
1013                 begin
1014                    return User_Func (...);
1015                 end Internal_Callback;
1016                 pragma Convention (C, Internal_Callback);
1017
1018            * Ideally we want to generate a generic package to which users
1019              can pass their own user data type. We then need to generate the
1020              proper Destroy callback that C will call to free that user data.
1021
1022           :profile: is an instance of SubprogramProfile.
1023           :cname: is the name of the gtk+ C function.
1024           :adaname: is the name of the corresponding Ada function.
1025           :cb: is a list of Parameter instances representing the callback
1026              parameters.
1027        """
1028
1029        if len(cb) > 1:
1030            print "No binding for %s: multiple callback parameters" % cname
1031            return
1032        cb = cb[0]
1033
1034        def call_to_c(gtk_func, values):
1035            """Implement the call to the C function.
1036               If the user passes a null callback, we always want to pass null
1037               to C rather than passing our Internal_Callback'Address.
1038
1039               :param values: a dictionary of the parameters to pass to call().
1040               :return: the code for the Ada function's body
1041            """
1042
1043            values_if_null = copy.deepcopy(values)
1044            values_if_null[cb.name.lower()] = "System.Null_Address"
1045
1046            if user_data is not None:
1047                values_if_null[user_data.lower()] = "System.Null_Address"
1048
1049            exec1 = gtk_func.call(
1050                in_pkg=self.pkg,
1051                extra_postcall="".join(call), values=values_if_null)
1052
1053            call1 = gtk_func.call_to_string(exec1, lang="ada->c")
1054            if not call1.endswith(";"):
1055                call1 += ";"
1056
1057            exec2 = gtk_func.call(
1058                in_pkg=self.pkg,
1059                extra_postcall="".join(call), values=values)
1060
1061            call2 = gtk_func.call_to_string(exec2, lang="ada->c")
1062            if not call2.endswith(";"):
1063                call2 += ";"
1064
1065            return ("""if %s = null then
1066   %s
1067else
1068   %s
1069end if;""" % (cb.name, call1, call2), exec2[2])
1070
1071        cbname = cb.type.param
1072
1073        # Compute the name of the Ada type representing the user callback
1074
1075        cb_type_name = naming.type(name=cb.type.ada, cname=cbname).ada
1076        funcname = base_name(cb_type_name)
1077
1078        destroy = profile.find_param(destroy_data_params)
1079
1080        # Compute the profile of the callback (will all its arguments)
1081
1082        gtkmethod = self.gtkpkg.get_method(cname=cname)
1083
1084        try:
1085            cb_gir_node = self.gir.callbacks[cb.type.ada]
1086        except:
1087            raise Exception(
1088                "No GIR node for %s in callback %s" % (cb.type.ada, cname))
1089
1090        cbgtk = self.gtkpkg.get_method(cbname)
1091
1092        cb_profile = SubprogramProfile.parse(
1093            cb_gir_node, gtkmethod=cbgtk, pkg=self.pkg)
1094
1095        user_data = profile.callback_user_data()
1096        cb_user_data = cb_profile.find_param(user_data_params)
1097        if user_data is None and cb_user_data is not None:
1098            user_data = cb_user_data
1099
1100        # Generate the access-to-subprogram type for the user callback, unless
1101        # we have already done so. This is the type that doesn't receive
1102        # user data.
1103
1104        if cbname not in self.callbacks:
1105            self.callbacks.add(cbname)   # Prevent multiple generations
1106
1107            section = self.pkg.section("Callbacks")
1108
1109            if cb_user_data is None:
1110                print "callback has no user data: %s" % cbname
1111                # If the C function has no user data, we do not know how to
1112                # generate a high-level binding, since we cannot go through an
1113                # intermediate C function that transforms the parameters into
1114                # their Ada equivalent.
1115                #
1116                # Instead, we just generate a low-level C callback passing
1117                # System.Address for widgets.
1118
1119                nouser_cb_profile = copy.deepcopy(cb_profile)
1120                subp = nouser_cb_profile.subprogram(name="", lang="ada->c")
1121                section.add(
1122                    "\ntype %s is %s" % (funcname, subp.spec(pkg=self.pkg)))
1123                section.add(
1124                    "\npragma Convention (C, %s);" % funcname)
1125
1126            else:
1127                # Generate a simpler version of the callback, without
1128                # user data, that the Ada applications can use
1129
1130                nouser_cb_profile = copy.deepcopy(cb_profile)
1131                nouser_cb_profile.remove_param(
1132                    destroy_data_params + [cb_user_data])
1133                subp = nouser_cb_profile.subprogram(name="")
1134                section.add(
1135                    "\ntype %s is %s" % (funcname, subp.spec(pkg=self.pkg)))
1136
1137                # Generate a subprogram in the body to act as the C callback.
1138                # This subprogram is responsible for calling the user's
1139                # callback. In the call to the user's callback, we need to
1140                # convert the parameters from the C values to the
1141                # corresponding Ada values.
1142
1143                self.pkg.add_with(
1144                    "Ada.Unchecked_Conversion", do_use=False, specs=False)
1145                section.add(
1146                    ("function To_%s is new Ada.Unchecked_Conversion\n"
1147                     + "   (System.Address, %s);\n") % (funcname, funcname),
1148                    in_spec=False)
1149                section.add(
1150                    ("function To_Address is new Ada.Unchecked_Conversion\n"
1151                     + "   (%s, System.Address);\n") % (cb_type_name,),
1152                    in_spec=False)
1153
1154                ada_func = copy.deepcopy(subp)
1155
1156                if ada_func.plist:
1157                    ada_func.name = "Func"
1158                else:
1159                    ada_func.name = "Func.all"
1160
1161                ada_func_call = ada_func.call(in_pkg=self.pkg, lang="c->ada")
1162                body_cb = cb_profile.subprogram(
1163                    name="Internal_%s" % funcname,
1164                    local_vars=[Local_Var(
1165                        "Func", "constant %s" % funcname,
1166                        "To_%s (%s)" % (funcname, cb_user_data))]
1167                    + ada_func_call[2],
1168                    lang="c->ada",
1169                    code=ada_func.call_to_string(ada_func_call, lang="c->ada"))
1170                body_cb.convention = "C"
1171                body_cb.doc = []
1172                section.add(body_cb, in_spec=False)
1173
1174        # The gtk C function, will all parameters.
1175        # This will be used to generate the "Internal" nested subprogram.
1176
1177        local_vars = []
1178        call = []
1179        gtk_func_profile = copy.deepcopy(profile)
1180
1181        if cb is not None:
1182            gtk_func_profile.replace_param(cb.name, "System.Address")
1183
1184        if cb_user_data is not None:
1185            gtk_func_profile.replace_param(destroy, "System.Address")
1186
1187        gtk_func = gtk_func_profile.subprogram(
1188            name=naming.case("C_%s" % cname), lang="ada->c").import_c(cname)
1189
1190        # This function is shared both by the version without user_data and by
1191        # the generic package, so we need to put it directly in the package,
1192        # not a nested subprogram.
1193
1194        self.pkg.section("").add(gtk_func, in_spec=False)
1195
1196        # Create a version of the function without a user data.
1197
1198        section = self.pkg.section("Methods")
1199
1200        nouser_profile = copy.deepcopy(profile)
1201
1202        if user_data is None:
1203            values = {destroy: "System.Null_Address",
1204                      cb.name.lower(): "%s'Address" % cb.name}
1205        elif cb_user_data is None:
1206            values = {destroy: "System.Null_Address",
1207                      cb.name.lower(): "Internal_%s'Address" % funcname,
1208                      user_data.lower(): "%s'Address" % cb.name}
1209        else:
1210            nouser_profile.remove_param(destroy_data_params + [user_data])
1211            values = {destroy: "System.Null_Address",
1212                      cb.name.lower(): "Internal_%s'Address" % funcname,
1213                      user_data.lower(): "To_Address (%s)" % cb.name}
1214
1215        c_call = call_to_c(gtk_func, values)
1216
1217        subp = nouser_profile.subprogram(
1218            name=adaname, local_vars=c_call[1],
1219            code=c_call[0])
1220        section.add(subp)
1221
1222        # Now create a generic package that will provide access to
1223        # user_data. The function can no longer be a primitive operation of the
1224        # object, since it is in a nested package.
1225        # It is possible that the function doesn't accept a user data in fact
1226        # (for instance when scope="async"). In this case, no need for a
1227        # generic package.
1228
1229        user_data2 = cb_profile.find_param(user_data_params)
1230
1231        if user_data2 is not None:
1232            self.pkg.add_with("Glib.Object", do_use=False, specs=False)
1233
1234            pkg2 = Package(name="%s_User_Data" % adaname)
1235            section.add(pkg2)
1236            pkg2.formal_params = """type User_Data_Type (<>) is private;
1237      with procedure Destroy (Data : in out User_Data_Type) is null;"""
1238
1239            sect2 = pkg2.section("")
1240            sect2.add("""package Users is new Glib.Object.User_Data_Closure
1241         (User_Data_Type, Destroy);""", in_spec=False)
1242
1243            sect2.add(
1244                ("function To_%s is new Ada.Unchecked_Conversion\n"
1245                 + "   (System.Address, %s);\n") % (funcname, funcname),
1246                in_spec=False)
1247            sect2.add(
1248                ("function To_Address is new Ada.Unchecked_Conversion\n"
1249                 + "   (%s, System.Address);\n") % (funcname,),
1250                in_spec=False)
1251
1252            cb_profile2 = copy.deepcopy(cb_profile)
1253            cb_profile2.replace_param(user_data2, "User_Data_Type")
1254            cb2 = cb_profile2.subprogram(name="")
1255            sect2.add(
1256                "\ntype %s is %s" % (funcname, cb2.spec(pkg=pkg2)))
1257
1258            values = {user_data2.lower(): "D.Data.all"}
1259            user_cb = cb_profile2.subprogram(name="To_%s (D.Func)" % funcname)
1260            user_cb_call = user_cb.call(
1261                in_pkg=self.pkg,
1262                lang="c->ada",
1263                extra_postcall="".join(call), values=values)
1264
1265            internal_cb = cb_profile.subprogram(
1266                name="Internal_Cb",
1267                local_vars=[
1268                    Local_Var("D", "constant Users.Internal_Data_Access",
1269                              "Users.Convert (%s)" % user_data2)]
1270                + user_cb_call[2],
1271                convention="C",
1272                lang="c->ada",
1273                code=user_cb.call_to_string(user_cb_call, lang="c->ada"))
1274            sect2.add(internal_cb, in_spec=False)
1275
1276            values = {destroy: "Users.Free_Data'Address",
1277                      cb.name.lower(): "%s'Address" % internal_cb.name,
1278                      user_data.lower():
1279                          "Users.Build (To_Address (%s), %s)" % (
1280                          cb.name, user_data)}
1281
1282            full_profile = copy.deepcopy(profile)
1283            full_profile.set_class_wide()
1284            full_profile.remove_param(destroy_data_params)
1285            full_profile.replace_param(cb.name, funcname)
1286            full_profile.replace_param(user_data, "User_Data_Type")
1287            c_call = call_to_c(gtk_func, values)
1288            subp2 = full_profile.subprogram(
1289                name=adaname, local_vars=c_call[1],
1290                code=c_call[0])
1291            sect2.add(subp2)
1292
1293        return subp
1294
1295    def _constructors(self):
1296        n = QName(uri, "constructor").text
1297        for c in self.node.findall(n):
1298            cname = c.get(cidentifier)
1299            gtkmethod = self.gtkpkg.get_method(cname=cname)
1300            if not gtkmethod.bind():
1301                naming.add_cmethod(
1302                    cname, gtkmethod.ada_name() or cname)  # Avoid warning
1303                continue
1304
1305            profile = SubprogramProfile.parse(
1306                node=c, gtkmethod=gtkmethod, pkg=self.pkg,
1307                ignore_return=True)
1308            if profile.has_varargs() \
1309                    and gtkmethod.get_param("varargs").node is None:
1310
1311                naming.add_cmethod(cname, cname)  # Avoid warning later on.
1312                print "No binding for %s: varargs" % cname
1313                continue
1314
1315            self._handle_constructor(
1316                c, gtkmethod=gtkmethod, cname=cname, profile=profile)
1317
1318    def _handle_constructor(self, c, cname, gtkmethod, profile=None):
1319        assert(profile is None or isinstance(profile, SubprogramProfile))
1320
1321        section = self.pkg.section("Constructors")
1322        name = c.get("name").title()
1323
1324        assert profile.params is not None, "No profile defined for %s" % cname
1325
1326        format_params = ", ".join(p.name for p in profile.params)
1327        if format_params:
1328            self._subst["internal_params"] = " (%s)" % format_params
1329            format_params = ", " + format_params
1330            self._subst["params"] = format_params
1331        else:
1332            self._subst["params"] = ""
1333            self._subst["internal_params"] = ""
1334
1335        if self.is_gobject or self.is_boxed:
1336            profile.returns = AdaType(
1337                "System.Address", pkg=self.pkg, in_spec=False)
1338        else:
1339            profile.returns = AdaType(
1340                "%(typename)s" % self._subst,
1341                pkg=self.pkg, in_spec=False)
1342
1343        local_vars = []
1344        code = []
1345        internal = Subprogram(
1346            name="Internal",
1347            lang="ada->c",
1348            plist=profile.c_params(local_vars, code),
1349            returns=profile.returns).import_c(cname)
1350
1351        call = internal.call(in_pkg=self.pkg)
1352        assert(call[1] is not None)   # A function
1353
1354        gtk_new_prefix = "Gtk_New"
1355
1356        adaname = gtkmethod.ada_name()
1357        if not adaname:
1358            if cname.startswith("gdk_") or cname.startswith("pango_"):
1359                gtk_new_prefix = "Gdk_New"
1360                adaname = "Gdk_%s" % name    # e.g.  Gdk_New
1361            elif cname.startswith("g_"):
1362                gtk_new_prefix = "G_New"
1363                adaname = "G_%s" % name      # e.g.  G_New
1364            else:
1365                adaname = "Gtk_%s" % name    # e.g.  Gtk_New
1366
1367        selfname = gtkmethod.get_param("self").ada_name() or "Self"
1368
1369        if self.is_gobject:
1370            selftype = "%(typename)s_Record'Class" % self._subst
1371        else:
1372            selftype = "%(typename)s" % self._subst
1373
1374        if self.is_gobject:
1375            filtered_params = [p for p in profile.params if p.ada_binding]
1376
1377            initialize_params = [Parameter(
1378                name=selfname,
1379                type=AdaType(selftype, pkg=self.pkg, in_spec=True),
1380                mode="not null access")] + filtered_params
1381            initialize = Subprogram(
1382                name=adaname.replace(
1383                    gtk_new_prefix, "%s.Initialize" % self.pkg.name),
1384                plist=initialize_params,
1385                local_vars=local_vars + call[2],
1386                doc=profile.doc,
1387                code="if not %s.Is_Created then %sSet_Object (%s, %s); end if" % (
1388                    selfname, call[0], selfname, call[1]),
1389            ).add_nested(internal)
1390
1391            call = initialize.call(in_pkg=self.pkg)
1392            assert(call[1] is None)  # This is a procedure
1393
1394            naming.add_cmethod(cname, "%s.%s" % (self.pkg.name, adaname))
1395            gtk_new = Subprogram(
1396                name=adaname,
1397                plist=[Parameter(
1398                    name=selfname,
1399                    type=AdaType("%(typename)s" % self._subst,
1400                                 pkg=self.pkg, in_spec=True),
1401                    mode="out")] + filtered_params,
1402                local_vars=call[2],
1403                code=selfname + " := new %(typename)s_Record;" % self._subst
1404                + call[0],
1405                doc=profile.doc)
1406
1407            section.add(gtk_new)
1408            section.add(initialize)
1409
1410            # Gtk_New as a function
1411            gtk_new = Subprogram(
1412                name="%s_%s" % (self._subst["typename"], name),
1413                returns=AdaType("%(typename)s" % self._subst,
1414                                pkg=self.pkg, in_spec=True),
1415                plist=filtered_params,
1416                local_vars=call[2] +
1417                [Local_Var(selfname,
1418                           "constant %(typename)s" % self._subst,
1419                           "new %(typename)s_Record" % self._subst)],
1420                code=call[0] + "return %s;" % selfname,
1421                doc=profile.doc)
1422            section.add(gtk_new)
1423
1424        elif self.is_boxed:
1425            gtk_new = Subprogram(
1426                name=adaname,
1427                plist=[Parameter(
1428                    name=selfname,
1429                    type=AdaType("%(typename)s" % self._subst,
1430                                 pkg=self.pkg, in_spec=True),
1431                    mode="out")] + profile.params,
1432                local_vars=local_vars + call[2],
1433                code="%s%s.Set_Object (%s)" % (call[0], selfname, call[1]),
1434                doc=profile.doc)
1435
1436            gtk_new.add_nested(internal)
1437            section.add(gtk_new)
1438
1439            # Now as a function
1440            gtk_new = Subprogram(
1441                name="%s_%s" % (self._subst["typename"], name),
1442                returns=AdaType("%(typename)s" % self._subst,
1443                                pkg=self.pkg, in_spec=True),
1444                plist=profile.params,
1445                local_vars=local_vars + call[2] +
1446                [Local_Var(selfname,
1447                           "%(typename)s" % self._subst)],
1448                code="%s%s.Set_Object (%s); return %s" % (
1449                    call[0], selfname, call[1], selfname),
1450                doc=profile.doc)
1451            gtk_new.add_nested(internal)
1452            section.add(gtk_new)
1453
1454        else:
1455            # likely a Proxy
1456            gtk_new = Subprogram(
1457                name=adaname,
1458                plist=[Parameter(
1459                    name=selfname,
1460                    type=AdaType("%(typename)s" % self._subst,
1461                                 pkg=self.pkg, in_spec=True),
1462                    mode="out")] + profile.params,
1463                local_vars=local_vars + call[2],
1464                code="%s%s := %s" % (call[0], selfname, call[1]),
1465                doc=profile.doc)
1466            gtk_new.add_nested(internal)
1467            section.add(gtk_new)
1468
1469            # Now as a function
1470            gtk_new = Subprogram(
1471                name="%s_%s" % (self._subst["typename"], name),
1472                returns=AdaType("%(typename)s" % self._subst,
1473                                pkg=self.pkg, in_spec=True),
1474                plist=profile.params,
1475                local_vars=local_vars + call[2] +
1476                [Local_Var(selfname,
1477                           "%(typename)s" % self._subst)],
1478                code="%s%s := %s; return %s;" % (
1479                    call[0], selfname, call[1], selfname),
1480                doc=profile.doc)
1481            gtk_new.add_nested(internal)
1482            section.add(gtk_new)
1483
1484    def _methods(self):
1485        all = self.node.findall(nmethod)
1486        if all is not None:
1487            section = self.pkg.section("Methods")
1488            for c in all:
1489                self._handle_function(section, c, ismethod=True)
1490
1491    def _functions(self):
1492        all = self.node.findall(nfunction)
1493        if all is not None:
1494            section = self.pkg.section("Functions")
1495            for c in all:
1496                self._handle_function(section, c)
1497
1498    def _virtual_methods(self):
1499        all = self.node.findall(nvirtualmethod)
1500        has_iface = False
1501
1502        if all is not None:
1503            ifacename = base_name(self.name)
1504            info = ''
1505
1506            for c in all:
1507                if not self.gtkpkg.bind_virtual_method(
1508                   c.get('name'), default=self.is_interface):
1509                    continue
1510
1511                gtkmethod = self.gtkpkg.get_method(cname=c.get('name'))
1512                basename = gtkmethod.ada_name() or c.get('name').title()
1513                adaname = "Virtual_%s" % basename
1514
1515                if not has_iface:
1516                    has_iface = True
1517                    section = self.pkg.section("Virtual Methods")
1518
1519                info += 'procedure Set_%s\n' % basename
1520
1521                if self.is_interface:
1522                    info += '   (Self    : %s_Interface_Descr;\n' % ifacename
1523                else:
1524                    info += '   (Self    : Glib.Object.GObject_Class;\n'
1525
1526                info += '    Handler : %s);\n' % adaname
1527                info += 'pragma Import (C, Set_%s, "gtkada_%s_set_%s");\n' % (
1528                    basename, ifacename, basename.lower())
1529
1530                c_iface = '%s%s' % (
1531                    self.identifier_prefix,
1532                    self.node.get(glib_type_struct))
1533
1534                self.gir.ccode += """
1535void gtkada_%s_set_%s(%s* iface, %s* handler) {
1536    iface->%s = handler;
1537}""" % (ifacename, basename.lower(),
1538                    c_iface,
1539                    'void',
1540                    c.get('name'))
1541
1542                profile = SubprogramProfile.parse(
1543                    node=c,
1544                    gtkmethod=gtkmethod,
1545                    pkg=self.pkg)
1546                self._add_self_param(
1547                    adaname=adaname, node=c, gtkmethod=gtkmethod, profile=profile,
1548                    inherited=False)
1549                subp = profile.subprogram(
1550                    name=adaname,
1551                    lang="ada->c",
1552                    convention="C",
1553                    showdoc=True)
1554                section.add(
1555                    '\ntype %s is %s' % (
1556                        adaname,
1557                        subp.spec(pkg=self.pkg, as_type=True)))
1558                subp.add_withs_for_subprogram(pkg=self.pkg, in_specs=True)
1559
1560        if has_iface:
1561            info = ('subtype %s_Interface_Descr is ' % ifacename
1562                    + 'Glib.Object.Interface_Description;\n'
1563                    + info
1564                    + '--  See Glib.Object.Add_Interface\n')
1565            section.add(info)
1566            self.pkg.add_with('Glib.Object')
1567
1568    def _globals(self):
1569        funcs = self.gtkpkg.get_global_functions()  # List of binding.xml nodes
1570        if funcs:
1571            section = self.pkg.section("Functions")  # Make sure section exists
1572            for f in funcs:
1573                c = self.gir.globals.get_function(
1574                    f.cname())  # Node in gir file
1575                self._handle_function(section, c, gtkmethod=f)
1576
1577    def _method_get_type(self):
1578        """Generate the Get_Type subprogram"""
1579
1580        n = self.node.get(ggettype)
1581        if n is not None:
1582            section = self.pkg.section("Constructors")
1583
1584            gtkmethod = self.gtkpkg.get_method(cname=n)
1585            if not gtkmethod.bind():
1586                return
1587
1588            self.pkg.add_with("Glib")
1589            get_type_name = gtkmethod.ada_name() or "Get_Type"
1590            section.add(
1591                Subprogram(
1592                    name=get_type_name,
1593                    returns=AdaType("Glib.GType", pkg=self.pkg, in_spec=True))
1594                .import_c(n))
1595
1596            if not self.gtktype.is_subtype() \
1597                    and not self.is_interface \
1598                    and self.is_gobject \
1599                    and self._subst["parent"] is not None:
1600
1601                self.pkg.add_with("Glib.Type_Conversion_Hooks", specs=False)
1602
1603                self._subst["get_type"] = get_type_name
1604
1605                section.add(
1606                    ("package Type_Conversion_%(typename)s is new"
1607                     + " Glib.Type_Conversion_Hooks.Hook_Registrator\n"
1608                     + "   (%(get_type)s'Access, %(typename)s_Record);\n"
1609                     + "pragma Unreferenced (Type_Conversion_%(typename)s);""")
1610                    % self._subst, in_spec=False)
1611
1612    def _get_c_type(self, node):
1613        t = node.find(ntype)
1614        if t is not None:
1615            return t.get(ctype_qname)
1616        return None
1617
1618    def _fields(self):
1619        fields = self.node.findall(nfield)
1620        if fields:
1621            section = self.pkg.section("Fields")
1622            for f in fields:
1623                name = f.get("name")
1624
1625                # Getter
1626
1627                if f.get("readable", "1") != "0":
1628                    cname = "gtkada_%(cname)s_get_%(name)s" % {
1629                        "cname": self._subst["cname"], "name": name}
1630                    gtkmethod = self.gtkpkg.get_method(cname=cname)
1631                    if gtkmethod.bind(default="false"):
1632                        profile = SubprogramProfile.parse(
1633                            node=f, gtkmethod=gtkmethod, pkg=self.pkg)
1634                        func = self._handle_function_internal(
1635                            section,
1636                            node=f,
1637                            cname=cname,
1638                            adaname="Get_%s" % name,
1639                            ismethod=True,
1640                            profile=profile,
1641                            gtkmethod=gtkmethod)
1642
1643                        if func is not None:
1644                            ctype = self._get_c_type(f)
1645                            if ctype is None:
1646                                continue
1647
1648                            self.gir.ccode += """
1649%(ctype)s %(cname)s (%(self)s* self) {
1650    return self->%(name)s;
1651}
1652""" % {"ctype": ctype, "cname": cname, "self": self.ctype, "name": name}
1653
1654                # Setter
1655
1656                if f.get("writable", "1") != "0":
1657                    cname = "gtkada_%(cname)s_set_%(name)s" % {
1658                        "cname": self._subst["cname"], "name": name}
1659                    gtkmethod = self.gtkpkg.get_method(cname=cname)
1660                    if gtkmethod.bind("false"):
1661                        profile = SubprogramProfile.setter(
1662                            node=f, pkg=self.pkg)
1663                        func = self._handle_function_internal(
1664                            section,
1665                            node=f,
1666                            cname=cname,
1667                            adaname="Set_%s" % name,
1668                            ismethod=True,
1669                            gtkmethod=gtkmethod,
1670                            profile=profile)
1671
1672                        if func is not None:
1673                            ctype = self._get_c_type(f)
1674                            if ctype is None:
1675                                continue
1676
1677                            self.gir.ccode += """
1678void %(cname)s (%(self)s* self, %(ctype)s val) {
1679    self->%(name)s = val;
1680}
1681""" % {"ctype": ctype, "cname": cname, "self": self.ctype, "name": name}
1682
1683    def _properties(self):
1684        n = QName(uri, "property")
1685
1686        props = list(self.node.findall(n.text))
1687        if props is not None:
1688            adaprops = []
1689            for p in props:
1690                flags = []
1691                if p.get("readable", "1") != "0":
1692                    flags.append("read")
1693                if p.get("writable", "1") != "0":
1694                    flags.append("write")
1695
1696                # Do not provide a "pkg=self.pkg" parameter, since we do
1697                # not want to generate a with for the actual property type
1698                # (for instance a Gtk_Cell_Area), just for the actual type
1699                # (Property_Object).
1700
1701                tp = _get_type(p)
1702                tp.userecord = False
1703                ptype = tp.as_property()
1704                if ptype:
1705                    pkg = ptype[:ptype.rfind(".")]
1706                    if pkg:
1707                        self.pkg.add_with(pkg)
1708                else:
1709                    section = self.pkg.section("Properties")
1710                    section.add(
1711                        ('   %(name)s_Property : constant '
1712                         + 'Glib.Properties.Property_String :=\n'
1713                         + '      Glib.Properties.Build ("%(cname)s");'
1714                         + '  --  Unknown type: %(type)s') % {
1715                            "name": naming.case(p.get("name")),
1716                            "type": (p.find(ntype).get("name")
1717                                     if p.find(ntype) is not None
1718                                     else "unspecified"),
1719                            "cname": p.get("name")})
1720                    self.pkg.add_with("Glib.Properties")
1721                    continue
1722
1723                adaprops.append({
1724                    "cname": p.get("name"),
1725                    "name": naming.case(p.get("name")),
1726                    "flags": "-".join(flags),
1727                    "doc": _get_clean_doc(p),
1728                    "pkg": pkg,
1729                    "ptype": ptype,
1730                    "type": tp.as_ada_param(self.pkg)})
1731
1732            if adaprops:
1733                section = self.pkg.section("Properties")
1734                section.add_comment(
1735                    """The following properties are defined for this widget.
1736See Glib.Properties for more information on properties)""")
1737
1738                adaprops.sort(lambda x, y: cmp(x["name"], y["name"]))
1739
1740                for p in adaprops:
1741                    prop_str = '   %(name)s_Property : constant %(ptype)s;' % p
1742                    if not section.add(prop_str):
1743                        continue
1744
1745                    # Only display the type if it isn't obvious from the actual
1746                    # type of the property.
1747                    if p["type"] not in ("Boolean", "UTF8_String", "Gfloat",
1748                                         "Gint", "Guint") \
1749                       and not p["type"].startswith("Gtk.Enums."):
1750                        section.add(
1751                            Code("Type:  %(type)s" % p, iscomment=True))
1752
1753                    if p["flags"] != "read-write":
1754                        section.add(
1755                            Code("Flags: %(flags)s" % p, iscomment=True))
1756                    if p["doc"]:
1757                        section.add(Code("%s" % p["doc"], iscomment=True))
1758
1759                    d = '   %(name)s_Property : constant %(ptype)s' % p
1760                    self.pkg.add_private(
1761                        d + ' :=\n     %(pkg)s.Build ("%(cname)s");' % p)
1762
1763    def _compute_marshaller_suffix(self, selftype, profile):
1764        """Computes the suffix for the connect and marshallers types based on
1765           the profile of the signal.
1766        """
1767        return "_".join(
1768            [base_name(selftype.ada)]
1769            + [base_name(p.type.ada) for p in profile.params]
1770            + [(base_name(profile.returns.ada)
1771                if profile.returns else "Void")])
1772
1773    def _marshall_gvalue(self, profile):
1774        """Return the arguments to parse to an Ada callback, after extracting
1775           them from a GValue. Returns a list of local variables for the
1776           marshaller, and its body
1777        """
1778        call_params = []
1779        for index, p in enumerate(profile.params):
1780            if isinstance(p.type, Tagged):
1781                call_params.append(
1782                    "%s.From_Object (Unchecked_To_Address (Params, %d))" %
1783                    (package_name(p.type.ada), index + 1))
1784            elif isinstance(p.type, Interface):
1785                call_params.append(
1786                    "%s (Unchecked_To_Interface (Params, %d))" %
1787                    (p.type.ada, index + 1))
1788            elif isinstance(p.type, GObject):
1789                if p.type.ada != "Glib.Object.GObject":
1790                    call_params.append(
1791                        "%s (Unchecked_To_Object (Params, %d))" % (
1792                            p.type.ada, index + 1))
1793                else:
1794                    call_params.append(
1795                        "Unchecked_To_Object (Params, %d)" % (index + 1, ))
1796            else:
1797                if p.mode != "in":
1798                    call_params.append(
1799                        "Unchecked_To_%s_Access (Params, %d)" % (
1800                            base_name(p.type.ada), index + 1))
1801                else:
1802                    call_params.append(
1803                        "Unchecked_To_%s (Params, %d)" % (
1804                            base_name(p.type.ada), index + 1))
1805
1806        if call_params:
1807            call = "H (Obj, %s)" % ", ".join(call_params)
1808        else:
1809            call = "H (Obj)"
1810
1811        if profile.returns:
1812            marsh_local = [
1813                Local_Var("V", profile.returns, aliased=True, default=call)]
1814            marsh_body = "Set_Value (Return_Value, V'Address);"
1815        else:
1816            marsh_local = []
1817            marsh_body = "%s;" % call
1818
1819        marsh_body += "exception when E : others => Process_Exception (E);"
1820
1821        return marsh_local, marsh_body
1822
1823    def _generate_slot_marshaller(self, section, selftype, node, gtkmethod):
1824        """Generate connect+marshaller when connect takes a slot object. These
1825           procedure are independent of the specific widget, and can be shared.
1826           Returns the name for the hander type.
1827        """
1828
1829        if SHARED_SLOT_MARSHALLERS:
1830            pkg = gir.slot_marshaller_pkg
1831            section = gir.slot_marshaller_section
1832            existing_marshallers = gir.slot_marshallers
1833        else:
1834            pkg = self.pkg
1835            section = section
1836            existing_marshallers = self.__marshallers
1837
1838        profile = SubprogramProfile.parse(
1839            node=node, gtkmethod=gtkmethod, pkg=pkg)
1840
1841        callback_selftype = GObject(
1842            "Glib.Object.GObject", classwide=True, allow_none=True)
1843
1844        name_suffix = self._compute_marshaller_suffix(
1845            callback_selftype, profile)
1846        slot_name = "Cb_%s" % name_suffix
1847        marshname = "Marsh_%s" % name_suffix
1848
1849        callback = Subprogram(
1850            name="",
1851            plist=[Parameter(name="Self", type=callback_selftype)]
1852            + profile.params,
1853            code="null",
1854            allow_none=False,
1855            returns=profile.returns)
1856
1857        if slot_name not in existing_marshallers:
1858            existing_marshallers.add(slot_name)
1859
1860            slot_handler_type = "type %s is %s;" % (
1861                slot_name, callback.profile(
1862                    pkg=pkg,
1863                    maxlen=69, indent="      "))
1864            section.add(Code(slot_handler_type), in_spec=True)
1865
1866            section.add(Code(
1867                """function Cb_To_Address is new Ada.Unchecked_Conversion
1868   (%s, System.Address);
1869function Address_To_Cb is new Ada.Unchecked_Conversion
1870   (System.Address, %s);
1871""" % (slot_name, slot_name)),
1872                in_spec=False)
1873
1874            if isinstance(selftype, Interface):
1875                obj_in_body = "Glib.Types.GType_Interface (Object)"
1876            else:
1877                obj_in_body = "Object"
1878
1879            connect_slot_body = """
1880      Unchecked_Do_Signal_Connect
1881        (Object      => %s,
1882         C_Name      => C_Name,
1883         Marshaller  => %s'Access,
1884         Handler     => Cb_To_Address (Handler),  --  Set in the closure
1885         Slot_Object => Slot,
1886         After       => After)""" % (obj_in_body, marshname)
1887
1888            marsh_local, marsh_body = self._marshall_gvalue(profile)
1889
1890            connect_slot = Subprogram(
1891                name="Connect_Slot",
1892                plist=[Parameter("Object", selftype),
1893                       Parameter("C_Name", "Glib.Signal_Name"),
1894                       Parameter("Handler", slot_name),
1895                       Parameter("After", "Boolean"),
1896                       Parameter("Slot", GObject(
1897                           "Glib.Object.GObject", allow_none=True,
1898                           classwide=True), default="null")
1899                       ],
1900                code=connect_slot_body)
1901            section.add(connect_slot, in_spec=False)
1902
1903            addr_to_obj = "Glib.Object.Convert (Get_Data (Closure))"
1904
1905            marsh = Subprogram(
1906                name=marshname,
1907                plist=[Parameter("Closure", "GClosure"),
1908                       Parameter("Return_Value", "Glib.Values.GValue"),
1909                       Parameter("N_Params", "Glib.Guint"),
1910                       Parameter("Params", "Glib.Values.C_GValues"),
1911                       Parameter("Invocation_Hint", "System.Address"),
1912                       Parameter("User_Data", "System.Address")],
1913                local_vars=[
1914                    Local_Var("H", "constant %s" % slot_name,
1915                              "Address_To_Cb (Get_Callback (Closure))"),
1916                    Local_Var("Obj", "Glib.Object.GObject", constant=True,
1917                              default=addr_to_obj)
1918                ] + marsh_local,
1919                convention="C",
1920                code=marsh_body)
1921            section.add(marsh, in_spec=False)
1922
1923        return slot_name, callback
1924
1925    def _generate_marshaller(self, section, selftype, node, gtkmethod):
1926        """Generate, if needed, a connect+marshaller for signals with this
1927           profile.
1928           Returns the name of the type that contains the subprogram profile
1929        """
1930
1931        profile = SubprogramProfile.parse(
1932            node=node, gtkmethod=gtkmethod,
1933            pkg=self.pkg if gtkmethod.bind() else None)
1934
1935        name_suffix = self._compute_marshaller_suffix(selftype, profile)
1936        marshname = "Marsh_%s" % name_suffix
1937        name = "Cb_%s" % name_suffix
1938
1939        callback = Subprogram(
1940            name="",
1941            plist=[Parameter(name="Self", type=selftype)] + profile.params,
1942            code="null",
1943            allow_none=False,
1944            returns=profile.returns)
1945
1946        if gtkmethod.bind() and name not in self.__marshallers:
1947            self.__marshallers.add(name)
1948
1949            handler_type = "type %s is %s;" % (
1950                name, callback.profile(
1951                    pkg=self.pkg, maxlen=69, indent="      "))
1952            section.add(Code(handler_type), in_spec=True)
1953
1954            section.add(Code(
1955                """function Cb_To_Address is new Ada.Unchecked_Conversion
1956   (%s, System.Address);
1957function Address_To_Cb is new Ada.Unchecked_Conversion
1958   (System.Address, %s);
1959""" % (name, name)),
1960                in_spec=False)
1961
1962            if isinstance(selftype, Interface):
1963                obj_in_body = "Glib.Types.GType_Interface (Object)"
1964            else:
1965                obj_in_body = "Object"
1966
1967            connect_body = """
1968      Unchecked_Do_Signal_Connect
1969        (Object      => %s,
1970         C_Name      => C_Name,
1971         Marshaller  => %s'Access,
1972         Handler     => Cb_To_Address (Handler),  --  Set in the closure
1973         After       => After)""" % (obj_in_body, marshname)
1974
1975            marsh_local, marsh_body = self._marshall_gvalue(profile)
1976
1977            connect = Subprogram(
1978                name="Connect",
1979                plist=[Parameter("Object", selftype),
1980                       Parameter("C_Name", "Glib.Signal_Name"),
1981                       Parameter("Handler", name),
1982                       Parameter("After", "Boolean"),
1983                       ],
1984                code=connect_body)
1985            section.add(connect, in_spec=False)
1986
1987            if isinstance(selftype, Interface):
1988                addr_to_obj = \
1989                    "%s (Unchecked_To_Interface (Params, 0))" % selftype.ada
1990            else:
1991                addr_to_obj = \
1992                    "%s (Unchecked_To_Object (Params, 0))" % selftype.ada
1993
1994            marsh = Subprogram(
1995                name=marshname,
1996                plist=[Parameter("Closure", "GClosure"),
1997                       Parameter("Return_Value", "Glib.Values.GValue"),
1998                       Parameter("N_Params", "Glib.Guint"),
1999                       Parameter("Params", "Glib.Values.C_GValues"),
2000                       Parameter("Invocation_Hint", "System.Address"),
2001                       Parameter("User_Data", "System.Address")],
2002                local_vars=[
2003                    Local_Var("H", "constant %s" % name,
2004                              "Address_To_Cb (Get_Callback (Closure))"),
2005                    Local_Var("Obj", selftype.ada, constant=True,
2006                              default=addr_to_obj)
2007                ] + marsh_local,
2008                convention="C",
2009                code=marsh_body)
2010            section.add(marsh, in_spec=False)
2011
2012        return name, callback, profile
2013
2014    def _signals(self):
2015        signals = list(self.node.findall(gsignal))
2016        if signals:
2017            adasignals = []
2018            section = self.pkg.section("Signals")
2019            section.sort_objects = False  # preserve insertion order
2020
2021            # If at least one signal gets a On_* procedure
2022            for s in signals:
2023                if self.gtkpkg.get_method(
2024                   cname="::%s" % s.get("name")).bind():
2025                    section.add(
2026                        Code("use type System.Address;"), in_spec=False)
2027                    self.pkg.add_with("Gtkada.Bindings", specs=False)
2028                    self.pkg.add_with("Glib.Values", specs=False)
2029                    self.pkg.add_with("Gtk.Arguments", specs=False)
2030
2031                    if SHARED_SLOT_MARSHALLERS:
2032                        self.pkg.add_with("Gtkada.Marshallers")
2033                    self.pkg.add_with(
2034                        "Ada.Unchecked_Conversion", specs=False, do_use=False)
2035                    break
2036
2037            signals.sort(key=lambda x: x.get("name"))
2038
2039            for s in signals:
2040                gtkmethod = self.gtkpkg.get_method(
2041                    cname="::%s" % (s.get("name")))
2042                bind = gtkmethod.bind()
2043
2044                name = s.get("name")
2045
2046                if self.is_gobject:
2047                    selftype = GObject("%(typename)s" % self._subst,
2048                                       allow_none=True, classwide=True)
2049                    on_selftype = GObject("%(typename)s" % self._subst,
2050                                          allow_none=False, classwide=False)
2051                elif self.is_interface:
2052                    on_selftype = selftype = Interface(
2053                        "%(typename)s" % self._subst)
2054                else:
2055                    on_selftype = selftype = Proxy(
2056                        "%(typename)s" % self._subst)
2057
2058                # We need to parse the profile twice, so that the with
2059                # statements are set both in self.pkg and in
2060                # gtkada.marshallers
2061                handler_type_name, sub, profile = \
2062                    self._generate_marshaller(
2063                        section, selftype, node=s, gtkmethod=gtkmethod)
2064
2065                if bind:
2066                    slot_handler_type_name, obj_sub = \
2067                        self._generate_slot_marshaller(
2068                            section, selftype, node=s, gtkmethod=gtkmethod)
2069
2070                section.add(
2071                    Code('   Signal_%s : constant Glib.Signal_Name := "%s";' %
2072                         (naming.case(name, protect=False), name)),
2073                    add_newline=False)
2074
2075                if bind:
2076                    connect = Subprogram(
2077                        name="On_%s" % naming.case(name, protect=False),
2078                        plist=[Parameter(name="Self", type=on_selftype),
2079                               Parameter(
2080                            name="Call",
2081                            type=Proxy(handler_type_name)),
2082                            Parameter(
2083                            name="After",
2084                            type="Boolean",
2085                            default="False")],
2086                        code='Connect (Self, "%s" & ASCII.NUL, Call, After);' %
2087                        name)
2088                    section.add(connect, add_newline=False)
2089
2090                    self.pkg.add_with("Glib.Object")
2091                    obj_connect = Subprogram(
2092                        name="On_%s" % naming.case(name, protect=False),
2093                        plist=[Parameter(name="Self", type=on_selftype),
2094                               Parameter(
2095                            name="Call",
2096                            type=Proxy(slot_handler_type_name)),
2097                            Parameter(
2098                            name="Slot",
2099                            type=GObject("Glib.Object.GObject",
2100                                         allow_none=False,
2101                                         classwide=True)),
2102                            Parameter(
2103                            name="After",
2104                            type="Boolean",
2105                            default="False")],
2106                        code=('Connect_Slot (Self, "%s" & ASCII.NUL,'
2107                              + ' Call, After, Slot);') % name)
2108                    section.add(obj_connect)
2109
2110                doc = _get_clean_doc(s)
2111                if doc:
2112                    section.add(Code("  %s""" % doc, iscomment=True))
2113
2114                if not bind:
2115                    sub.name = "Handler"
2116                    section.add(
2117                        Code(
2118                            sub.profile(pkg=self.pkg, maxlen=69),
2119                            fill=False, iscomment=True))
2120
2121                if profile.returns_doc or len(profile.params) > 1:
2122                    doc = "\n Callback parameters:" + sub.formatted_doc()
2123                    if profile.returns_doc:
2124                        doc += "\n   --  %s" % profile.returns_doc
2125                    section.add(Code(doc, fill=False, iscomment=True))
2126
2127    def _implements(self):
2128        """Bind the interfaces that a class implements"""
2129
2130        implements = list(self.node.findall(nimplements)) or []
2131
2132        for impl in implements:
2133            name = impl.get("name")
2134
2135            # Special case, because the GIR file are inconsistent
2136            if name == "Gio.Icon":
2137                name = "Icon"
2138
2139            # If the interface is purposefully not bound
2140            if "--%s" % name in interfaces:
2141                continue
2142
2143            try:
2144                intf = self.gir.interfaces[name]
2145            except KeyError:
2146                intf = self.gir.interfaces[naming.girname_to_ctype[name]]
2147
2148            type = naming.type(intf.ctype)
2149            if "." in type.ada:
2150                self.pkg.add_with(type.ada[:type.ada.rfind(".")])
2151                self.pkg.add_with("Glib.Types")
2152
2153            impl = dict(
2154                name=name,
2155                adatype=base_name(type.ada),
2156                impl=type.ada,
2157                interface=intf,
2158                body="",
2159                pkg="%(typename)s" % self._subst)
2160            impl["code"] = \
2161                """package Implements_%(adatype)s is new Glib.Types.Implements
2162       (%(impl)s, %(pkg)s_Record, %(pkg)s);
2163   function "+"
2164      (Widget : access %(pkg)s_Record'Class)
2165      return %(impl)s
2166      renames Implements_%(adatype)s.To_Interface;
2167   function "-"
2168      (Interf : %(impl)s)
2169      return %(pkg)s
2170      renames Implements_%(adatype)s.To_Object;
2171""" % impl
2172
2173            self.implements[name] = impl
2174
2175        # For an interface, we also define "+" to cast to itself. This is used
2176        # when writting custom bodies for the methods of the interface, so that
2177        # those bodies can be reused for the types that implement the
2178        # interface. See GtkTreeModel.
2179
2180        if self.is_interface:
2181            self.implements[""] = {
2182                "name": self._subst["typename"],
2183                "interface": None,
2184                "code": """function "+" (W : %(typename)s) return %(typename)s;
2185    pragma Inline ("+"); """ % self._subst,
2186                "body": """function "+" (W : %(typename)s) return %(typename)s is
2187begin
2188   return W;
2189end "+";""" % self._subst,
2190            }
2191
2192        if self.implements:
2193
2194            # Duplicate the subprograms from the interfaces. This doesn't
2195            # quite work: for instance, Gtk.About_Dialog already has a
2196            # Get_Name, so we can't redefine the one inherited from Buildable.
2197            section = self.pkg.section(
2198                "Inherited subprograms (from interfaces)")
2199
2200            for impl in sorted(self.implements.iterkeys()):
2201                impl = self.implements[impl]
2202                if impl["name"] == "Buildable":
2203                    # Do not repeat for buildable, that's rarely used
2204
2205                    section.add_comment(
2206                        "Methods inherited from the Buildable interface are"
2207                        + " not duplicated here since they are meant to be"
2208                        + " used by tools, mostly. If you need to call them,"
2209                        + ' use an explicit cast through the "-" operator'
2210                        + " below.")
2211
2212                    continue
2213
2214                interf = impl["interface"]
2215
2216                # Ignore interfaces that we haven't bound
2217                if interf is not None and not hasattr(interf, "gtkpkg"):
2218                    print "%s: methods for interface %s were not bound" % (
2219                        self.name, impl["name"])
2220                elif interf is not None:
2221                    all = interf.node.findall(nmethod)
2222                    for c in all:
2223                        cname = c.get(cidentifier)
2224                        gtkmethod = interf.gtkpkg.get_method(cname)
2225                        interfmethod = self.gtkpkg.get_method(cname)
2226
2227                        if interfmethod.bind():
2228                            self._handle_function(
2229                                section, c, showdoc=False, gtkmethod=gtkmethod,
2230                                ismethod=True, isinherited=True)
2231
2232            section = self.pkg.section("Interfaces")
2233            section.add_comment(
2234                "This class implements several interfaces. See Glib.Types")
2235
2236            for impl in sorted(self.implements.iterkeys()):
2237                impl = self.implements[impl]
2238                section.add_comment("")
2239                section.add_comment('- "%(name)s"' % impl)
2240                section.add(impl["code"])
2241                if impl["body"]:
2242                    section.add(impl["body"], in_spec=False)
2243
2244    def add_list_binding(self, section, adaname, ctype, singleList):
2245        """Generate a list instance"""
2246
2247        conv = "%s->Address" % ctype.ada
2248        decl = ""
2249        body = ""
2250
2251        if conv not in self.conversions:
2252            self.conversions[conv] = True
2253
2254            base = "function Convert (R : %s) return System.Address" % (
2255                ctype.ada)
2256
2257            decl += base + ';\n'
2258            body += base + " is\nbegin\n"
2259
2260            if isinstance(ctype, Proxy):
2261                body += "return Glib.To_Address (Glib.C_Proxy (R));"
2262            else:
2263                body += "return Get_Object (R);"
2264
2265            body += "\nend Convert;\n\n"
2266
2267        conv = "Address->%s" % ctype.ada
2268        if conv not in self.conversions:
2269            self.conversions[conv] = True
2270
2271            decl += "function Convert (R : System.Address) return %s;\n" % (
2272                ctype.ada)
2273            body += "function Convert (R : System.Address) return %s is\n" % (
2274                ctype.ada)
2275
2276            if isinstance(ctype, Proxy):
2277                body += "begin\nreturn %s" % ctype.ada \
2278                    + "(Glib.C_Proxy'(Glib.To_Proxy (R)));"
2279
2280            elif isinstance(ctype, Tagged):
2281                # Not a GObject ?
2282                body += "begin\nreturn From_Object(R);"
2283
2284            else:
2285                body += "Stub : %s_Record;" % ctype.ada
2286                body += "begin\n"
2287                body += "return %s (Glib.Object.Get_User_Data (R, Stub));" % (
2288                    ctype.ada)
2289
2290            body += "\nend Convert;"
2291
2292        if singleList:
2293            pkg = "GSlist"
2294            generic = "Generic_SList"
2295        else:
2296            pkg = "Glist"
2297            generic = "Generic_List"
2298
2299        self.pkg.add_with("Glib.%s" % pkg)
2300
2301        decl += "package %s is new %s (%s);\n" % (adaname, generic, ctype.ada)
2302        section.add(decl)
2303        section.add(body, in_spec=False)
2304
2305    def record_binding(
2306            self, section, ctype, adaname, type, override_fields,
2307            unions, private):
2308        """Create the binding for a <record> or <union> type.
2309           override_fields has the same format as returned by
2310           GtkAdaPackage.records()
2311        """
2312        base = adaname or base_name(type.ada)
2313
2314        try:
2315            node = gir.records[ctype]
2316        except KeyError:
2317            # The package doesn't contain a type (for instance GtkMain)
2318            return
2319
2320        gir.bound.add(ctype)
2321
2322        is_union = node.tag == nunion
2323        first_field_ctype = None
2324
2325        fields = []   # array of (name,type,default) tuples
2326
2327        # Check if we have forced the mapping as a C proxy ?
2328
2329        if (naming.type_exceptions.get(ctype, None) is None
2330                or not isinstance(naming.type_exceptions[ctype], Proxy)):
2331
2332            for field in node.findall(nfield):
2333                name = field.get("name")
2334
2335                ftype = None
2336                type = _get_type(field)
2337                cb = field.findall(ncallback)
2338
2339                if type:
2340                    ftype = override_fields.get(name, None)
2341                    if ftype is None:
2342
2343                        if not first_field_ctype:
2344                            t = field.findall(ntype)
2345                            assert t, "No type info for %s.%s" % (ctype, name)
2346
2347                            ctype = t[0].get(ctype_qname)
2348                            if not ctype:
2349                                # <type name="..."> has no c:type attribute,
2350                                # so we try to map the name to a Girname
2351                                ctype = naming.girname_to_ctype[
2352                                    t[0].get("name")]
2353
2354                            first_field_ctype = ctype
2355
2356                        ftype = type
2357
2358                elif cb:
2359                    # ??? JL: Should properly bind the callback here.
2360                    # For now, we just use a System.Address to maintain the
2361                    # record integrity
2362                    ftype = override_fields.get(name, None)
2363                    if ftype is None:
2364                        ftype = AdaType(
2365                            "System.Address", pkg=self.pkg)
2366
2367                else:
2368                    print "WARNING: Field '%s.%s' has no type" % (name, base)
2369                    print " generated record is most certainly incorrect"
2370
2371                if ftype is not None:
2372                    if ftype.ada in ("GSList", "GList") and private:
2373                        ftype = "System.Address"
2374                        default_value = "System.Null_Address"
2375                    else:
2376                        default_value = ftype.default_record_field_value
2377                        ftype = ftype.record_field_type(pkg=self.pkg)
2378
2379                    self.pkg.add_with(package_name(ftype))
2380                    fields.append((naming.case(name), ftype, default_value))
2381
2382        if not fields:
2383            section.add(
2384                ("\ntype %(typename)s is new Glib.C_Proxy;\n"
2385                 + "function From_Object_Free (B : access %(typename)s) "
2386                 + "return %(typename)s;\npragma Inline (From_Object_Free);")
2387                 % {"typename": base})
2388            section.add("""
2389function From_Object_Free (B : access %(typename)s) return %(typename)s is
2390   Result : constant %(typename)s := B.all;
2391begin
2392   Glib.g_free (B.all'Address);
2393   return Result;
2394end From_Object_Free;""" % {"typename": base}, in_spec=False)
2395
2396        else:
2397            if private:
2398                section.add(
2399                    ("\ntype %(typename)s is private;\n"
2400                     + "function From_Object_Free (B : access %(typename)s)"
2401                     + " return %(typename)s;\n"
2402                     + "pragma Inline (From_Object_Free);")
2403                    % {"typename": base})
2404                adder = self.pkg.add_private
2405            else:
2406                adder = section.add
2407
2408            if is_union:
2409                enums = self.get_enumeration_values(first_field_ctype)
2410                enums_dict = {ctype: adatype for ctype, adatype in enums}
2411                text = "\ntype %s (%s : %s := %s) is record\n" % (
2412                    base, fields[0][0], fields[0][1],
2413                    enums[0][1]) + \
2414                    "    case %s is\n" % fields[0][0]
2415                for index, f in enumerate(fields):
2416                    if index != 0:
2417                        when_stmt = []
2418                        if unions:
2419                            for v, key in unions:
2420                                # applies to field
2421                                if key.lower() == f[0].lower():
2422                                    when_stmt.append(enums_dict[v])
2423                        else:
2424                            when_stmt = [enums[index][1]]
2425
2426                        if not when_stmt:
2427                            print("ERROR: no discrimant value for field %s"
2428                                  % f[0])
2429
2430                        text += "\n      when %s =>\n %s : %s;\n" % (
2431                            "\n          | ".join(when_stmt), f[0], f[1])
2432
2433                text += "   end case;\nend record;\n"
2434                text += "pragma Convention (C, %s);\n" % base
2435                text += "pragma Unchecked_Union(%s);\n" % base
2436                adder("\n" + Code(text).format())
2437
2438            else:
2439                c = []
2440                for f in fields:
2441                    if f[2]:
2442                        c.append('%s : %s := %s;' % (f[0], f[1], f[2]))
2443                    else:
2444                        c.append('%s : %s;' % (f[0], f[1]))
2445
2446                c = Code('\ntype %s is record\n' % base
2447                         + '\n'.join(c)
2448                         + '\nend record;\npragma Convention (C, %s);\n' % base)
2449                adder(c.format())
2450
2451            if not private:
2452                section.add(
2453                    ("\nfunction From_Object_Free (B : access %(type)s)"
2454                     + " return %(type)s;\n"
2455                     + "pragma Inline (From_Object_Free);") % {"type": base})
2456
2457            section.add("""
2458function From_Object_Free (B : access %(typename)s) return %(typename)s is
2459   Result : constant %(typename)s := B.all;
2460begin
2461   Glib.g_free (B.all'Address);
2462   return Result;
2463end From_Object_Free;""" % {"typename": base}, in_spec=False)
2464
2465        section.add(Code(_get_clean_doc(node), iscomment=True))
2466
2467    def get_enumeration_values(sef, enum_ctype):
2468        """Return the list of enumeration values for the given enum, as a list
2469           of tuples  (C identifier, ada identifier)"""
2470
2471        node = gir.enums[enum_ctype]
2472        return [(m.get(cidentifier), naming.adamethod_name(m.get(cidentifier)))
2473                for m in node.findall(nmember)]
2474
2475    def constants_binding(self, section, regexp, prefix):
2476        constants = []
2477        r = re.compile(regexp)
2478
2479        for name, node in gir.constants.iteritems():
2480            if r.match(name):
2481                name = name.replace(prefix, "").title()
2482
2483                gir.bound.add(node.get(ctype_qname))
2484
2485                type = node.findall(ntype)
2486                ctype = type[0].get(ctype_qname)
2487                ftype = naming.type(name="", cname=ctype)
2488
2489                constants.append(
2490                    '%s : constant %s := "%s";' %
2491                    (name, ftype.ada, node.get("value")))
2492
2493        constants.sort()
2494        section.add("\n".join(constants))
2495
2496    def enumeration_binding(self, section, ctype, type, prefix,
2497                            asbitfield=False, ignore=""):
2498        """Add to the section the Ada type definition for the <enumeration>
2499           ctype. type is the corresponding instance of CType().
2500           This function also handles <bitfield> types.
2501
2502           :param prefix: is removed from the values to get the default Ada name,
2503              which can be overridden in data.cname_to_adaname.
2504           :param ignore: space-separated list of values that should not be
2505              bound.
2506        """
2507        base = base_name(type.ada)
2508        node = gir.enums[ctype]
2509
2510        current = 0
2511        is_default_representation = True
2512
2513        gir.bound.add(ctype)
2514
2515        members = []
2516        ignore = set(ignore.split())
2517
2518        for member in node.findall(nmember):
2519            cname = member.get(cidentifier)
2520
2521            if cname in ignore:
2522                continue
2523
2524            m = naming.adamethod_name(cname, warning_if_not_found=False)
2525            if m is None:
2526                continue
2527
2528            if cname == m:
2529                # No special case ? Attempt a simple rule (remove leading
2530                # Gtk prefix, and capitalize the value)
2531                m = cname.replace(prefix, "").title()
2532
2533            else:
2534                m = base_name(m)
2535
2536            # For proper substitution in docs
2537            naming.add_cmethod(
2538                cname=cname,
2539                adaname="%s.%s" % (self.name, m))
2540
2541            value = int(member.get("value"))
2542            if value != current:
2543                is_default_representation = False
2544            current += 1
2545
2546            members.append((m, value))
2547
2548        decl = ""
2549
2550        if node.tag == nenumeration and not asbitfield:
2551            section.add(
2552                "type %s is " % base
2553                + "(\n" + ",\n".join(m[0]
2554                                     for m in sorted(members, key=lambda m: m[1]))
2555                + ");\n"
2556                + "pragma Convention (C, %s);\n" % base)
2557            section.add(Code(_get_clean_doc(node), iscomment=True))
2558
2559            if not is_default_representation:
2560                repr = ("   for %s use (\n" % base
2561                        + ",\n".join("      %s => %s" % m
2562                                     for m in sorted(members, key=lambda m: m[1]))
2563                        + ");\n")
2564                section.add(repr)
2565
2566        elif node.tag == nbitfield or asbitfield:
2567            section.add(
2568                "\ntype %s is " % base
2569                + "mod 2 ** Integer'Size;\n"
2570                + "pragma Convention (C, %s);\n" % base)
2571            section.add(Code(_get_clean_doc(node), iscomment=True))
2572
2573            for m, value in members:
2574                decl += "%s : constant %s := %s;\n" % (m, base, value)
2575            section.add(decl)
2576
2577        section.pkg.section("Enumeration Properties").add(
2578            "package %s_Properties is\n" % base
2579            + "   new Generic_Internal_Discrete_Property (%s);\n" % base
2580            + "type Property_%s is new %s_Properties.Property;\n\n" % (
2581                base, base))
2582
2583        self.pkg.add_with("Glib.Generic_Properties")
2584
2585    def generate(self, gir):
2586        if self._generated:
2587            return
2588
2589        extra = self.gtkpkg.extra()
2590        if extra:
2591            self.node.extend(extra)
2592
2593        # The parent is unfortunately specified as a GIR name. But that creates
2594        # ambiguities when loading both Gtk and Gdk, which for instance both
2595        # define "Window". So we first look in the same file as the current
2596        # Class.
2597
2598        parent = gir._get_class_node(
2599            self.rootNode,
2600            girname=self.gtkpkg.parent_type() or self.node.get("parent"))
2601        parent = naming.type(
2602            name=self.gtkpkg.parent_type() or self.node.get(
2603                "parent"),  # GIRName
2604            cname=parent and parent.get(ctype_qname)).ada
2605
2606        if parent and parent.rfind(".") != -1:
2607            self._subst["parent_pkg"] = package_name(parent)
2608            self._subst["parent"] = base_name(parent)
2609        else:
2610            self._subst["parent_pkg"] = None
2611            self._subst["parent"] = parent
2612
2613        self._generated = True
2614
2615        girdoc = _get_clean_doc(self.node)
2616
2617        into = self.gtkpkg.into()
2618        if into:
2619            # Make sure we have already generated the other package, so that
2620            # its types go first.
2621            klass = gir.classes.get(into, None) or gir.ctype_interfaces[into]
2622            klass.generate(gir)
2623            into = klass.name  # from now on, we want the Ada name
2624
2625            # Do not integrate the documentation from the other package, it
2626            # is likely useless anyway
2627
2628            girdoc = ""
2629
2630            # Override the type exception. For instance, from now on we
2631            # want to use "Gtk.Box.Gtk_HBox" rather than "Gtk.HBox.Gtk_HBox"
2632            # which doesn't exist
2633            typename = "%s.%s" % (into, self._subst["typename"])
2634
2635            # retrieve the old type
2636            oldtype = naming.type(cname=self.ctype)
2637            newtype = None
2638            # and create the new one accordingly
2639            if isinstance(oldtype, Tagged):
2640                newtype = Tagged(typename)
2641            elif isinstance(oldtype, GObject):
2642                newtype = GObject(typename)
2643            elif isinstance(oldtype, Proxy):
2644                newtype = Proxy(typename)
2645            elif isinstance(oldtype, Record):
2646                newtype = Record(typename)
2647            else:
2648                raise Exception("Can't override %s for a package with 'into'"
2649                                % oldtype)
2650            naming.add_type_exception(
2651                override=True,
2652                cname=self.ctype,
2653                type=newtype)
2654
2655        self.pkg = gir.get_package(into or self.ada_package_name,
2656                                   ctype=self.ctype,
2657                                   doc=girdoc)
2658
2659        if self._subst["parent_pkg"]:
2660            self.pkg.add_with("%(parent_pkg)s" % self._subst)
2661
2662        self.gtktype = self.gtkpkg.get_type(self._subst["typename"])
2663
2664        section = self.pkg.section("")
2665
2666        if self.gtkpkg.is_obsolete():
2667            section.add("pragma Obsolescent;")
2668
2669        if not self.has_toplevel_type:
2670            pass
2671
2672        elif self.is_interface:
2673            self.pkg.add_with("Glib.Types")
2674            section.add(
2675                """type %(typename)s is new Glib.Types.GType_Interface;
2676Null_%(typename)s : constant %(typename)s;""" % self._subst)
2677
2678            self.pkg.add_private("""
2679Null_%(typename)s : constant %(typename)s :=
2680   %(typename)s (Glib.Types.Null_Interface);""" %
2681                                 self._subst)
2682
2683        elif self.gtktype.is_subtype():
2684            section.add(
2685                """
2686subtype %(typename)s_Record is %(parent)s_Record;
2687subtype %(typename)s is %(parent)s;""" % self._subst)
2688
2689        elif self.is_proxy:
2690            section.add("""
2691   type %(typename)s is new Glib.C_Proxy;""" % self._subst)
2692
2693        elif self.is_boxed:
2694            # The type is not private so that we can directly instantiate
2695            # generic packages for lists of this type.
2696
2697            section.add("""
2698   type %(typename)s is new Glib.C_Boxed with null record;
2699   Null_%(typename)s : constant %(typename)s;
2700
2701   function From_Object (Object : System.Address) return %(typename)s;
2702   function From_Object_Free (B : access %(typename)s'Class) return %(typename)s;
2703   pragma Inline (From_Object_Free, From_Object);
2704""" % self._subst)
2705
2706            # Insert constant declaration at the end of the package, to avoid
2707            # freezing issues
2708            self.pkg.add_private(
2709                ("\n   Null_%(typename)s : constant %(typename)s :="
2710                + " (Glib.C_Boxed with null record);\n") %
2711                self._subst, at_end=True)
2712
2713            section.add("""
2714   function From_Object_Free
2715      (B : access %(typename)s'Class) return %(typename)s
2716   is
2717      Result : constant %(typename)s := %(typename)s (B.all);
2718   begin
2719      Glib.g_free (B.all'Address);
2720      return Result;
2721   end From_Object_Free;
2722
2723   function From_Object (Object : System.Address) return %(typename)s is
2724      S : %(typename)s;
2725   begin
2726      S.Set_Object (Object);
2727      return S;
2728   end From_Object;
2729""" % self._subst, in_spec=False)
2730
2731        elif self._subst["parent"] is None:
2732            # Likely a public record type (ie with visible fields).
2733            # Automatically add it to the list of records to bind.
2734
2735            self.gtkpkg.add_record_type(self.ctype)
2736
2737        else:
2738            section.add("""
2739type %(typename)s_Record is new %(parent)s_Record with null record;
2740type %(typename)s is access all %(typename)s_Record'Class;"""
2741                        % self._subst)
2742
2743        for ctype, enum, prefix, asbitfield, ignore in \
2744             self.gtkpkg.enumerations():
2745
2746            self.enumeration_binding(
2747                section, ctype, enum, prefix, asbitfield=asbitfield,
2748                ignore=ignore)
2749
2750        for regexp, prefix in self.gtkpkg.constants():
2751            self.constants_binding(section, regexp, prefix)
2752
2753        for ctype, enum, adaname, fields, unions, private in \
2754             self.gtkpkg.records():
2755
2756            self.record_binding(
2757                section, ctype, adaname, enum, fields, unions, private)
2758
2759        for ada, ctype, single, sect_name in self.gtkpkg.lists():
2760            sect = self.pkg.section(sect_name)
2761            self.add_list_binding(sect, ada, ctype, single)
2762
2763        if extra:
2764            for p in extra:
2765                if p.tag == "with_spec":
2766                    self.pkg.add_with(
2767                        p.get("pkg", "Missing package name in <extra>"),
2768                        do_use=p.get("use", "true").lower() == "true")
2769                elif p.tag == "with_body":
2770                    self.pkg.add_with(
2771                        p.get("pkg"), specs=False,
2772                        do_use=p.get("use", "true").lower() == "true")
2773                elif p.tag == "type":
2774                    naming.add_type_exception(
2775                        cname=p.get("ctype"),
2776                        type=Proxy(p.get("ada"), p.get("properties", None)))
2777                    section.add(p.text)
2778                elif p.tag == "body":
2779                    if p.get("before", "true").lower() == "true":
2780                        # Go before the body of generated subprograms, so that
2781                        # we can add type definition
2782                        section.add(p.text, in_spec=False)
2783
2784        self._constructors()
2785        self._method_get_type()
2786        self._methods()
2787
2788        if extra:
2789            s = None
2790            for p in extra:
2791                if p.tag == "spec":
2792                    if p.get("private", "False").lower() == "true":
2793                        self.pkg.add_private(p.text, at_end=True)
2794                    else:
2795                        s = s or self.pkg.section("GtkAda additions")
2796                        s.add(p.text)
2797                elif p.tag == "body" \
2798                        and p.get("before", "true").lower() != "true":
2799                    s.add(p.text, in_spec=False)
2800
2801        self._functions()
2802        self._globals()
2803        self._fields()
2804
2805        self._virtual_methods()
2806
2807        if not into and self.name != "Gtk.Widget":
2808            self._implements()
2809        self._properties()
2810        self._signals()
2811
2812
2813# Set up and invoke our command line parser
2814parser = OptionParser()
2815parser.add_option(
2816    "--gir-file",
2817    help="input GTK .gir file",
2818    action="append",
2819    dest="gir_file",
2820    metavar="FILE")
2821parser.add_option(
2822    "--xml-file",
2823    help="input GtkAda binding.xml file",
2824    dest="xml_file",
2825    metavar="FILE")
2826parser.add_option(
2827    "--ada-output",
2828    help="Ada language output file",
2829    dest="ada_outfile",
2830    metavar="FILE")
2831parser.add_option(
2832    "--c-output",
2833    help="C language output file",
2834    dest="c_outfile",
2835    metavar="FILE")
2836(options, args) = parser.parse_args()
2837
2838# Command line argument sanity checking: make sure that all of our
2839# inputs and outputs are specified.
2840missing_files = []
2841if options.gir_file is None:
2842    missing_files.append("GIR file")
2843if options.xml_file is None:
2844    missing_files.append("binding.xml file")
2845if options.ada_outfile is None:
2846    missing_files.append("Ada output file")
2847if options.c_outfile is None:
2848    missing_files.append("C output file")
2849if missing_files:
2850    parser.error('Must specify files:\n\t' + ', '.join(missing_files))
2851
2852gtkada = GtkAda(options.xml_file)
2853gir = GIR(options.gir_file)
2854
2855Package.copyright_header = \
2856    """------------------------------------------------------------------------------
2857--                                                                          --
2858--      Copyright (C) 1998-2000 E. Briot, J. Brobecker and A. Charlet       --
2859--                     Copyright (C) 2000-2015, AdaCore                     --
2860--                                                                          --
2861-- This library is free software;  you can redistribute it and/or modify it --
2862-- under terms of the  GNU General Public License  as published by the Free --
2863-- Software  Foundation;  either version 3,  or (at your  option) any later --
2864-- version. This library is distributed in the hope that it will be useful, --
2865-- but WITHOUT ANY WARRANTY;  without even the implied warranty of MERCHAN- --
2866-- TABILITY or FITNESS FOR A PARTICULAR PURPOSE.                            --
2867--                                                                          --
2868-- As a special exception under Section 7 of GPL version 3, you are granted --
2869-- additional permissions described in the GCC Runtime Library Exception,   --
2870-- version 3.1, as published by the Free Software Foundation.               --
2871--                                                                          --
2872-- You should have received a copy of the GNU General Public License and    --
2873-- a copy of the GCC Runtime Library Exception along with this program;     --
2874-- see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see    --
2875-- <http://www.gnu.org/licenses/>.                                          --
2876--                                                                          --
2877------------------------------------------------------------------------------
2878"""
2879
2880gir.ccode = \
2881    """/*****************************************************************************
2882 *               GtkAda - Ada95 binding for Gtk+/Gnome                       *
2883 *                                                                           *
2884 *   Copyright (C) 1998-2000 E. Briot, J. Brobecker and A. Charlet           *
2885 *                     Copyright (C) 2000-2015, AdaCore                      *
2886 *                                                                           *
2887 * This library is free software;  you can redistribute it and/or modify it  *
2888 * under terms of the  GNU General Public License  as published by the Free  *
2889 * Software  Foundation;  either version 3,  or (at your  option) any later  *
2890 * version. This library is distributed in the hope that it will be useful,  *
2891 * but WITHOUT ANY WARRANTY;  without even the implied warranty of MERCHAN-  *
2892 * TABILITY or FITNESS FOR A PARTICULAR PURPOSE.                             *
2893 *                                                                           *
2894 * As a special exception under Section 7 of GPL version 3, you are granted  *
2895 * additional permissions described in the GCC Runtime Library Exception,    *
2896 * version 3.1, as published by the Free Software Foundation.                *
2897 *                                                                           *
2898 * You should have received a copy of the GNU General Public License and     *
2899 * a copy of the GCC Runtime Library Exception along with this program;      *
2900 * see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see     *
2901 * <http://www.gnu.org/licenses/>.                                           *
2902 *
2903 *****************************************************************************
2904
2905This file is automatically generated from the .gir files
2906*/
2907#include <gtk/gtk.h>
2908"""
2909
2910
2911for the_ctype in enums:
2912    node = Element(
2913        nclass,
2914        {ctype_qname: the_ctype})
2915    root = Element(nclass)
2916
2917    cl = gir._create_class(rootNode=root, node=node,
2918                           identifier_prefix='',
2919                           is_interface=False,
2920                           is_gobject=False,
2921                           has_toplevel_type=False)
2922    cl.generate(gir)
2923
2924for name in interfaces:
2925    if name.startswith("--"):
2926        gir.bound.add(name[2:])
2927        continue
2928
2929    gir.interfaces[name].generate(gir)
2930    gir.bound.add(name)
2931
2932for the_ctype in binding:
2933    if the_ctype.startswith("--"):
2934        gir.bound.add(the_ctype[2:])
2935        continue
2936
2937    try:
2938        e = gir.classes[the_ctype]
2939    except KeyError:
2940        cl = gtkada.get_pkg(the_ctype)
2941        if not cl:
2942            raise
2943        node = Element(nclass, {ctype_qname: the_ctype})
2944        e = gir.classes[the_ctype] = gir._create_class(
2945            rootNode=root, node=node, is_interface=False,
2946            identifier_prefix='')
2947
2948    e.generate(gir)
2949    gir.bound.add(the_ctype)
2950
2951
2952out = file(options.ada_outfile, "w")
2953cout = file(options.c_outfile, "w")
2954gir.generate(out, cout)
2955
2956gir.show_unbound()
2957