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
23 from . import cgobject
24 from .odict import odict
25 from .ast import (Callback, Enum, Function, Member, Namespace, Parameter,
26 Property, Return, Struct, Type, Alias, type_name_from_ctype)
27 from .glibast import (GLibBoxed, GLibEnum, GLibEnumMember, GLibFlags,
28 GLibInterface, GLibObject, GLibSignal)
29 from .utils import extract_libtool, to_underscores
32 class GLibTransformer(object):
34 def __init__(self, transformer):
35 self._transformer = transformer
36 self._namespace_name = None
38 self._output_ns = odict()
40 self._internal_types = {}
44 def add_library(self, libname):
45 if libname.endswith('.la'):
46 libname = extract_libtool(libname)
47 self._libraries.append(ctypes.cdll.LoadLibrary(libname))
50 namespace = self._transformer.parse()
51 self._namespace_name = namespace.name
54 for node in namespace.nodes:
55 self._parse_node(node)
57 # Introspection is done from within parsing
59 # Second pass, resolving types
60 for node in self._output_ns.values():
61 # associate GtkButtonClass with GtkButton
62 if isinstance(node, Struct):
63 self._pair_class_struct(node)
64 self._resolve_node(node)
66 # Create a new namespace with what we found
67 namespace = Namespace(namespace.name)
68 namespace.nodes = self._aliases + self._output_ns.values()
73 def _add_attribute(self, node, replace=False):
75 if node_name in self._output_ns and not replace:
77 self._output_ns[node_name] = node
79 def _remove_attribute(self, name):
80 del self._output_ns[name]
82 def _get_attribute(self, name):
83 return self._output_ns.get(name)
85 def _register_internal_type(self, type_name, node):
86 self._internal_types[type_name] = node
90 def _create_type(self, type_id):
91 ctype = cgobject.type_name(type_id)
92 type_name = type_name_from_ctype(ctype)
93 return Type(type_name, ctype)
95 def _create_gobject(self, node):
96 type_name = 'G' + node.name
97 if type_name == 'GObject':
98 parent_type_name = None
101 type_id = cgobject.type_from_name(type_name)
102 parent_type_name = cgobject.type_name(
103 cgobject.type_parent(type_id))
104 symbol = to_underscores(type_name).lower() + '_get_type'
105 node = GLibObject(node.name, parent_type_name, type_name, symbol)
106 type_id = cgobject.TYPE_OBJECT
107 self._introspect_properties(node, type_id)
108 self._introspect_signals(node, type_id)
109 self._add_attribute(node)
110 self._register_internal_type(type_name, node)
114 def _parse_node(self, node):
115 if isinstance(node, Enum):
116 self._parse_enum(node)
117 elif isinstance(node, Function):
118 self._parse_function(node)
119 elif isinstance(node, Struct):
120 self._parse_struct(node)
121 elif isinstance(node, Callback):
122 self._parse_callback(node)
123 elif isinstance(node, Alias):
124 self._parse_alias(node)
125 elif isinstance(node, Member):
126 # FIXME: atk_misc_instance singletons
129 print 'GOBJECT BUILDER: Unhandled node:', node
131 def _parse_alias(self, alias):
132 self._aliases.append(alias)
134 def _parse_enum(self, enum):
135 self._add_attribute(enum)
137 def _parse_function(self, func):
138 if self._parse_get_type_function(func):
140 elif self._parse_constructor(func):
142 elif self._parse_method(func):
145 self._add_attribute(func)
147 def _parse_get_type_function(self, func):
148 if not self._libraries:
150 # GType *_get_type(void)
152 if not symbol.endswith('_get_type'):
154 if func.retval.type.name != 'GObject.GType':
159 for library in self._libraries:
161 func = getattr(library, symbol)
163 except AttributeError:
166 print 'Warning: could not find symbol: %s' % symbol
169 func.restype = cgobject.GType
172 self._introspect_type(type_id, symbol)
175 def _parse_method(self, func):
176 if not func.parameters:
179 # FIXME: This is hackish, we should preserve the pointer structures
180 # here, so we can find pointers to objects and not just
181 # pointers to anything
182 first_arg = func.parameters[0].type.name
183 if first_arg.count('*') != 1:
186 object_name = first_arg.replace('*', '')
187 return self._parse_method_common(func, object_name, is_method=True)
189 def _parse_constructor(self, func):
190 # FIXME: This is hackish, we should preserve the pointer structures
191 # here, so we can find pointers to objects and not just
192 # pointers to anything
193 rtype = func.retval.type
194 if rtype.name.count('*') != 1:
197 object_name = rtype.name.replace('*', '')
198 return self._parse_method_common(func, object_name, is_method=False)
200 def _parse_method_common(self, func, object_name, is_method):
201 orig_name = object_name
202 if object_name.lower().startswith(self._namespace_name.lower()):
203 object_name = object_name[len(self._namespace_name):]
204 class_ = self._get_attribute(object_name)
205 if class_ is None or not isinstance(class_, (GLibObject, GLibBoxed)):
208 # GtkButton -> gtk_button_, so we can figure out the method name
209 prefix = to_underscores(orig_name).lower() + '_'
210 if not func.symbol.startswith(prefix):
213 # Strip namespace and object prefix: gtk_window_new -> new
214 func.name = func.symbol[len(prefix):]
216 class_.methods.append(func)
218 class_.constructors.append(func)
221 def _parse_struct(self, struct):
222 # This is a hack, but GObject is a rather fundamental piece so.
223 if (self._namespace_name == 'GObject' and
224 struct.name in ["Object", 'InitiallyUnowned']):
225 self._create_gobject(struct)
227 node = self._output_ns.get(struct.name)
229 self._add_attribute(struct, replace=True)
231 node.fields = struct.fields[:]
233 def _parse_callback(self, callback):
234 self._add_attribute(callback)
236 def _pair_class_struct(self, class_node):
237 name = class_node.name
238 if (name.endswith('Class') or
239 name.endswith('Iface')):
241 elif name.endswith('Interface'):
246 node = self._output_ns.get(self._resolve_type_name(name))
247 del self._output_ns[class_node.name]
250 for field in class_node.fields[1:]:
251 node.fields.append(field)
255 def _introspect_type(self, type_id, symbol):
256 fundamental_type_id = cgobject.type_fundamental(type_id)
257 if (fundamental_type_id == cgobject.TYPE_ENUM or
258 fundamental_type_id == cgobject.TYPE_FLAGS):
259 self._introspect_enum(fundamental_type_id, type_id, symbol)
260 elif fundamental_type_id == cgobject.TYPE_OBJECT:
261 self._introspect_object(type_id, symbol)
262 elif fundamental_type_id == cgobject.TYPE_INTERFACE:
263 self._introspect_interface(type_id, symbol)
264 elif fundamental_type_id == cgobject.TYPE_BOXED:
265 self._introspect_boxed(type_id, symbol)
267 print 'unhandled GType: %s' % (cgobject.type_name(type_id), )
269 def _introspect_enum(self, ftype_id, type_id, symbol):
270 type_class = cgobject.type_class_ref(type_id)
271 if type_class is None:
275 for enum_value in type_class.get_values():
276 members.append(GLibEnumMember(enum_value.value_nick,
278 enum_value.value_name,
279 enum_value.value_nick))
281 klass = (GLibFlags if ftype_id == cgobject.TYPE_FLAGS else GLibEnum)
282 type_name = cgobject.type_name(type_id)
283 enum_name = self._transformer.strip_namespace_object(type_name)
284 node = klass(enum_name, type_name, members, symbol)
285 self._add_attribute(node, replace=True)
286 self._register_internal_type(type_name, node)
288 def _introspect_object(self, type_id, symbol):
289 type_name = cgobject.type_name(type_id)
290 parent_type_name = cgobject.type_name(cgobject.type_parent(type_id))
292 self._transformer.strip_namespace_object(type_name),
293 self._resolve_type_name(parent_type_name),
295 self._introspect_properties(node, type_id)
296 self._introspect_signals(node, type_id)
297 self._add_attribute(node)
299 self._remove_attribute(type_name)
301 print 'Warning: could not remove %s' % type_name
303 self._register_internal_type(type_name, node)
305 def _introspect_interface(self, type_id, symbol):
306 type_name = cgobject.type_name(type_id)
307 parent_type_name = cgobject.type_name(cgobject.type_parent(type_id))
308 node = GLibInterface(
309 self._transformer.strip_namespace_object(type_name),
310 self._resolve_type_name(parent_type_name),
312 self._introspect_properties(node, type_id)
313 self._introspect_signals(node, type_id)
314 self._add_attribute(node)
315 self._register_internal_type(type_name, node)
317 def _introspect_boxed(self, type_id, symbol):
318 type_name = cgobject.type_name(type_id)
319 node = GLibBoxed(self._transformer.strip_namespace_object(type_name),
321 self._add_attribute(node)
322 # GdkEvent raises KeyError, FooBoxed ends up duplicated if we don't
324 self._remove_attribute(type_name)
327 self._register_internal_type(type_name, node)
329 def _introspect_properties(self, node, type_id):
330 fundamental_type_id = cgobject.type_fundamental(type_id)
331 if fundamental_type_id == cgobject.TYPE_OBJECT:
332 pspecs = cgobject.object_class_list_properties(type_id)
333 elif fundamental_type_id == cgobject.TYPE_INTERFACE:
334 pspecs = cgobject.object_interface_list_properties(type_id)
339 if pspec.owner_type != type_id:
341 ctype = cgobject.type_name(pspec.value_type)
342 node.properties.append(Property(
344 type_name_from_ctype(ctype),
348 def _introspect_signals(self, node, type_id):
349 for signal_info in cgobject.signal_list(type_id):
350 rtype = self._create_type(signal_info.return_type)
351 return_ = Return(rtype)
352 signal = GLibSignal(signal_info.signal_name, return_)
353 for i, parameter in enumerate(signal_info.get_params()):
357 name = 'p%s' % (i-1, )
358 ptype = self._create_type(parameter)
359 param = Parameter(name, ptype)
360 signal.parameters.append(param)
361 node.signals.append(signal)
365 def _resolve_type_name(self, type_name):
366 type_name = type_name.replace('*', '')
367 possible_name = self._transformer.resolve_type_name(type_name)
368 if possible_name != type_name:
370 possible_node = self._internal_types.get(type_name)
372 return possible_node.name
375 def _resolve_param_type(self, ptype):
376 ptype.name = ptype.name.replace('*', '')
377 type_name = ptype.name
378 type_name = self._transformer.resolve_possible_typedef(type_name)
379 possible_node = self._internal_types.get(type_name)
381 ptype.name = possible_node.name
383 ptype = self._transformer.resolve_param_type(ptype)
386 def _resolve_node(self, node):
387 if isinstance(node, (Callback, Function)):
388 self._resolve_function(node)
389 elif isinstance(node, GLibObject):
390 self._resolve_glib_object(node)
391 elif isinstance(node, GLibInterface):
392 self._resolve_glib_interface(node)
393 elif isinstance(node, GLibBoxed):
394 self._resolve_glib_boxed(node)
395 elif isinstance(node, Struct):
396 self._resolve_struct(node)
398 def _resolve_struct(self, node):
399 for field in node.fields:
400 self._resolve_field(field)
402 def _resolve_glib_interface(self, node):
403 self._resolve_methods(node.methods)
404 self._resolve_properties(node.properties)
405 self._resolve_signals(node.signals)
407 def _resolve_glib_object(self, node):
408 self._resolve_constructors(node.constructors)
409 self._resolve_methods(node.methods)
410 self._resolve_properties(node.properties)
411 self._resolve_signals(node.signals)
413 def _resolve_glib_boxed(self, node):
414 self._resolve_constructors(node.constructors)
415 self._resolve_methods(node.methods)
417 def _resolve_constructors(self, constructors):
418 for ctor in constructors:
419 self._resolve_function(ctor)
421 def _resolve_methods(self, methods):
422 for method in methods:
423 self._resolve_function(method)
425 def _resolve_signals(self, signals):
426 for signal in signals:
427 self._resolve_function(signal)
429 def _resolve_properties(self, properties):
430 for prop in properties:
431 self._resolve_property(prop)
433 def _resolve_property(self, prop):
434 prop.type = self._resolve_param_type(prop.type)
436 def _resolve_function(self, func):
437 self._resolve_parameters(func.parameters)
438 func.retval.type = self._resolve_param_type(func.retval.type)
440 def _resolve_parameters(self, parameters):
441 for parameter in parameters:
442 parameter.type = self._resolve_param_type(parameter.type)
444 def _resolve_field(self, field):
445 if isinstance(field, Callback):
446 self._resolve_function(field)
448 field.type = self._resolve_param_type(field.type)