Add a GIRepository-2.0.gir. Change the libtool lookup slightly so we can
[gnome.gobject-introspection] / giscanner / glibtransformer.py
1 # -*- Mode: Python -*-
2 # GObject-Introspection - a framework for introspecting GObject libraries
3 # Copyright (C) 2008  Johan Dahlin
4 #
5 # This library is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU Lesser General Public
7 # License as published by the Free Software Foundation; either
8 # version 2 of the License, or (at your option) any later version.
9 #
10 # This library is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 # Lesser General Public License for more details.
14 #
15 # You should have received a copy of the GNU Lesser General Public
16 # License along with this library; if not, write to the
17 # Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 # Boston, MA 02111-1307, USA.
19 #
20
21 import os
22 import re
23 import ctypes
24 from ctypes.util import find_library
25
26 from . import cgobject
27 from .ast import (Callback, Constant, Enum, Function, Member, Namespace,
28                   Parameter, Property, Return, Struct, Type, Alias,
29                   Union, Field, type_name_from_ctype,
30                   default_array_types, TYPE_UINT8, PARAM_DIRECTION_IN)
31 from .transformer import Names
32 from .glibast import (GLibBoxed, GLibEnum, GLibEnumMember, GLibFlags,
33                       GLibInterface, GLibObject, GLibSignal, GLibBoxedStruct,
34                       GLibBoxedUnion, GLibBoxedOther, type_names)
35 from .utils import extract_libtool, to_underscores, to_underscores_noprefix
36
37 default_array_types['guchar*'] = TYPE_UINT8
38
39 SYMBOL_BLACKLIST = [
40     # These ones break GError conventions
41     'g_simple_async_result_new_from_error',
42     'g_simple_async_result_set_from_error',
43     'g_simple_async_result_propagate_error',
44     'g_simple_async_result_report_error_in_idle',
45     'gtk_print_operation_get_error',
46 ]
47
48 SYMBOL_BLACKLIST_RE = [re.compile(x) for x in \
49                            [r'\w+_marshal_[A-Z]+__', ]]
50
51
52 class Unresolved(object):
53
54     def __init__(self, target):
55         self.target = target
56
57
58 class UnknownTypeError(Exception):
59     pass
60
61
62 class GLibTransformer(object):
63
64     def __init__(self, transformer, noclosure=False):
65         self._transformer = transformer
66         self._transformer.set_container_types(['GList*', 'GSList*'],
67                                               ['GHashtable*'])
68         self._namespace_name = None
69         self._names = Names()
70         self._uscore_type_names = {}
71         self._libraries = []
72         self._failed_types = {}
73         self._boxed_types = {}
74         self._private_internal_types = {}
75         self._noclosure = noclosure
76         self._validating = False
77
78     # Public API
79
80     def add_library(self, libname):
81         # For testing mainly.
82         libtool_libname = 'lib' + libname + '.la'
83         if os.path.exists(libname):
84             found_libname = os.path.abspath(libname)
85         elif os.path.exists(libtool_libname):
86             found_libname = extract_libtool(libtool_libname)
87             libname = os.path.basename(found_libname)
88         else:
89             found_libname = find_library(libname)
90
91         if libname.endswith('.la'):
92             found_libname = extract_libtool(libname)
93             libname = os.path.basename(found_libname)
94         if not found_libname:
95             raise ValueError("Failed to find library: %r" % (libname, ))
96         self._libraries.append(ctypes.cdll.LoadLibrary(found_libname))
97         return libname
98
99     def _print_statistics(self):
100         nodes = list(self._names.names.itervalues())
101
102         def count_type(otype):
103             return len([x for x in nodes
104                         if isinstance(x[1], otype)])
105         objectcount = count_type(GLibObject)
106         ifacecount = count_type(GLibInterface)
107         enumcount = count_type(GLibEnum)
108         print " %d nodes; %d objects, %d interfaces, %d enums" \
109             % (len(nodes), objectcount, ifacecount, enumcount)
110
111     def parse(self):
112         namespace = self._transformer.parse()
113         self._namespace_name = namespace.name
114
115         # First pass: parsing
116         for node in namespace.nodes:
117             self._parse_node(node)
118
119         # We don't want an alias for this - it's handled specially in
120         # the typelib compiler.
121         if namespace.name == 'GObject':
122             del self._names.aliases['Type']
123
124         # Introspection is done from within parsing
125
126         # Second pass: pair boxed structures
127         for boxed in self._boxed_types.itervalues():
128             self._pair_boxed_type(boxed)
129         # Third pass: delete class structures, resolve
130         # all types we now know about
131         nodes = list(self._names.names.itervalues())
132         for (ns, node) in nodes:
133             try:
134                 self._resolve_node(node)
135             except KeyError, e:
136                 print "WARNING: DELETING node %s: %s" % (node.name, e)
137                 self._remove_attribute(node.name)
138             # associate GtkButtonClass with GtkButton
139             if isinstance(node, Struct):
140                 self._pair_class_struct(node)
141         for (ns, alias) in self._names.aliases.itervalues():
142             self._resolve_alias(alias)
143
144         self._print_statistics()
145         # Fourth pass: ensure all types are known
146         if not self._noclosure:
147             self._validate(nodes)
148
149         # Create a new namespace with what we found
150         namespace = Namespace(namespace.name, namespace.version)
151         namespace.nodes = map(lambda x: x[1], self._names.aliases.itervalues())
152         for (ns, x) in self._names.names.itervalues():
153             namespace.nodes.append(x)
154         return namespace
155
156     # Private
157
158     def _add_attribute(self, node, replace=False):
159         node_name = node.name
160         if (not replace) and node_name in self._names.names:
161             return
162         self._names.names[node_name] = (None, node)
163
164     def _remove_attribute(self, name):
165         del self._names.names[name]
166
167     def _get_attribute(self, name):
168         node = self._names.names.get(name)
169         if node:
170             return node[1]
171         return None
172
173     def _register_internal_type(self, type_name, node):
174         self._names.type_names[type_name] = (None, node)
175         uscored = to_underscores(type_name).lower()
176         self._uscore_type_names[uscored] = node
177         # Besides the straight underscore conversion, we also try
178         # removing the underscores from the namespace as a possible C
179         # mapping; e.g. it's webkit_web_view, not web_kit_web_view
180         suffix = self._transformer.remove_prefix(type_name)
181         prefix = type_name[:-len(suffix)]
182         no_uscore_prefixed = (prefix + '_' + to_underscores(suffix)).lower()
183         self._uscore_type_names[no_uscore_prefixed] = node
184
185     # Helper functions
186
187     def _type_from_gtype(self, type_id):
188         ctype = cgobject.type_name(type_id)
189         type_name = type_name_from_ctype(ctype)
190         type_name = type_name.replace('*', '')
191         type_name = self._resolve_type_name(type_name)
192
193         type = Type(type_name, ctype)
194         type._gtype = type_id
195         return type
196
197     def _resolve_gtypename(self, gtype_name):
198         try:
199             return self._transformer.gtypename_to_giname(gtype_name,
200                                                          self._names)
201         except KeyError, e:
202             return Unresolved(gtype_name)
203
204     def _create_gobject(self, node):
205         type_name = 'G' + node.name
206         if type_name == 'GObject':
207             parent_gitype = None
208             symbol = 'intern'
209         else:
210             type_id = cgobject.type_from_name(type_name)
211             parent_type_name = cgobject.type_name(
212                 cgobject.type_parent(type_id))
213             parent_gitype = self._resolve_gtypename(parent_type_name)
214             symbol = to_underscores(type_name).lower() + '_get_type'
215         node = GLibObject(node.name, parent_gitype, type_name, symbol, True)
216         type_id = cgobject.TYPE_OBJECT
217         self._introspect_properties(node, type_id)
218         self._introspect_signals(node, type_id)
219         self._add_attribute(node)
220         self._register_internal_type(type_name, node)
221
222     # Parser
223
224     def _parse_node(self, node):
225         if isinstance(node, Enum):
226             self._parse_enum(node)
227         elif isinstance(node, Function):
228             self._parse_function(node)
229         elif isinstance(node, Struct):
230             self._parse_struct(node)
231         elif isinstance(node, Callback):
232             self._parse_callback(node)
233         elif isinstance(node, Alias):
234             self._parse_alias(node)
235         elif isinstance(node, Member):
236             # FIXME: atk_misc_instance singletons
237             pass
238         elif isinstance(node, Union):
239             self._parse_union(node)
240         elif isinstance(node, Constant):
241             self._parse_constant(node)
242         else:
243             print 'GLIB Transformer: Unhandled node:', node
244
245     def _parse_alias(self, alias):
246         self._names.aliases[alias.name] = (None, alias)
247
248     def _parse_enum(self, enum):
249         self._add_attribute(enum)
250
251     def _parse_constant(self, constant):
252         self._add_attribute(constant)
253
254     def _parse_function(self, func):
255         if func.symbol in SYMBOL_BLACKLIST:
256             return
257         if func.symbol.startswith('_'):
258             return
259         for regexp in SYMBOL_BLACKLIST_RE:
260             if regexp.match(func.symbol):
261                 return
262         if self._parse_get_type_function(func):
263             return
264
265         self._add_attribute(func)
266
267     def _parse_get_type_function(self, func):
268         symbol = func.symbol
269         if not symbol.endswith('_get_type'):
270             return False
271         if self._namespace_name == 'GLib':
272             # No GObjects in GLib
273             return False
274         if func.parameters:
275             return False
276         # GType *_get_type(void)
277         if func.retval.type.name not in ['Type',
278                                          'GType',
279                                          'GObject.Type',
280                                          'Gtk.Type']:
281             print ("Warning: *_get_type function returns '%r'"
282                    ", not GObject.Type") % (func.retval.type.name, )
283             return False
284
285         if not self._libraries:
286             print "Warning: No libraries loaded, cannot call %s" % (symbol, )
287             return False
288
289         for library in self._libraries:
290             try:
291                 func = getattr(library, symbol)
292                 break
293             except AttributeError:
294                 continue
295         else:
296             print 'Warning: could not find symbol: %s' % symbol
297             name = symbol.replace('_get_type', '')
298             self._failed_types[name] = True
299             return False
300
301         func.restype = cgobject.GType
302         func.argtypes = []
303         type_id = func()
304         self._introspect_type(type_id, symbol)
305         return True
306
307     def _name_is_internal_gtype(self, giname):
308         try:
309             node = self._get_attribute(giname)
310             return isinstance(node, (GLibObject, GLibInterface,
311                                      GLibBoxed, GLibEnum, GLibFlags))
312         except KeyError, e:
313             return False
314
315     def _parse_method(self, func):
316         if not func.parameters:
317             return False
318         return self._parse_method_common(func, True)
319
320     def _parse_constructor(self, func):
321         return self._parse_method_common(func, False)
322
323     def _parse_method_common(self, func, is_method):
324         # Skip _get_type functions, we processed them
325         # already
326         if func.symbol.endswith('_get_type'):
327             return None
328         if self._namespace_name == 'GLib':
329             # No GObjects in GLib
330             return None
331
332         if not is_method:
333             target_arg = func.retval
334         else:
335             target_arg = func.parameters[0]
336
337         if is_method:
338             # Methods require their first arg to be a known class
339             # Look at the original C type (before namespace stripping), without
340             # pointers: GtkButton -> gtk_button_, so we can figure out the
341             # method name
342             argtype = target_arg.type.ctype.replace('*', '')
343             name = self._transformer.remove_prefix(argtype)
344             name_uscore = to_underscores_noprefix(name).lower()
345             name_offset = func.symbol.find(name_uscore)
346             if name_offset < 0:
347                 return None
348             prefix = func.symbol[:name_offset+len(name_uscore)]
349         else:
350             # Constructors must have _new
351             # Take everything before that as class name
352             new_idx = func.symbol.find('_new')
353             if new_idx < 0:
354                 return None
355             # Constructors don't return basic types
356             derefed = self._transformer.follow_aliases(target_arg.type.name,
357                                                        self._names)
358             if derefed in type_names:
359                 #print "NOTE: Rejecting constructor returning basic: %r" \
360                 #    % (func.symbol, )
361                 return None
362             prefix = func.symbol[:new_idx]
363
364         klass = None
365
366         def valid_matching_klass(tclass):
367             if tclass is None:
368                 return False
369             elif isinstance(klass, (GLibEnum, GLibFlags)):
370                 return False
371             elif not isinstance(tclass, (GLibObject, GLibBoxed,
372                                           GLibInterface)):
373                 return False
374             else:
375                 return True
376
377         klass = self._uscore_type_names.get(prefix)
378         if klass is None:
379             #print "NOTE: No valid matching class for likely "+\
380             #    "method or constructor: %r" % (func.symbol, )
381             return None
382         # Enums can't have ctors or methods
383         if isinstance(klass, (GLibEnum, GLibFlags)):
384             return None
385
386         # The _uscore_type_names member holds the plain GLibBoxed
387         # object; we want to actually use the struct/record associated
388         if isinstance(klass, GLibBoxed):
389             name = self._transformer.remove_prefix(klass.type_name)
390             klass = self._get_attribute(name)
391
392         if not is_method:
393             # Interfaces can't have constructors, punt to global scope
394             if isinstance(klass, GLibInterface):
395                 #print "NOTE: Rejecting constructor for"+\
396                 #    " interface type: %r" % (func.symbol, )
397                 return None
398             # TODO - check that the return type is a subclass of the
399             # class from the prefix
400             # But for now, ensure that constructor returns are always
401             # the most concrete class
402             name = self._transformer.remove_prefix(klass.type_name)
403             func.retval.type = Type(name, func.retval.type.ctype)
404
405         self._remove_attribute(func.name)
406         # Strip namespace and object prefix: gtk_window_new -> new
407         func.name = func.symbol[len(prefix)+1:]
408         if is_method:
409             # We don't need the "this" parameter
410             del func.parameters[0]
411             klass.methods.append(func)
412         else:
413             klass.constructors.append(func)
414         return func
415
416     def _parse_struct(self, struct):
417         # This is a hack, but GObject is a rather fundamental piece so.
418         internal_names = ["Object", 'InitiallyUnowned']
419         g_internal_names = ["G" + x for x in internal_names]
420         if (self._namespace_name == 'GObject' and
421             struct.name in internal_names):
422             self._create_gobject(struct)
423             return
424         elif struct.name in g_internal_names:
425             # Avoid duplicates
426             return
427         node = self._names.names.get(struct.name)
428         if node is None:
429             self._add_attribute(struct, replace=True)
430             return
431         (ns, node) = node
432         node.fields = struct.fields[:]
433
434     def _parse_union(self, union):
435         node = self._names.names.get(union.name)
436         if node is None:
437             self._add_attribute(union, replace=True)
438             return
439         (ns, node) = node
440         node.fields = union.fields[:]
441
442     def _parse_callback(self, callback):
443         self._add_attribute(callback)
444
445     def _strip_class_suffix(self, name):
446         if (name.endswith('Class') or
447             name.endswith('Iface')):
448             return name[:-5]
449         elif name.endswith('Interface'):
450             return name[:-9]
451         else:
452             return name
453
454     def _arg_is_failed(self, param):
455         ctype = self._transformer.ctype_of(param).replace('*', '')
456         uscored = to_underscores(self._strip_class_suffix(ctype)).lower()
457         if uscored in self._failed_types:
458             print "Warning: failed type: %r" % (param, )
459             return True
460         return False
461
462     def _pair_class_struct(self, maybe_class):
463         name = self._strip_class_suffix(maybe_class.name)
464         if name == maybe_class.name:
465             return
466
467         if self._arg_is_failed(maybe_class):
468             print "WARNING: deleting no-type %r" % (maybe_class.name, )
469             del self._names.names[maybe_class.name]
470             return
471
472         # Object class fields are assumed to be read-only
473         # (see also _introspect_object and transformer.py)
474         for field in maybe_class.fields:
475             if isinstance(field, Field):
476                 field.writable = False
477
478         name = self._resolve_type_name(name)
479         resolved = self._transformer.remove_prefix(name)
480         pair_class = self._get_attribute(resolved)
481         if pair_class and isinstance(pair_class,
482                                      (GLibObject, GLibInterface)):
483             for field in maybe_class.fields[1:]:
484                 pair_class.fields.append(field)
485             return
486         name = self._transformer.remove_prefix(maybe_class.name)
487         pair_class = self._get_attribute(name)
488         if pair_class and isinstance(pair_class,
489                                      (GLibObject, GLibInterface)):
490
491             del self._names.names[maybe_class.name]
492
493     # Introspection
494
495     def _introspect_type(self, type_id, symbol):
496         fundamental_type_id = cgobject.type_fundamental(type_id)
497         if (fundamental_type_id == cgobject.TYPE_ENUM or
498             fundamental_type_id == cgobject.TYPE_FLAGS):
499             self._introspect_enum(fundamental_type_id, type_id, symbol)
500         elif fundamental_type_id == cgobject.TYPE_OBJECT:
501             self._introspect_object(type_id, symbol)
502         elif fundamental_type_id == cgobject.TYPE_INTERFACE:
503             self._introspect_interface(type_id, symbol)
504         elif fundamental_type_id == cgobject.TYPE_BOXED:
505             self._introspect_boxed(type_id, symbol)
506         elif fundamental_type_id == cgobject.TYPE_BOXED:
507             self._introspect_boxed(type_id, symbol)
508         elif fundamental_type_id == cgobject.TYPE_POINTER:
509             # FIXME: Should we do something about these?
510             #        GHashTable, GValue and a few other fundamentals are
511             #        covered here
512             return
513         else:
514             print 'unhandled GType: %s(%d)' % (cgobject.type_name(type_id),
515                                                type_id)
516
517     def _introspect_enum(self, ftype_id, type_id, symbol):
518         type_class = cgobject.type_class_ref(type_id)
519         if type_class is None:
520             return
521
522         members = []
523         for enum_value in type_class.get_values():
524             members.append(GLibEnumMember(enum_value.value_nick,
525                                           enum_value.value,
526                                           enum_value.value_name,
527                                           enum_value.value_nick))
528
529         klass = (GLibFlags if ftype_id == cgobject.TYPE_FLAGS else GLibEnum)
530         type_name = cgobject.type_name(type_id)
531         enum_name = self._transformer.remove_prefix(type_name)
532         node = klass(enum_name, type_name, members, symbol)
533         self._add_attribute(node, replace=True)
534         self._register_internal_type(type_name, node)
535
536     def _introspect_object(self, type_id, symbol):
537         type_name = cgobject.type_name(type_id)
538         # We handle this specially above; in 2.16 and below there
539         # was no g_object_get_type, for later versions we need
540         # to skip it
541         if type_name == 'GObject':
542             return
543         parent_type_name = cgobject.type_name(cgobject.type_parent(type_id))
544         parent_gitype = self._resolve_gtypename(parent_type_name)
545         is_abstract = cgobject.type_is_abstract(type_id)
546         node = GLibObject(
547             self._transformer.remove_prefix(type_name),
548             parent_gitype,
549             type_name,
550             symbol, is_abstract)
551         self._introspect_properties(node, type_id)
552         self._introspect_signals(node, type_id)
553         self._introspect_implemented_interfaces(node, type_id)
554
555         # add struct fields
556         struct = self._get_attribute(node.name)
557         if struct is not None:
558             node.fields = struct.fields
559             for field in node.fields:
560                 if isinstance(field, Field):
561                     # Object instance fields are assumed to be read-only
562                     # (see also _pair_class_struct and transformer.py)
563                     field.writable = False
564
565         self._add_attribute(node, replace=True)
566         self._register_internal_type(type_name, node)
567
568     def _introspect_interface(self, type_id, symbol):
569         type_name = cgobject.type_name(type_id)
570         parent_type_name = cgobject.type_name(cgobject.type_parent(type_id))
571         if parent_type_name == 'GInterface':
572             parent_gitype = None
573         else:
574             parent_gitype = self._resolve_gtypename(parent_type_name)
575         node = GLibInterface(
576             self._transformer.remove_prefix(type_name),
577             parent_gitype,
578             type_name, symbol)
579         self._introspect_properties(node, type_id)
580         self._introspect_signals(node, type_id)
581         # GtkFileChooserEmbed is an example of a private interface, we
582         # just filter them out
583         if symbol.startswith('_'):
584             print "NOTICE: Marking %s as internal type" % (type_name, )
585             self._private_internal_types[type_name] = node
586         else:
587             self._add_attribute(node, replace=True)
588             self._register_internal_type(type_name, node)
589
590     def _introspect_boxed(self, type_id, symbol):
591         type_name = cgobject.type_name(type_id)
592         # This one doesn't go in the main namespace; we associate it with
593         # the struct or union
594         node = GLibBoxed(type_name, symbol)
595         self._boxed_types[node.type_name] = node
596         self._register_internal_type(type_name, node)
597
598     def _introspect_implemented_interfaces(self, node, type_id):
599         fundamental_type_id = cgobject.type_fundamental(type_id)
600         if fundamental_type_id != cgobject.TYPE_OBJECT:
601             raise AssertionError
602         interfaces = cgobject.type_interfaces(type_id)
603         gt_interfaces = []
604         for interface_typeid in interfaces:
605             iname = cgobject.type_name(interface_typeid)
606             gitype = self._resolve_gtypename(iname)
607             gt_interfaces.append(gitype)
608         node.interfaces = gt_interfaces
609
610     def _introspect_properties(self, node, type_id):
611         fundamental_type_id = cgobject.type_fundamental(type_id)
612         if fundamental_type_id == cgobject.TYPE_OBJECT:
613             pspecs = cgobject.object_class_list_properties(type_id)
614         elif fundamental_type_id == cgobject.TYPE_INTERFACE:
615             pspecs = cgobject.object_interface_list_properties(type_id)
616         else:
617             raise AssertionError
618
619         for pspec in pspecs:
620             if pspec.owner_type != type_id:
621                 continue
622             ctype = cgobject.type_name(pspec.value_type)
623             readable = (pspec.flags & 1) != 0
624             writable = (pspec.flags & 2) != 0
625             construct = (pspec.flags & 4) != 0
626             construct_only = (pspec.flags & 8) != 0
627             node.properties.append(Property(
628                 pspec.name,
629                 type_name_from_ctype(ctype),
630                 readable, writable, construct, construct_only,
631                 ctype,
632                 ))
633
634     def _introspect_signals(self, node, type_id):
635         for signal_info in cgobject.signal_list(type_id):
636             rtype = self._type_from_gtype(signal_info.return_type)
637             return_ = Return(rtype)
638             signal = GLibSignal(signal_info.signal_name, return_)
639             for i, parameter in enumerate(signal_info.get_params()):
640                 if i == 0:
641                     name = 'object'
642                 else:
643                     name = 'p%s' % (i-1, )
644                 ptype = self._type_from_gtype(parameter)
645                 param = Parameter(name, ptype)
646                 signal.parameters.append(param)
647             node.signals.append(signal)
648
649     # Resolver
650
651     def _resolve_type_name(self, type_name, ctype=None):
652         # Workaround glib bug #548689, to be included in 2.18.0
653         if type_name == "GParam":
654             type_name = "GObject.ParamSpec"
655
656         res = self._transformer.resolve_type_name_full
657         try:
658             return res(type_name, ctype, self._names)
659         except KeyError, e:
660             return self._transformer.resolve_type_name(type_name, ctype)
661
662     def _resolve_param_type(self, ptype, **kwargs):
663         return self._transformer.resolve_param_type_full(ptype,
664                                                          self._names,
665                                                          **kwargs)
666
667     def _resolve_node(self, node):
668         if isinstance(node, Function):
669             self._resolve_function_toplevel(node)
670
671         elif isinstance(node, Callback):
672             self._resolve_function(node)
673         elif isinstance(node, GLibObject):
674             self._resolve_glib_object(node)
675         elif isinstance(node, GLibInterface):
676             self._resolve_glib_interface(node)
677         elif isinstance(node, Struct):
678             self._resolve_struct(node)
679         elif isinstance(node, Union):
680             self._resolve_union(node)
681         elif isinstance(node, Alias):
682             self._resolve_alias(node)
683
684     def _resolve_function_toplevel(self, func):
685         newfunc = self._parse_constructor(func)
686         if not newfunc:
687             newfunc = self._parse_method(func)
688             if not newfunc:
689                 self._resolve_function(func)
690                 return
691         self._resolve_function(newfunc)
692
693     def _pair_boxed_type(self, boxed):
694         name = self._transformer.remove_prefix(boxed.type_name)
695         pair_node = self._get_attribute(name)
696         if not pair_node:
697             boxed_item = GLibBoxedOther(name, boxed.type_name,
698                                         boxed.get_type)
699         elif isinstance(pair_node, Struct):
700             boxed_item = GLibBoxedStruct(pair_node.name, boxed.type_name,
701                                          boxed.get_type)
702             boxed_item.fields = pair_node.fields
703         elif isinstance(pair_node, Union):
704             boxed_item = GLibBoxedUnion(pair_node.name, boxed.type_name,
705                                          boxed.get_type)
706             boxed_item.fields = pair_node.fields
707         else:
708             return False
709         self._add_attribute(boxed_item, replace=True)
710
711     def _resolve_struct(self, node):
712         for field in node.fields:
713             self._resolve_field(field)
714
715     def _resolve_union(self, node):
716         for field in node.fields:
717             self._resolve_field(field)
718
719     def _force_resolve(self, item, allow_unknown=False):
720         if isinstance(item, Unresolved):
721             if item.target in self._private_internal_types:
722                 return None
723             try:
724                 return self._transformer.gtypename_to_giname(item.target,
725                                                              self._names)
726             except KeyError, e:
727                 if allow_unknown:
728                     print "WARNING: Skipping unknown interface %s" % \
729                         (item.target, )
730                     return None
731                 else:
732                     raise
733         if item in self._private_internal_types:
734             return None
735         return item
736
737     def _resolve_glib_interface(self, node):
738         node.parent = self._force_resolve(node.parent)
739         self._resolve_methods(node.methods)
740         self._resolve_properties(node.properties, node)
741         self._resolve_signals(node.signals)
742
743     def _resolve_glib_object(self, node):
744         node.parent = self._force_resolve(node.parent)
745         node.interfaces = filter(None,
746             [self._force_resolve(x, allow_unknown=True)
747                                     for x in node.interfaces])
748         self._resolve_constructors(node.constructors)
749         self._resolve_methods(node.methods)
750         self._resolve_properties(node.properties, node)
751         self._resolve_signals(node.signals)
752         for field in node.fields:
753             self._resolve_field(field)
754
755     def _resolve_glib_boxed(self, node):
756         self._resolve_constructors(node.constructors)
757         self._resolve_methods(node.methods)
758
759     def _resolve_constructors(self, constructors):
760         for ctor in constructors:
761             self._resolve_function(ctor)
762
763     def _resolve_methods(self, methods):
764         for method in methods:
765             self._resolve_function(method)
766
767     def _resolve_signals(self, signals):
768         for signal in signals:
769             self._resolve_function(signal)
770
771     def _resolve_properties(self, properties, context):
772         failed = []
773         for prop in properties:
774             try:
775                 self._resolve_property(prop)
776             except KeyError, e:
777                 failed.append(prop)
778         for fail in failed:
779             print ("WARNING: Deleting object property %r (of %r) "
780                    "with unknown type") % (fail, context)
781             properties.remove(fail)
782
783     def _resolve_property(self, prop):
784         prop.type = self._resolve_param_type(prop.type, allow_invalid=False)
785
786     def _adjust_transfer(self, param):
787         # Do GLib/GObject-specific type transformations here
788
789         transfer = None
790         is_object = None
791         if hasattr(param.type, '_gtype'):
792             ftype = cgobject.type_fundamental(param.type._gtype)
793             assert ftype != cgobject.TYPE_INVALID, param.type._gtype
794
795             is_object = ftype in [cgobject.TYPE_OBJECT,
796                                   cgobject.TYPE_INTERFACE]
797
798             if ftype in [cgobject.TYPE_OBJECT,
799                          cgobject.TYPE_INTERFACE,
800                          cgobject.TYPE_STRING,
801                          cgobject.TYPE_BOXED,
802                          cgobject.TYPE_PARAM]:
803                 transfer = 'full'
804             else:
805                 # if type is a cgobject.TYPE_POINTER we could require direction
806                 # and transfer-ownership annotations
807                 transfer = 'none'
808
809         if is_object is None:
810             is_object = (param.type.name == 'GObject.Object' or
811                          (self._namespace_name == 'GObject' and
812                           param.type.name == 'Object'))
813
814         # Default to full transfer for GObjects
815         if isinstance(param, Parameter):
816             is_out = (param.direction != PARAM_DIRECTION_IN)
817         else:
818             is_out = True
819         if param.transfer is None or param.transfer_inferred:
820             if is_out and is_object:
821                 param.transfer = 'full'
822             elif transfer is not None:
823                 param.transfer = transfer
824
825     def _adjust_throws(self, func):
826         if func.parameters == []:
827             return
828
829         last_param = func.parameters.pop()
830
831         if (last_param.type.name == 'GLib.Error' or
832             (self._namespace_name == 'GLib' and
833              last_param.type.name == 'Error')):
834             func.throws = True
835         else:
836             func.parameters.append(last_param)
837
838     def _resolve_function(self, func):
839         self._resolve_parameters(func.parameters)
840         func.retval.type = self._resolve_param_type(func.retval.type)
841         self._adjust_throws(func)
842         self._adjust_transfer(func.retval)
843
844     def _resolve_parameters(self, parameters):
845         for parameter in parameters:
846             parameter.type = self._resolve_param_type(parameter.type)
847             self._adjust_transfer(parameter)
848
849     def _resolve_field(self, field):
850         if isinstance(field, Callback):
851             self._resolve_function(field)
852             return
853         field.type = self._resolve_param_type(field.type)
854
855     def _resolve_alias(self, alias):
856         alias.target = self._resolve_type_name(alias.target, alias.target)
857
858     # Validation
859
860     def _validate(self, nodes):
861         nodes = list(self._names.names.itervalues())
862         i = 0
863         self._validating = True
864         while True:
865             initlen = len(nodes)
866
867             print "Type resolution; pass=%d" % (i, )
868             nodes = list(self._names.names.itervalues())
869             for node in nodes:
870                 try:
871                     self._resolve_node(node)
872                 except UnknownTypeError, e:
873                     print "WARNING: %s: Deleting %r" % (e, node)
874                     self._remove_attribute(node.name)
875             if len(nodes) == initlen:
876                 break
877             i += 1
878             self._print_statistics()
879         self._validating = False