2 # GObject-Introspection - a framework for introspecting GObject libraries
3 # Copyright (C) 2008 Johan Dahlin
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.
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.
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.
28 from .ast import (Alias, Bitfield, Callback, Constant, Enum, Function, Member,
29 Namespace, Parameter, Property, Record, Return, Type, Union,
30 Field, VFunction, type_name_from_ctype,
31 default_array_types, TYPE_UINT8, PARAM_TRANSFER_FULL)
32 from .transformer import Names
33 from .glibast import (GLibBoxed, GLibEnum, GLibEnumMember, GLibFlags,
34 GLibInterface, GLibObject, GLibSignal, GLibBoxedStruct,
35 GLibBoxedUnion, GLibBoxedOther, GLibRecord,
37 from .utils import to_underscores, to_underscores_noprefix
39 default_array_types['guchar*'] = TYPE_UINT8
42 G_PARAM_READABLE = 1 << 0
43 G_PARAM_WRITABLE = 1 << 1
44 G_PARAM_CONSTRUCT = 1 << 2
45 G_PARAM_CONSTRUCT_ONLY = 1 << 3
46 G_PARAM_LAX_VALIDATION = 1 << 4
47 G_PARAM_STATIC_NAME = 1 << 5
48 G_PARAM_STATIC_NICK = 1 << 6
49 G_PARAM_STATIC_BLURB = 1 << 7
52 # These ones break GError conventions
53 'g_simple_async_result_new_from_error',
54 'g_simple_async_result_set_from_error',
55 'g_simple_async_result_propagate_error',
56 'g_simple_async_result_report_error_in_idle',
57 'gtk_print_operation_get_error',
60 SYMBOL_BLACKLIST_RE = [re.compile(x) for x in \
61 [r'\w+_marshal_[A-Z]+__', ]]
63 GET_TYPE_OVERRIDES = {
64 # this is a special case, from glibtransforer.py:create_gobject
65 'intern': 'g_object_get_type',
66 # this is presumably a typo, should be fixed upstream
67 'g_gstring_get_type': 'g_string_get_type',
68 # this is historical cruft: there's a deprecated
69 # #define gdk_window_get_type gdk_window_get_window_type
70 # upstream; this method can be renamed properly upstream once
71 # that deprecated alias is removed (in some future release)
72 'gdk_window_object_get_type': 'gdk_window_get_type',
76 class IntrospectionBinary(object):
78 def __init__(self, args, tmpdir=None):
81 self.tmpdir = tempfile.mkdtemp('', 'tmp-introspect')
86 class Unresolved(object):
88 def __init__(self, target):
92 class UnknownTypeError(Exception):
96 class GLibTransformer(object):
98 def __init__(self, transformer, noclosure=False):
99 self._transformer = transformer
100 self._noclosure = noclosure
101 self._namespace_name = None
102 self._names = Names()
103 self._uscore_type_names = {}
105 self._get_type_functions = []
106 self._error_quark_functions = []
107 self._gtype_data = {}
108 self._failed_types = {}
109 self._boxed_types = {}
110 self._private_internal_types = {}
111 self._validating = False
115 def _print_statistics(self):
116 nodes = list(self._names.names.itervalues())
118 def count_type(otype):
119 return len([x for x in nodes
120 if isinstance(x[1], otype)])
121 objectcount = count_type(GLibObject)
122 ifacecount = count_type(GLibInterface)
123 enumcount = count_type(GLibEnum)
124 print " %d nodes; %d objects, %d interfaces, %d enums" \
125 % (len(nodes), objectcount, ifacecount, enumcount)
127 def init_parse(self):
128 """Do parsing steps that don't involve the introspection binary
130 This does enough work that get_type_functions() can be called.
134 namespace = self._transformer.parse()
135 self._namespace_name = namespace.name
136 self._namespace_version = namespace.version
138 # First pass: parsing
139 for node in namespace.nodes:
140 self._parse_node(node)
142 # We don't want an alias for this - it's handled specially in
143 # the typelib compiler.
144 if namespace.name == 'GObject':
145 del self._names.aliases['Type']
147 def get_get_type_functions(self):
148 return self._get_type_functions
150 def set_introspection_binary(self, binary):
151 self._binary = binary
154 """Do remaining parsing steps requiring introspection binary"""
156 # Get all the GObject data by passing our list of get_type
157 # functions to the compiled binary
159 self._execute_binary()
161 # Introspection is done from within parsing
163 # Second pass: pair boxed structures
164 for boxed in self._boxed_types.itervalues():
165 self._pair_boxed_type(boxed)
166 # Third pass: delete class structures, resolve
167 # all types we now know about
168 nodes = list(self._names.names.itervalues())
169 for (ns, node) in nodes:
171 self._resolve_node(node)
173 #print "WARNING: DELETING node %s: %s" % (node.name, e)
174 self._remove_attribute(node.name)
175 # Another pass, since we need to have the methods parsed
176 # in order to correctly modify them after class/record
178 for (ns, node) in nodes:
179 # associate GtkButtonClass with GtkButton
180 if isinstance(node, Record):
181 self._pair_class_record(node)
182 for (ns, alias) in self._names.aliases.itervalues():
183 self._resolve_alias(alias)
184 self._resolve_quarks()
185 # Fourth pass: ensure all types are known
186 if not self._noclosure:
187 self._resolve_types(nodes)
189 #self._validate(nodes)
191 # Create a new namespace with what we found
192 namespace = Namespace(self._namespace_name, self._namespace_version)
193 namespace.nodes = map(lambda x: x[1], self._names.aliases.itervalues())
194 for (ns, x) in self._names.names.itervalues():
195 namespace.nodes.append(x)
200 def _add_attribute(self, node, replace=False):
201 node_name = node.name
202 if (not replace) and node_name in self._names.names:
204 self._names.names[node_name] = (None, node)
206 def _remove_attribute(self, name):
207 del self._names.names[name]
209 def _get_attribute(self, name):
210 node = self._names.names.get(name)
215 def _lookup_node(self, name):
216 if name in type_names:
218 node = self._get_attribute(name)
220 node = self._transformer.get_names().names.get(name)
225 def _get_no_uscore_prefixed_name(self, type_name):
226 # Besides the straight underscore conversion, we also try
227 # removing the underscores from the namespace as a possible C
228 # mapping; e.g. it's webkit_web_view, not web_kit_web_view
229 suffix = self._transformer.remove_prefix(type_name)
230 prefix = type_name[:-len(suffix)]
231 return (prefix + '_' + to_underscores(suffix)).lower()
233 def _register_internal_type(self, type_name, node):
234 self._names.type_names[type_name] = (None, node)
235 uscored = to_underscores(type_name).lower()
236 # prefer the prefix of the get_type method, if there is one
237 if hasattr(node, 'get_type'):
238 uscored = GET_TYPE_OVERRIDES.get(node.get_type, node.get_type)
239 uscored = uscored[:-len('_get_type')]
240 self._uscore_type_names[uscored] = node
242 no_uscore_prefixed = self._get_no_uscore_prefixed_name(type_name)
243 # since this is a guess, don't overwrite any 'real' prefix
244 if no_uscore_prefixed not in self._uscore_type_names:
245 self._uscore_type_names[no_uscore_prefixed] = node
247 def _resolve_quarks(self):
248 # self._uscore_type_names is an authoritative mapping of types
249 # to underscored versions, since it is based on get_type() methods;
250 # but only covers enums that are registered as GObject enums.
251 # Create a fallback mapping based on all known enums in this module.
253 for enum in self._transformer.iter_enums():
254 type_name = enum.symbol
255 uscored = to_underscores(type_name).lower()
257 uscore_enums[uscored] = enum
259 no_uscore_prefixed = self._get_no_uscore_prefixed_name(type_name)
260 if no_uscore_prefixed not in uscore_enums:
261 uscore_enums[no_uscore_prefixed] = enum
263 for node in self._error_quark_functions:
264 short = node.symbol[:-len('_quark')]
265 if short == "g_io_error":
266 # Special case; GIOError was already taken forcing GIOErrorEnum
267 enum = self._names.type_names["GIOErrorEnum"][1]
269 enum = self._uscore_type_names.get(short)
271 enum = uscore_enums.get(short)
273 enum.error_quark = node.symbol
275 print "WARNING: " + \
276 "Couldn't find corresponding enumeration for %s" % \
281 def _resolve_gtypename(self, gtype_name):
283 return self._transformer.gtypename_to_giname(gtype_name,
286 return Unresolved(gtype_name)
288 def _resolve_gtypename_chain(self, gtype_names):
289 """Like _resolve_gtypename, but grab the first one that resolves.
290 If none of them do, return an Unresolved for the first."""
291 for gtype_name in gtype_names:
293 return self._transformer.gtypename_to_giname(gtype_name,
297 return Unresolved(gtype_names[0])
299 def _execute_binary(self):
300 in_path = os.path.join(self._binary.tmpdir, 'types.txt')
301 f = open(in_path, 'w')
302 # TODO: Introspect GQuark functions
303 for func in self._get_type_functions:
307 out_path = os.path.join(self._binary.tmpdir, 'dump.xml')
310 args.extend(self._binary.args)
311 args.append('--introspect-dump=%s,%s' % (in_path, out_path))
313 # Invoke the binary, having written our get_type functions to types.txt
315 subprocess.check_call(args, stdout=sys.stdout, stderr=sys.stderr)
316 except subprocess.CalledProcessError, e:
318 self._read_introspect_dump(out_path)
320 # Clean up temporaries
321 shutil.rmtree(self._binary.tmpdir)
323 def _read_introspect_dump(self, xmlpath):
324 from xml.etree.cElementTree import parse
325 tree = parse(xmlpath)
326 root = tree.getroot()
328 self._gtype_data[child.attrib['name']] = child
330 self._introspect_type(child)
332 def _create_gobject(self, node):
333 type_name = 'G' + node.name
334 if type_name == 'GObject':
337 elif type_name == 'GInitiallyUnowned':
338 parent_type_name = 'GObject'
339 parent_gitype = self._resolve_gtypename(parent_type_name)
340 symbol = 'g_initially_unowned_get_type'
343 gnode = GLibObject(node.name, parent_gitype, type_name, symbol, True)
344 if type_name == 'GObject':
345 gnode.fields.extend(node.fields)
347 # http://bugzilla.gnome.org/show_bug.cgi?id=569408
348 # GInitiallyUnowned is actually a typedef for GObject, but
349 # that's not reflected in the GIR, where it appears as a
350 # subclass (as it appears in the GType hierarchy). So
351 # what we do here is copy all of the GObject fields into
352 # GInitiallyUnowned so that struct offset computation
354 gnode.fields = self._names.names['Object'][1].fields
355 self._add_attribute(gnode)
356 self._register_internal_type(type_name, gnode)
360 def _parse_node(self, node):
361 if isinstance(node, Enum):
362 self._parse_enum(node)
363 elif isinstance(node, Bitfield):
364 self._parse_bitfield(node)
365 elif isinstance(node, Function):
366 self._parse_function(node)
367 elif isinstance(node, Record):
368 self._parse_record(node)
369 elif isinstance(node, Callback):
370 self._parse_callback(node)
371 elif isinstance(node, Alias):
372 self._parse_alias(node)
373 elif isinstance(node, Member):
374 # FIXME: atk_misc_instance singletons
376 elif isinstance(node, Union):
377 self._parse_union(node)
378 elif isinstance(node, Constant):
379 self._parse_constant(node)
381 print 'GLIB Transformer: Unhandled node:', node
383 def _parse_alias(self, alias):
384 self._names.aliases[alias.name] = (None, alias)
386 def _parse_enum(self, enum):
387 self._add_attribute(enum)
389 def _parse_bitfield(self, enum):
390 self._add_attribute(enum)
392 def _parse_constant(self, constant):
393 self._add_attribute(constant)
395 def _parse_function(self, func):
396 if func.symbol in SYMBOL_BLACKLIST:
398 if func.symbol.startswith('_'):
400 for regexp in SYMBOL_BLACKLIST_RE:
401 if regexp.match(func.symbol):
403 if self._parse_get_type_function(func):
405 if self._parse_error_quark_function(func):
408 self._add_attribute(func)
410 def _parse_get_type_function(self, func):
412 if not symbol.endswith('_get_type'):
414 if self._namespace_name == 'GLib':
415 # No GObjects in GLib
417 if (self._namespace_name == 'GObject' and
418 symbol in ('g_object_get_type', 'g_initially_unowned_get_type')):
419 # We handle these internally, see _create_gobject
423 # GType *_get_type(void)
424 if func.retval.type.name not in ['Type',
428 print ("Warning: *_get_type function returns '%r'"
429 ", not GObject.Type") % (func.retval.type.name, )
432 self._get_type_functions.append(symbol)
435 def _parse_error_quark_function(self, func):
436 if not func.symbol.endswith('_error_quark'):
440 if (func.retval.type.name != 'GLib.Quark' and
441 func.retval.type.ctype != 'GQuark'):
444 self._error_quark_functions.append(func)
447 def _name_is_internal_gtype(self, giname):
449 node = self._get_attribute(giname)
450 return isinstance(node, (GLibObject, GLibInterface,
451 GLibBoxed, GLibEnum, GLibFlags))
455 def _parse_static_method(self, func):
456 components = func.symbol.split('_')
457 if len(components) < 2:
460 prefix_components = None
462 for i in xrange(1, len(components)):
463 prefix_components = '_'.join(components[0:-i])
464 methname = '_'.join(components[-i:])
465 target_klass = self._uscore_type_names.get(prefix_components)
466 if target_klass and isinstance(target_klass, GLibObject):
471 self._remove_attribute(func.name)
473 target_klass.static_methods.append(func)
474 func.is_method = True
477 def _parse_method(self, func):
478 if not func.parameters:
480 return self._parse_method_common(func, True)
482 def _parse_constructor(self, func):
483 return self._parse_method_common(func, False)
485 def _parse_method_common(self, func, is_method):
486 # Skip _get_type functions, we processed them
488 if func.symbol.endswith('_get_type'):
490 if self._namespace_name == 'GLib':
491 # No GObjects in GLib
495 target_arg = func.retval
497 target_arg = func.parameters[0]
500 # Methods require their first arg to be a known class
501 # Look at the original C type (before namespace stripping), without
502 # pointers: GtkButton -> gtk_button_, so we can figure out the
504 argtype = target_arg.type.ctype.replace('*', '')
505 name = self._transformer.remove_prefix(argtype)
506 name_uscore = to_underscores_noprefix(name).lower()
507 # prefer the prefix of the _get_type method, if there is one
508 if argtype in self._names.type_names:
509 node = self._names.type_names[argtype][1]
510 if hasattr(node, 'get_type'):
511 name_uscore = GET_TYPE_OVERRIDES.get(node.get_type,
513 name_uscore = name_uscore[:-len('_get_type')]
514 name_offset = func.symbol.find(name_uscore)
517 prefix = func.symbol[:name_offset+len(name_uscore)]
519 # Constructors must have _new
520 # Take everything before that as class name
521 new_idx = func.symbol.find('_new')
524 # Constructors don't return basic types
525 derefed = self._transformer.follow_aliases(target_arg.type.name,
527 if derefed in type_names:
528 #print "NOTE: Rejecting constructor returning basic: %r" \
531 prefix = func.symbol[:new_idx]
533 klass = self._uscore_type_names.get(prefix)
535 #print "NOTE: No valid matching class for likely "+\
536 # "method or constructor: %r" % (func.symbol, )
538 # Enums can't have ctors or methods
539 if isinstance(klass, (GLibEnum, GLibFlags)):
542 # The _uscore_type_names member holds the plain GLibBoxed
543 # object; we want to actually use the struct/record associated
544 if isinstance(klass, (Record, Union)):
545 remove_prefix = klass.symbol
547 remove_prefix = klass.type_name
549 name = self._transformer.remove_prefix(remove_prefix)
550 klass = self._get_attribute(name)
555 # Interfaces can't have constructors, punt to global scope
556 if isinstance(klass, GLibInterface):
557 #print "NOTE: Rejecting constructor for"+\
558 # " interface type: %r" % (func.symbol, )
560 # TODO - check that the return type is a subclass of the
561 # class from the prefix
562 # But for now, ensure that constructor returns are always
563 # the most concrete class
564 name = self._transformer.remove_prefix(remove_prefix)
565 func.retval.type = Type(name, func.retval.type.ctype)
567 self._remove_attribute(func.name)
568 # Strip namespace and object prefix: gtk_window_new -> new
569 func.name = func.symbol[len(prefix)+1:]
571 # We don't need the "this" parameter
572 del func.parameters[0]
573 klass.methods.append(func)
574 func.is_method = True
576 klass.constructors.append(func)
579 def _parse_record(self, record):
580 # This is a hack, but GObject is a rather fundamental piece so.
581 internal_names = ["Object", 'InitiallyUnowned']
582 g_internal_names = ["G" + x for x in internal_names]
583 if (self._namespace_name == 'GObject' and
584 record.name in internal_names):
585 self._create_gobject(record)
587 elif record.name in g_internal_names:
590 if record.name == 'InitiallyUnownedClass':
591 record.fields = self._names.names['ObjectClass'][1].fields
592 node = self._names.names.get(record.name)
594 self._add_attribute(record, replace=True)
595 self._register_internal_type(record.symbol, record)
598 node.fields = record.fields[:]
600 def _parse_union(self, union):
601 node = self._names.names.get(union.name)
603 self._add_attribute(union, replace=True)
604 self._register_internal_type(union.symbol, union)
607 node.fields = union.fields[:]
609 def _parse_callback(self, callback):
610 self._add_attribute(callback)
612 def _strip_class_suffix(self, name):
613 if (name.endswith('Class') or
614 name.endswith('Iface')):
616 elif name.endswith('Interface'):
621 def _arg_is_failed(self, param):
622 ctype = self._transformer.ctype_of(param).replace('*', '')
623 uscored = to_underscores(self._strip_class_suffix(ctype)).lower()
624 if uscored in self._failed_types:
625 print "Warning: failed type: %r" % (param, )
629 def _pair_class_record(self, maybe_class):
630 name = self._strip_class_suffix(maybe_class.name)
631 if name == maybe_class.name:
634 class_struct = maybe_class
635 if self._arg_is_failed(class_struct):
636 print "WARNING: deleting no-type %r" % (class_struct.name, )
637 del self._names.names[class_struct.name]
640 pair_class = self._get_attribute(name)
641 if (not pair_class or
642 not isinstance(pair_class, (GLibObject, GLibInterface))):
645 # Object class fields are assumed to be read-only
646 # (see also _introspect_object and transformer.py)
647 for field in maybe_class.fields:
648 if isinstance(field, Field):
649 field.writable = False
651 # Loop through fields to determine which are virtual
652 # functions and which are signal slots by
653 # assuming everything that doesn't share a name
654 # with a known signal is a virtual slot.
655 for field in maybe_class.fields:
656 if not isinstance(field, Callback):
658 # Check the first parameter is the object
659 if len(field.parameters) == 0:
661 firstparam_type = field.parameters[0].type
662 if firstparam_type != pair_class:
664 # Also double check we don't have a signal with this
666 matched_signal = False
667 for signal in pair_class.signals:
668 if signal.name.replace('-', '_') == field.name:
669 matched_signal = True
673 vfunc = VFunction.from_callback(field)
674 pair_class.virtual_methods.append(vfunc)
676 # Take the set of virtual methods we found, and try
677 # to pair up with any matching methods using the
679 for vfunc in pair_class.virtual_methods:
680 for method in pair_class.methods:
681 if (method.name != vfunc.name or
682 method.retval != vfunc.retval or
683 method.parameters != vfunc.parameters):
685 vfunc.invoker = method.name
687 gclass_struct = GLibRecord.from_record(class_struct)
688 self._remove_attribute(class_struct.name)
689 self._add_attribute(gclass_struct, True)
690 pair_class.glib_type_struct = gclass_struct
691 gclass_struct.is_gtype_struct_for = name
695 def _introspect_type(self, xmlnode):
696 if xmlnode.tag in ('enum', 'flags'):
697 self._introspect_enum(xmlnode)
698 elif xmlnode.tag == 'class':
699 self._introspect_object(xmlnode)
700 elif xmlnode.tag == 'interface':
701 self._introspect_interface(xmlnode)
702 elif xmlnode.tag == 'boxed':
703 self._introspect_boxed(xmlnode)
705 raise ValueError("Unhandled introspection XML tag %s", xmlnode.tag)
707 def _introspect_enum(self, node):
709 for member in node.findall('member'):
710 # Keep the name closer to what we'd take from C by default;
711 # see http://bugzilla.gnome.org/show_bug.cgi?id=575613
712 name = member.attrib['nick'].replace('-', '_')
713 members.append(GLibEnumMember(name,
714 member.attrib['value'],
715 member.attrib['name'],
716 member.attrib['nick']))
718 klass = (GLibFlags if node.tag == 'flags' else GLibEnum)
719 type_name = node.attrib['name']
720 enum_name = self._transformer.remove_prefix(type_name)
721 node = klass(enum_name, type_name, members, node.attrib['get-type'])
722 self._add_attribute(node, replace=True)
723 self._register_internal_type(type_name, node)
725 def _introspect_object(self, xmlnode):
726 type_name = xmlnode.attrib['name']
727 # We handle this specially above; in 2.16 and below there
728 # was no g_object_get_type, for later versions we need
730 if type_name == 'GObject':
732 # Get a list of parents here; some of them may be hidden, and what
733 # we really want to do is use the most-derived one that we know of.
735 parent_type_names = xmlnode.attrib['parents'].split(',')
736 parent_gitype = self._resolve_gtypename_chain(parent_type_names)
737 is_abstract = not not xmlnode.attrib.get('abstract', False)
739 self._transformer.remove_prefix(type_name),
742 xmlnode.attrib['get-type'], is_abstract)
743 self._introspect_properties(node, xmlnode)
744 self._introspect_signals(node, xmlnode)
745 self._introspect_implemented_interfaces(node, xmlnode)
748 record = self._get_attribute(node.name)
749 if record is not None:
750 node.fields = record.fields
751 for field in node.fields:
752 if isinstance(field, Field):
753 # Object instance fields are assumed to be read-only
754 # (see also _pair_class_record and transformer.py)
755 field.writable = False
757 self._add_attribute(node, replace=True)
758 self._register_internal_type(type_name, node)
760 def _introspect_interface(self, xmlnode):
761 type_name = xmlnode.attrib['name']
762 node = GLibInterface(
763 self._transformer.remove_prefix(type_name),
765 type_name, xmlnode.attrib['get-type'])
766 self._introspect_properties(node, xmlnode)
767 self._introspect_signals(node, xmlnode)
768 for child in xmlnode.findall('prerequisite'):
769 name = child.attrib['name']
770 prereq = self._resolve_gtypename(name)
771 node.prerequisites.append(prereq)
772 # GtkFileChooserEmbed is an example of a private interface, we
773 # just filter them out
774 if xmlnode.attrib['get-type'].startswith('_'):
775 print "NOTICE: Marking %s as internal type" % (type_name, )
776 self._private_internal_types[type_name] = node
778 self._add_attribute(node, replace=True)
779 self._register_internal_type(type_name, node)
781 def _introspect_boxed(self, xmlnode):
782 type_name = xmlnode.attrib['name']
783 # This one doesn't go in the main namespace; we associate it with
784 # the struct or union
785 node = GLibBoxed(type_name, xmlnode.attrib['get-type'])
786 self._boxed_types[node.type_name] = node
787 self._register_internal_type(type_name, node)
789 def _introspect_implemented_interfaces(self, node, xmlnode):
791 for interface in xmlnode.findall('implements'):
792 gitype = self._resolve_gtypename(interface.attrib['name'])
793 gt_interfaces.append(gitype)
794 node.interfaces = sorted(gt_interfaces)
796 def _introspect_properties(self, node, xmlnode):
797 for pspec in xmlnode.findall('property'):
798 ctype = pspec.attrib['type']
799 flags = int(pspec.attrib['flags'])
800 readable = (flags & G_PARAM_READABLE) != 0
801 writable = (flags & G_PARAM_WRITABLE) != 0
802 construct = (flags & G_PARAM_CONSTRUCT) != 0
803 construct_only = (flags & G_PARAM_CONSTRUCT_ONLY) != 0
804 node.properties.append(Property(
805 pspec.attrib['name'],
806 type_name_from_ctype(ctype),
807 readable, writable, construct, construct_only,
810 node.properties = sorted(node.properties)
812 def _introspect_signals(self, node, xmlnode):
813 for signal_info in xmlnode.findall('signal'):
814 rctype = signal_info.attrib['return']
815 rtype = Type(self._transformer.parse_ctype(rctype), rctype)
816 return_ = Return(rtype, signal_info.attrib['return'])
817 return_.transfer = PARAM_TRANSFER_FULL
818 signal = GLibSignal(signal_info.attrib['name'], return_)
819 for i, parameter in enumerate(signal_info.findall('param')):
823 name = 'p%s' % (i-1, )
824 pctype = parameter.attrib['type']
825 ptype = Type(self._transformer.parse_ctype(pctype), pctype)
826 param = Parameter(name, ptype)
827 param.transfer = 'none'
828 signal.parameters.append(param)
829 node.signals.append(signal)
830 node.signals = sorted(node.signals)
834 def _resolve_type_name(self, type_name, ctype=None):
835 # Workaround glib bug #548689, to be included in 2.18.0
836 if type_name == "GParam":
837 type_name = "GObject.ParamSpec"
838 res = self._transformer.resolve_type_name_full
840 return res(type_name, ctype, self._names)
842 return self._transformer.resolve_type_name(type_name, ctype)
844 def _resolve_param_type(self, ptype, **kwargs):
845 # Workaround glib bug #548689, to be included in 2.18.0
846 if ptype.name == "GParam":
847 ptype.name = "GObject.ParamSpec"
848 return self._transformer.resolve_param_type_full(ptype,
852 def _resolve_node(self, node):
853 if isinstance(node, Function):
854 self._resolve_function_toplevel(node)
856 elif isinstance(node, Callback):
857 self._resolve_function(node)
858 elif isinstance(node, GLibObject):
859 self._resolve_glib_object(node)
860 elif isinstance(node, GLibInterface):
861 self._resolve_glib_interface(node)
862 elif isinstance(node, Record):
863 self._resolve_record(node)
864 elif isinstance(node, Union):
865 self._resolve_union(node)
866 elif isinstance(node, Alias):
867 self._resolve_alias(node)
869 def _resolve_function_toplevel(self, func):
870 for parser in [self._parse_constructor,
872 self._parse_static_method]:
873 newfunc = parser(func)
875 self._resolve_function(newfunc)
877 self._resolve_function(func)
879 def _pair_boxed_type(self, boxed):
880 name = self._transformer.remove_prefix(boxed.type_name)
881 pair_node = self._get_attribute(name)
883 boxed_item = GLibBoxedOther(name, boxed.type_name,
885 elif isinstance(pair_node, Record):
886 boxed_item = GLibBoxedStruct(pair_node.name, boxed.type_name,
888 boxed_item.fields = pair_node.fields
889 elif isinstance(pair_node, Union):
890 boxed_item = GLibBoxedUnion(pair_node.name, boxed.type_name,
892 boxed_item.fields = pair_node.fields
895 self._add_attribute(boxed_item, replace=True)
897 def _resolve_record(self, node):
898 for field in node.fields:
899 self._resolve_field(field)
901 def _resolve_union(self, node):
902 for field in node.fields:
903 self._resolve_field(field)
905 def _force_resolve(self, item, allow_unknown=False):
906 if isinstance(item, Unresolved):
907 if item.target in self._private_internal_types:
910 return self._transformer.gtypename_to_giname(item.target,
914 print "WARNING: Skipping unknown interface %s" % \
919 if item in self._private_internal_types:
923 def _resolve_glib_interface(self, node):
924 node.parent = self._force_resolve(node.parent)
925 self._resolve_methods(node.methods)
926 self._resolve_properties(node.properties, node)
927 self._resolve_signals(node.signals)
928 node.prerequisites = filter(None,
929 [self._force_resolve(x, allow_unknown=True)
930 for x in node.prerequisites])
932 def _resolve_glib_object(self, node):
933 # If we can't find the parent class, just drop back to GObject.
934 # This supports hidden parent classes.
935 # http://bugzilla.gnome.org/show_bug.cgi?id=561360
937 node.parent = self._force_resolve(node.parent)
939 #print ("WARNING: Parent %r of class %r" +\
940 # " not found; using GObject") % (node.parent.target,
942 node.parent = self._transformer.gtypename_to_giname("GObject",
944 node.interfaces = filter(None,
945 [self._force_resolve(x, allow_unknown=True)
946 for x in node.interfaces])
947 self._resolve_constructors(node.constructors)
948 self._resolve_methods(node.methods)
949 self._resolve_methods(node.static_methods)
950 self._resolve_properties(node.properties, node)
951 self._resolve_signals(node.signals)
952 for field in node.fields:
953 self._resolve_field(field)
955 def _resolve_glib_boxed(self, node):
956 self._resolve_constructors(node.constructors)
957 self._resolve_methods(node.methods)
959 def _resolve_constructors(self, constructors):
960 for ctor in constructors:
961 self._resolve_function(ctor)
963 def _resolve_methods(self, methods):
964 for method in methods:
965 self._resolve_function(method)
967 def _resolve_signals(self, signals):
968 for signal in signals:
969 self._resolve_function(signal)
971 def _resolve_properties(self, properties, context):
973 for prop in properties:
975 self._resolve_property(prop)
979 #print ("WARNING: Deleting object property %r (of %r) "
980 # "with unknown type") % (fail, context)
981 properties.remove(fail)
983 def _resolve_property(self, prop):
984 prop.type = self._resolve_param_type(prop.type, allow_invalid=False)
986 def _adjust_throws(self, func):
987 if func.parameters == []:
990 last_param = func.parameters.pop()
992 # Checking type.name=='GLib.Error' generates false positives
993 # on methods that take a 'GError *'
994 if last_param.type.ctype == 'GError**':
997 func.parameters.append(last_param)
999 def _resolve_function(self, func):
1000 self._resolve_parameters(func.parameters)
1001 func.retval.type = self._resolve_param_type(func.retval.type)
1002 self._adjust_throws(func)
1004 def _resolve_parameters(self, parameters):
1005 for parameter in parameters:
1006 parameter.type = self._resolve_param_type(parameter.type)
1008 def _resolve_field(self, field):
1009 if isinstance(field, Callback):
1010 self._resolve_function(field)
1011 elif isinstance(field, Record): # non-typedef'd struct
1012 self._resolve_record(field)
1013 elif isinstance(field, Union): # non-typedef'd union
1014 self._resolve_union(field)
1016 field.type = self._resolve_param_type(field.type)
1018 def _resolve_alias(self, alias):
1019 alias.target = self._resolve_type_name(alias.target, alias.target)
1021 def _resolve_types(self, nodes):
1022 nodes = list(self._names.names.itervalues())
1024 self._validating = True
1026 initlen = len(nodes)
1028 #print "Type resolution; pass=%d" % (i, )
1029 nodes = list(self._names.names.itervalues())
1032 self._resolve_node(node)
1033 except UnknownTypeError, e:
1034 print "WARNING: %s: Deleting %r" % (e, node)
1035 self._remove_attribute(node.name)
1036 if len(nodes) == initlen:
1039 self._print_statistics()
1040 self._validating = False
1044 def _validate_interface(self, iface):
1045 for vfunc in iface.virtual_methods:
1046 if not vfunc.invoker:
1047 print ("warning: Interface %r virtual function %r " + \
1048 "has no known invoker") % (iface.name, vfunc.name)
1050 # This function is called at the very end, before we hand back the
1051 # completed namespace to the writer. Add static analysis checks here.
1052 def _validate(self, nodes):
1053 for (name, node) in nodes:
1054 if isinstance(node, GLibInterface):
1055 self._validate_interface(node)