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 resolve_libtool, to_underscores
35 class GLibTransformer(object):
37 def __init__(self, transformer):
38 self._transformer = transformer
39 self._namespace_name = None
40 self._output_ns = odict()
46 def load_library(self, libname):
47 if libname.endswith('.la'):
48 libname = resolve_libtool(libname)
49 self._library = ctypes.cdll.LoadLibrary(libname)
52 namespace = self._transformer.parse()
53 self._namespace_name = namespace.name
54 self._type_names = self._transformer.get_type_names()
56 for node in namespace.nodes:
57 self._parse_node(node)
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 namespace = Namespace(namespace.name)
67 namespace.nodes = self._output_ns.values()
72 def _add_attribute(self, node, replace=False):
74 if node_name in self._output_ns and not replace:
76 self._output_ns[node_name] = node
78 def _remove_attribute(self, name):
79 del self._output_ns[name]
81 def _get_attribute(self, name):
82 return self._output_ns.get(name)
84 def _register_internal_type(self, type_name, node):
85 self._type_names[type_name] = (None, node)
87 def _resolve_type_name(self, type_name):
88 item = self._type_names.get(type_name)
93 return '%s.%s' % (nsname, item.name)
96 def _resolve_param_type(self, ptype):
97 type_name = ptype.name.replace('*', '')
98 type_name = self._transformer.resolve_possible_typedef(type_name)
99 ptype.name = self._resolve_type_name(type_name)
102 def _parse_node(self, node):
103 if isinstance(node, Enum):
104 self._parse_enum(node)
105 elif isinstance(node, Function):
106 self._parse_function(node)
107 elif isinstance(node, Struct):
108 self._parse_struct(node)
109 elif isinstance(node, Callback):
110 self._parse_callback(node)
111 elif isinstance(node, Alias):
112 self._parse_alias(node)
113 elif isinstance(node, Member):
114 # FIXME: atk_misc_instance singletons
117 print 'GOBJECT BUILDER: Unhandled node:', node
119 def _resolve_node(self, node):
122 for klass in klasses:
123 if isinstance(node, klass):
127 if isany(Callback, Function):
128 self._resolve_function(node)
129 if isany(GLibObject, GLibBoxed, GLibInterface):
130 for meth in node.methods:
131 self._resolve_function(meth)
132 if isany(GLibObject, GLibBoxed):
133 for ctor in node.constructors:
134 self._resolve_function(ctor)
135 if isany(GLibObject, GLibInterface):
136 for prop in node.properties:
137 self._resolve_property(prop)
138 for sig in node.signals:
139 self._resolve_function(sig)
141 for field in node.fields:
142 if isinstance(field, Field):
143 self._resolve_field(field)
144 elif isinstance(field, Callback):
145 self._resolve_function(field)
147 def _parse_alias(self, alias):
148 self._add_attribute(alias)
150 def _parse_enum(self, enum):
151 self._add_attribute(enum)
153 def _parse_function(self, func):
154 if self._parse_get_type_function(func):
156 elif self._parse_constructor(func):
158 elif self._parse_method(func):
161 self._add_attribute(func)
163 def _resolve_property(self, prop):
164 prop.type = self._resolve_param_type(prop.type)
166 def _resolve_function(self, func):
167 self._resolve_parameters(func.parameters)
168 func.retval.type = self._resolve_param_type(func.retval.type)
170 def _resolve_parameters(self, parameters):
171 for parameter in parameters:
172 parameter.type = self._resolve_param_type(parameter.type)
174 def _resolve_field(self, field):
175 field.type = self._resolve_param_type(field.type)
177 def _parse_get_type_function(self, func):
178 if self._library is None:
180 # GType *_get_type(void)
182 if not symbol.endswith('_get_type'):
184 if func.retval.type.name != 'GType':
190 func = getattr(self._library, symbol)
191 except AttributeError:
192 print 'Warning: could not find symbol: %s' % symbol
195 func.restype = cgobject.GType
198 self._introspect_type(type_id, symbol)
201 def _parse_method(self, func):
202 if not func.parameters:
205 # FIXME: This is hackish, we should preserve the pointer structures
206 # here, so we can find pointers to objects and not just
207 # pointers to anything
208 first_arg = func.parameters[0].type.name
209 if first_arg.count('*') != 1:
212 object_name = first_arg.replace('*', '')
213 return self._parse_method_common(func, object_name, is_method=True)
215 def _parse_constructor(self, func):
216 # FIXME: This is hackish, we should preserve the pointer structures
217 # here, so we can find pointers to objects and not just
218 # pointers to anything
219 rtype = func.retval.type
220 if rtype.name.count('*') != 1:
223 object_name = rtype.name.replace('*', '')
224 return self._parse_method_common(func, object_name, is_method=False)
226 def _parse_method_common(self, func, object_name, is_method):
227 orig_name = object_name
228 if object_name.lower().startswith(self._namespace_name.lower()):
229 object_name = object_name[len(self._namespace_name):]
230 class_ = self._get_attribute(object_name)
231 if class_ is None or not isinstance(class_, (GLibObject, GLibBoxed)):
234 # GtkButton -> gtk_button_, so we can figure out the method name
235 prefix = to_underscores(orig_name).lower() + '_'
236 if not func.symbol.startswith(prefix):
239 # Strip namespace and object prefix: gtk_window_new -> new
240 func.name = func.symbol[len(prefix):]
242 class_.methods.append(func)
244 class_.constructors.append(func)
247 def _parse_struct(self, struct):
248 node = self._output_ns.get(struct.name)
250 self._add_attribute(struct, replace=True)
252 node.fields = struct.fields[:]
254 def _parse_callback(self, callback):
255 self._add_attribute(callback)
257 def _pair_class_struct(self, class_node):
258 name = class_node.name
259 if (name.endswith('Class') or
260 name.endswith('Iface')):
262 elif name.endswith('Interface'):
267 node = self._output_ns.get(self._resolve_type_name(name))
268 del self._output_ns[class_node.name]
271 for field in class_node.fields[1:]:
272 node.fields.append(field)
274 def _create_type(self, type_id):
275 ctype = cgobject.type_name(type_id)
276 type_name = type_name_from_ctype(ctype)
277 return Type(type_name, ctype)
279 def _introspect_type(self, type_id, symbol):
280 fundamental_type_id = cgobject.type_fundamental(type_id)
281 if (fundamental_type_id == cgobject.TYPE_ENUM or
282 fundamental_type_id == cgobject.TYPE_FLAGS):
283 self._introspect_enum(fundamental_type_id, type_id, symbol)
284 elif fundamental_type_id == cgobject.TYPE_OBJECT:
285 self._introspect_object(type_id, symbol)
286 elif fundamental_type_id == cgobject.TYPE_INTERFACE:
287 self._introspect_interface(type_id, symbol)
288 elif fundamental_type_id == cgobject.TYPE_BOXED:
289 self._introspect_boxed(type_id, symbol)
291 print 'unhandled GType: %s' % (cgobject.type_name(type_id), )
293 def _introspect_enum(self, ftype_id, type_id, symbol):
294 type_class = cgobject.type_class_ref(type_id)
295 if type_class is None:
299 for enum_value in type_class.get_values():
300 members.append(GLibEnumMember(enum_value.value_nick,
302 enum_value.value_name,
303 enum_value.value_nick))
305 klass = (GLibFlags if ftype_id == cgobject.TYPE_FLAGS else GLibEnum)
306 type_name = cgobject.type_name(type_id)
307 enum_name = self._transformer.strip_namespace_object(type_name)
308 node = klass(enum_name, type_name, members, symbol)
309 self._add_attribute(node, replace=True)
310 self._register_internal_type(type_name, node)
312 def _introspect_object(self, type_id, symbol):
313 type_name = cgobject.type_name(type_id)
314 parent_type_name = cgobject.type_name(cgobject.type_parent(type_id))
315 node = GLibObject(self._transformer.strip_namespace_object(type_name),
316 self._resolve_type_name(parent_type_name),
318 self._introspect_properties(node, type_id)
319 self._introspect_signals(node, type_id)
320 self._add_attribute(node)
322 self._remove_attribute(type_name)
324 print 'Warning: could not remove %s' % type_name
326 self._register_internal_type(type_name, node)
328 def _introspect_interface(self, type_id, symbol):
329 type_name = cgobject.type_name(type_id)
330 node = GLibInterface(
331 self._transformer.strip_namespace_object(type_name),
333 self._introspect_properties(node, type_id)
334 self._introspect_signals(node, type_id)
335 self._add_attribute(node)
336 self._register_internal_type(type_name, node)
338 def _introspect_boxed(self, type_id, symbol):
339 type_name = cgobject.type_name(type_id)
340 node = GLibBoxed(self._transformer.strip_namespace_object(type_name),
342 self._add_attribute(node)
343 # GdkEvent raises KeyError, FooBoxed ends up duplicated if we don't
345 self._remove_attribute(type_name)
348 self._register_internal_type(type_name, node)
350 def _introspect_properties(self, node, type_id):
351 fundamental_type_id = cgobject.type_fundamental(type_id)
352 if fundamental_type_id == cgobject.TYPE_OBJECT:
353 pspecs = cgobject.object_class_list_properties(type_id)
354 elif fundamental_type_id == cgobject.TYPE_INTERFACE:
355 pspecs = cgobject.object_interface_list_properties(type_id)
360 if pspec.owner_type != type_id:
362 ctype = cgobject.type_name(pspec.value_type)
363 node.properties.append(Property(
365 type_name_from_ctype(ctype),
369 def _introspect_signals(self, node, type_id):
370 for signal_info in cgobject.signal_list(type_id):
371 rtype = self._create_type(signal_info.return_type)
372 return_ = Return(rtype)
373 signal = GLibSignal(signal_info.signal_name, return_)
374 for i, parameter in enumerate(signal_info.get_params()):
378 name = 'p%s' % (i-1, )
379 ptype = self._create_type(parameter)
380 param = Parameter(name, ptype)
381 signal.parameters.append(param)
382 node.signals.append(signal)