2 # GObject-Introspection - a framework for introspecting GObject libraries
3 # Copyright (C) 2008 Johan Dahlin
5 # This program is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU General Public License
7 # as published by the Free Software Foundation; either version 2
8 # of the License, or (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
25 from . import cgobject
26 from .odict import odict
27 from .ast import (Callback, Enum, Function, Member, Namespace, Parameter,
28 Property, Return, Sequence, Struct, Field, Type, Alias,
30 from .glibast import (GLibBoxed, GLibEnum, GLibEnumMember, GLibFlags,
31 GLibInterface, GLibObject, GLibSignal)
32 from .utils import extract_libtool, to_underscores
35 class GLibTransformer(object):
37 def __init__(self, transformer):
38 self._transformer = transformer
39 self._namespace_name = None
41 self._output_ns = odict()
43 self._internal_types = {}
47 def add_library(self, libname):
48 if libname.endswith('.la'):
49 libname = extract_libtool(libname)
50 self._libraries.append(ctypes.cdll.LoadLibrary(libname))
53 namespace = self._transformer.parse()
54 self._namespace_name = namespace.name
57 for node in namespace.nodes:
58 self._parse_node(node)
60 # Introspection is done from within parsing
62 # Second pass, resolving types
63 for node in self._output_ns.values():
64 # associate GtkButtonClass with GtkButton
65 if isinstance(node, Struct):
66 self._pair_class_struct(node)
67 self._resolve_node(node)
69 # Create a new namespace with what we found
70 namespace = Namespace(namespace.name)
71 namespace.nodes = self._aliases + self._output_ns.values()
76 def _add_attribute(self, node, replace=False):
78 if node_name in self._output_ns and not replace:
80 self._output_ns[node_name] = node
82 def _remove_attribute(self, name):
83 del self._output_ns[name]
85 def _get_attribute(self, name):
86 return self._output_ns.get(name)
88 def _register_internal_type(self, type_name, node):
89 self._internal_types[type_name] = node
93 def _create_type(self, type_id):
94 ctype = cgobject.type_name(type_id)
95 type_name = type_name_from_ctype(ctype)
96 return Type(type_name, ctype)
98 def _create_gobject(self, node):
99 type_name = 'G' + node.name
100 if type_name == 'GObject':
101 parent_type_name = None
104 type_id = cgobject.type_from_name(type_name)
105 parent_type_name = cgobject.type_name(
106 cgobject.type_parent(type_id))
107 symbol = to_underscores(type_name).lower() + '_get_type'
108 node = GLibObject(node.name, parent_type_name, type_name, symbol)
109 type_id = cgobject.TYPE_OBJECT
110 self._introspect_properties(node, type_id)
111 self._introspect_signals(node, type_id)
112 self._add_attribute(node)
113 self._register_internal_type(type_name, node)
117 def _parse_node(self, node):
118 if isinstance(node, Enum):
119 self._parse_enum(node)
120 elif isinstance(node, Function):
121 self._parse_function(node)
122 elif isinstance(node, Struct):
123 self._parse_struct(node)
124 elif isinstance(node, Callback):
125 self._parse_callback(node)
126 elif isinstance(node, Alias):
127 self._parse_alias(node)
128 elif isinstance(node, Member):
129 # FIXME: atk_misc_instance singletons
132 print 'GOBJECT BUILDER: Unhandled node:', node
134 def _parse_alias(self, alias):
135 self._aliases.append(alias)
137 def _parse_enum(self, enum):
138 self._add_attribute(enum)
140 def _parse_function(self, func):
141 if self._parse_get_type_function(func):
143 elif self._parse_constructor(func):
145 elif self._parse_method(func):
148 self._add_attribute(func)
150 def _parse_get_type_function(self, func):
151 if not self._libraries:
153 # GType *_get_type(void)
155 if not symbol.endswith('_get_type'):
157 if func.retval.type.name != 'GObject.GType':
162 for library in self._libraries:
164 func = getattr(library, symbol)
166 except AttributeError:
169 print 'Warning: could not find symbol: %s' % symbol
172 func.restype = cgobject.GType
175 self._introspect_type(type_id, symbol)
178 def _parse_method(self, func):
179 if not func.parameters:
182 # FIXME: This is hackish, we should preserve the pointer structures
183 # here, so we can find pointers to objects and not just
184 # pointers to anything
185 first_arg = func.parameters[0].type.name
186 if first_arg.count('*') != 1:
189 object_name = first_arg.replace('*', '')
190 return self._parse_method_common(func, object_name, is_method=True)
192 def _parse_constructor(self, func):
193 # FIXME: This is hackish, we should preserve the pointer structures
194 # here, so we can find pointers to objects and not just
195 # pointers to anything
196 rtype = func.retval.type
197 if rtype.name.count('*') != 1:
200 object_name = rtype.name.replace('*', '')
201 return self._parse_method_common(func, object_name, is_method=False)
203 def _parse_method_common(self, func, object_name, is_method):
204 orig_name = object_name
205 if object_name.lower().startswith(self._namespace_name.lower()):
206 object_name = object_name[len(self._namespace_name):]
207 class_ = self._get_attribute(object_name)
208 if class_ is None or not isinstance(class_, (GLibObject, GLibBoxed)):
211 # GtkButton -> gtk_button_, so we can figure out the method name
212 prefix = to_underscores(orig_name).lower() + '_'
213 if not func.symbol.startswith(prefix):
216 # Strip namespace and object prefix: gtk_window_new -> new
217 func.name = func.symbol[len(prefix):]
219 class_.methods.append(func)
221 class_.constructors.append(func)
224 def _parse_struct(self, struct):
225 # This is a hack, but GObject is a rather fundamental piece so.
226 if (self._namespace_name == 'GObject' and
227 struct.name in ["Object", 'InitiallyUnowned']):
228 self._create_gobject(struct)
230 node = self._output_ns.get(struct.name)
232 self._add_attribute(struct, replace=True)
234 node.fields = struct.fields[:]
236 def _parse_callback(self, callback):
237 self._add_attribute(callback)
239 def _pair_class_struct(self, class_node):
240 name = class_node.name
241 if (name.endswith('Class') or
242 name.endswith('Iface')):
244 elif name.endswith('Interface'):
249 node = self._output_ns.get(self._resolve_type_name(name))
250 del self._output_ns[class_node.name]
253 for field in class_node.fields[1:]:
254 node.fields.append(field)
258 def _introspect_type(self, type_id, symbol):
259 fundamental_type_id = cgobject.type_fundamental(type_id)
260 if (fundamental_type_id == cgobject.TYPE_ENUM or
261 fundamental_type_id == cgobject.TYPE_FLAGS):
262 self._introspect_enum(fundamental_type_id, type_id, symbol)
263 elif fundamental_type_id == cgobject.TYPE_OBJECT:
264 self._introspect_object(type_id, symbol)
265 elif fundamental_type_id == cgobject.TYPE_INTERFACE:
266 self._introspect_interface(type_id, symbol)
267 elif fundamental_type_id == cgobject.TYPE_BOXED:
268 self._introspect_boxed(type_id, symbol)
270 print 'unhandled GType: %s' % (cgobject.type_name(type_id), )
272 def _introspect_enum(self, ftype_id, type_id, symbol):
273 type_class = cgobject.type_class_ref(type_id)
274 if type_class is None:
278 for enum_value in type_class.get_values():
279 members.append(GLibEnumMember(enum_value.value_nick,
281 enum_value.value_name,
282 enum_value.value_nick))
284 klass = (GLibFlags if ftype_id == cgobject.TYPE_FLAGS else GLibEnum)
285 type_name = cgobject.type_name(type_id)
286 enum_name = self._transformer.strip_namespace_object(type_name)
287 node = klass(enum_name, type_name, members, symbol)
288 self._add_attribute(node, replace=True)
289 self._register_internal_type(type_name, node)
291 def _introspect_object(self, type_id, symbol):
292 type_name = cgobject.type_name(type_id)
293 parent_type_name = cgobject.type_name(cgobject.type_parent(type_id))
295 self._transformer.strip_namespace_object(type_name),
296 self._resolve_type_name(parent_type_name),
298 self._introspect_properties(node, type_id)
299 self._introspect_signals(node, type_id)
300 self._add_attribute(node)
302 self._remove_attribute(type_name)
304 print 'Warning: could not remove %s' % type_name
306 self._register_internal_type(type_name, node)
308 def _introspect_interface(self, type_id, symbol):
309 type_name = cgobject.type_name(type_id)
310 parent_type_name = cgobject.type_name(cgobject.type_parent(type_id))
311 node = GLibInterface(
312 self._transformer.strip_namespace_object(type_name),
313 self._resolve_type_name(parent_type_name),
315 self._introspect_properties(node, type_id)
316 self._introspect_signals(node, type_id)
317 self._add_attribute(node)
318 self._register_internal_type(type_name, node)
320 def _introspect_boxed(self, type_id, symbol):
321 type_name = cgobject.type_name(type_id)
322 node = GLibBoxed(self._transformer.strip_namespace_object(type_name),
324 self._add_attribute(node)
325 # GdkEvent raises KeyError, FooBoxed ends up duplicated if we don't
327 self._remove_attribute(type_name)
330 self._register_internal_type(type_name, node)
332 def _introspect_properties(self, node, type_id):
333 fundamental_type_id = cgobject.type_fundamental(type_id)
334 if fundamental_type_id == cgobject.TYPE_OBJECT:
335 pspecs = cgobject.object_class_list_properties(type_id)
336 elif fundamental_type_id == cgobject.TYPE_INTERFACE:
337 pspecs = cgobject.object_interface_list_properties(type_id)
342 if pspec.owner_type != type_id:
344 ctype = cgobject.type_name(pspec.value_type)
345 node.properties.append(Property(
347 type_name_from_ctype(ctype),
351 def _introspect_signals(self, node, type_id):
352 for signal_info in cgobject.signal_list(type_id):
353 rtype = self._create_type(signal_info.return_type)
354 return_ = Return(rtype)
355 signal = GLibSignal(signal_info.signal_name, return_)
356 for i, parameter in enumerate(signal_info.get_params()):
360 name = 'p%s' % (i-1, )
361 ptype = self._create_type(parameter)
362 param = Parameter(name, ptype)
363 signal.parameters.append(param)
364 node.signals.append(signal)
368 def _resolve_type_name(self, type_name):
369 type_name = type_name.replace('*', '')
370 possible_name = self._transformer.resolve_type_name(type_name)
371 if possible_name != type_name:
373 possible_node = self._internal_types.get(type_name)
375 return possible_node.name
378 def _resolve_param_type(self, ptype):
379 ptype.name = ptype.name.replace('*', '')
380 type_name = ptype.name
381 type_name = self._transformer.resolve_possible_typedef(type_name)
382 possible_node = self._internal_types.get(type_name)
384 ptype.name = possible_node.name
386 ptype = self._transformer.resolve_param_type(ptype)
389 def _resolve_node(self, node):
390 if isinstance(node, (Callback, Function)):
391 self._resolve_function(node)
392 elif isinstance(node, GLibObject):
393 self._resolve_glib_object(node)
394 elif isinstance(node, GLibInterface):
395 self._resolve_glib_interface(node)
396 elif isinstance(node, GLibBoxed):
397 self._resolve_glib_boxed(node)
398 elif isinstance(node, Struct):
399 self._resolve_struct(node)
401 def _resolve_struct(self, node):
402 for field in node.fields:
403 self._resolve_field(field)
405 def _resolve_glib_interface(self, node):
406 self._resolve_methods(node.methods)
407 self._resolve_properties(node.properties)
408 self._resolve_signals(node.signals)
410 def _resolve_glib_object(self, node):
411 self._resolve_constructors(node.constructors)
412 self._resolve_methods(node.methods)
413 self._resolve_properties(node.properties)
414 self._resolve_signals(node.signals)
416 def _resolve_glib_boxed(self, node):
417 self._resolve_constructors(node.constructors)
418 self._resolve_methods(node.methods)
420 def _resolve_constructors(self, constructors):
421 for ctor in constructors:
422 self._resolve_function(ctor)
424 def _resolve_methods(self, methods):
425 for method in methods:
426 self._resolve_function(method)
428 def _resolve_signals(self, signals):
429 for signal in signals:
430 self._resolve_function(signal)
432 def _resolve_properties(self, properties):
433 for prop in properties:
434 self._resolve_property(prop)
436 def _resolve_property(self, prop):
437 prop.type = self._resolve_param_type(prop.type)
439 def _resolve_function(self, func):
440 self._resolve_parameters(func.parameters)
441 func.retval.type = self._resolve_param_type(func.retval.type)
443 def _resolve_parameters(self, parameters):
444 for parameter in parameters:
445 parameter.type = self._resolve_param_type(parameter.type)
447 def _resolve_field(self, field):
448 if isinstance(field, Callback):
449 self._resolve_function(field)
451 field.type = self._resolve_param_type(field.type)