timeline-object: Add TrackObject to the Track after the TimelineObject
[platform/upstream/gstreamer.git] / bindings / python / codegen / codegen.py
1 #! /usr/bin/env python
2
3 import getopt
4 import keyword
5 import os
6 import string
7 import sys
8
9 import argtypes
10 import definitions
11 import defsparser
12 import override
13 import reversewrapper
14 import warnings
15
16 class Coverage(object):
17     def __init__(self, name):
18         self.name = name
19         self.wrapped = 0
20         self.not_wrapped = 0
21
22     def declare_wrapped(self):
23         self.wrapped += 1
24
25     def declare_not_wrapped(self):
26         self.not_wrapped += 1
27
28     def printstats(self):
29         total = self.wrapped + self.not_wrapped
30         fd = sys.stderr
31         if total:
32             fd.write("***INFO*** The coverage of %s is %.2f%% (%i/%i)\n" %
33                      (self.name,
34                       float(self.wrapped*100)/total,
35                       self.wrapped,
36                       total))
37         else:
38             fd.write("***INFO*** There are no declared %s.\n" % self.name)
39
40 functions_coverage = Coverage("global functions")
41 methods_coverage = Coverage("methods")
42 vproxies_coverage = Coverage("virtual proxies")
43 vaccessors_coverage = Coverage("virtual accessors")
44 iproxies_coverage = Coverage("interface proxies")
45
46 def exc_info():
47     warnings.warn("deprecated", DeprecationWarning, stacklevel=2)
48     #traceback.print_exc()
49     etype, value, tb = sys.exc_info()
50     ret = ""
51     try:
52         sval = str(value)
53         if etype == argtypes.ArgTypeError:
54             ret = "No ArgType for %s" % (sval,)
55         else:
56             ret = sval
57     finally:
58         del etype, value, tb
59     return ret
60
61 def fixname(name):
62     if keyword.iskeyword(name):
63         return name + '_'
64     return name
65
66 class FileOutput:
67     '''Simple wrapper for file object, that makes writing #line
68     statements easier.''' # "
69     def __init__(self, fp, filename=None):
70         self.fp = fp
71         self.lineno = 1
72         if filename:
73             self.filename = filename
74         else:
75             self.filename = self.fp.name
76     # handle writing to the file, and keep track of the line number ...
77     def write(self, str):
78         self.fp.write(str)
79         self.lineno = self.lineno + string.count(str, '\n')
80     def writelines(self, sequence):
81         for line in sequence:
82             self.write(line)
83     def close(self):
84         self.fp.close()
85     def flush(self):
86         self.fp.flush()
87
88     def setline(self, linenum, filename):
89         '''writes out a #line statement, for use by the C
90         preprocessor.''' # "
91         self.write('#line %d "%s"\n' % (linenum, filename))
92     def resetline(self):
93         '''resets line numbering to the original file'''
94         self.setline(self.lineno + 1, self.filename)
95
96 class Wrapper:
97     type_tmpl = (
98         'PyTypeObject G_GNUC_INTERNAL Py%(typename)s_Type = {\n'
99         '    PyObject_HEAD_INIT(NULL)\n'
100         '    0,                                 /* ob_size */\n'
101         '    "%(classname)s",                   /* tp_name */\n'
102         '    sizeof(%(tp_basicsize)s),          /* tp_basicsize */\n'
103         '    0,                                 /* tp_itemsize */\n'
104         '    /* methods */\n'
105         '    (destructor)%(tp_dealloc)s,        /* tp_dealloc */\n'
106         '    (printfunc)0,                      /* tp_print */\n'
107         '    (getattrfunc)%(tp_getattr)s,       /* tp_getattr */\n'
108         '    (setattrfunc)%(tp_setattr)s,       /* tp_setattr */\n'
109         '    (cmpfunc)%(tp_compare)s,           /* tp_compare */\n'
110         '    (reprfunc)%(tp_repr)s,             /* tp_repr */\n'
111         '    (PyNumberMethods*)%(tp_as_number)s,     /* tp_as_number */\n'
112         '    (PySequenceMethods*)%(tp_as_sequence)s, /* tp_as_sequence */\n'
113         '    (PyMappingMethods*)%(tp_as_mapping)s,   /* tp_as_mapping */\n'
114         '    (hashfunc)%(tp_hash)s,             /* tp_hash */\n'
115         '    (ternaryfunc)%(tp_call)s,          /* tp_call */\n'
116         '    (reprfunc)%(tp_str)s,              /* tp_str */\n'
117         '    (getattrofunc)%(tp_getattro)s,     /* tp_getattro */\n'
118         '    (setattrofunc)%(tp_setattro)s,     /* tp_setattro */\n'
119         '    (PyBufferProcs*)%(tp_as_buffer)s,  /* tp_as_buffer */\n'
120         '    %(tp_flags)s,                      /* tp_flags */\n'
121         '    %(tp_doc)s,                        /* Documentation string */\n'
122         '    (traverseproc)%(tp_traverse)s,     /* tp_traverse */\n'
123         '    (inquiry)%(tp_clear)s,             /* tp_clear */\n'
124         '    (richcmpfunc)%(tp_richcompare)s,   /* tp_richcompare */\n'
125         '    %(tp_weaklistoffset)s,             /* tp_weaklistoffset */\n'
126         '    (getiterfunc)%(tp_iter)s,          /* tp_iter */\n'
127         '    (iternextfunc)%(tp_iternext)s,     /* tp_iternext */\n'
128         '    (struct PyMethodDef*)%(tp_methods)s, /* tp_methods */\n'
129         '    (struct PyMemberDef*)0,              /* tp_members */\n'
130         '    (struct PyGetSetDef*)%(tp_getset)s,  /* tp_getset */\n'
131         '    NULL,                              /* tp_base */\n'
132         '    NULL,                              /* tp_dict */\n'
133         '    (descrgetfunc)%(tp_descr_get)s,    /* tp_descr_get */\n'
134         '    (descrsetfunc)%(tp_descr_set)s,    /* tp_descr_set */\n'
135         '    %(tp_dictoffset)s,                 /* tp_dictoffset */\n'
136         '    (initproc)%(tp_init)s,             /* tp_init */\n'
137         '    (allocfunc)%(tp_alloc)s,           /* tp_alloc */\n'
138         '    (newfunc)%(tp_new)s,               /* tp_new */\n'
139         '    (freefunc)%(tp_free)s,             /* tp_free */\n'
140         '    (inquiry)%(tp_is_gc)s              /* tp_is_gc */\n'
141         '};\n\n'
142         )
143
144     slots_list = [
145         'tp_getattr', 'tp_setattr', 'tp_getattro', 'tp_setattro',
146         'tp_compare', 'tp_repr',
147         'tp_as_number', 'tp_as_sequence', 'tp_as_mapping', 'tp_hash',
148         'tp_call', 'tp_str', 'tp_as_buffer', 'tp_richcompare', 'tp_iter',
149         'tp_iternext', 'tp_descr_get', 'tp_descr_set', 'tp_init',
150         'tp_alloc', 'tp_new', 'tp_free', 'tp_is_gc',
151         'tp_traverse', 'tp_clear', 'tp_dealloc', 'tp_flags', 'tp_doc'
152         ]
153
154     getter_tmpl = (
155         'static PyObject *\n'
156         '%(funcname)s(PyObject *self, void *closure)\n'
157         '{\n'
158         '%(varlist)s'
159         '    ret = %(field)s;\n'
160         '%(codeafter)s\n'
161         '}\n\n'
162         )
163
164     parse_tmpl = (
165         '    if (!PyArg_ParseTupleAndKeywords(args, kwargs,'
166         '"%(typecodes)s:%(name)s"%(parselist)s))\n'
167         '        return %(errorreturn)s;\n'
168         )
169
170     deprecated_tmpl = (
171         '    if (PyErr_Warn(PyExc_DeprecationWarning, '
172         '"%(deprecationmsg)s") < 0)\n'
173         '        return %(errorreturn)s;\n'
174         )
175
176     methdef_tmpl = (
177         '    { "%(name)s", (PyCFunction)%(cname)s, %(flags)s,\n'
178         '      %(docstring)s },\n'
179         )
180
181     noconstructor = (
182         'static int\n'
183         'pygobject_no_constructor(PyObject *self, PyObject *args, '
184         'PyObject *kwargs)\n'
185         '{\n'
186         '    gchar buf[512];\n'
187         '\n'
188         '    g_snprintf(buf, sizeof(buf), "%s is an abstract widget", '
189         'self->ob_type->tp_name);\n'
190         '    PyErr_SetString(PyExc_NotImplementedError, buf);\n'
191         '    return -1;\n'
192         '}\n\n'
193         )
194
195     function_tmpl = (
196         'static PyObject *\n'
197         '_wrap_%(cname)s(PyObject *self%(extraparams)s)\n'
198         '{\n'
199         '%(varlist)s'
200         '%(parseargs)s'
201         '%(codebefore)s'
202         '    %(begin_allow_threads)s\n'
203         '    %(setreturn)s%(cname)s(%(arglist)s);\n'
204         '    %(end_allow_threads)s\n'
205         '%(codeafter)s\n'
206         '}\n\n'
207         )
208
209     virtual_accessor_tmpl = (
210         'static PyObject *\n'
211         '_wrap_%(cname)s(PyObject *cls%(extraparams)s)\n'
212         '{\n'
213         '    gpointer klass;\n'
214         '%(varlist)s'
215         '%(parseargs)s'
216         '%(codebefore)s'
217         '    klass = g_type_class_ref(pyg_type_from_object(cls));\n'
218         '    if (%(class_cast_macro)s(klass)->%(virtual)s)\n'
219         '        %(setreturn)s%(class_cast_macro)s(klass)->'
220         '%(virtual)s(%(arglist)s);\n'
221         '    else {\n'
222         '        PyErr_SetString(PyExc_NotImplementedError, '
223         '"virtual method %(name)s not implemented");\n'
224         '        g_type_class_unref(klass);\n'
225         '        return NULL;\n'
226         '    }\n'
227         '    g_type_class_unref(klass);\n'
228         '%(codeafter)s\n'
229         '}\n\n'
230         )
231
232     # template for method calls
233     constructor_tmpl = None
234     method_tmpl = None
235
236     def __init__(self, parser, objinfo, overrides, fp=FileOutput(sys.stdout)):
237         self.parser = parser
238         self.objinfo = objinfo
239         self.overrides = overrides
240         self.fp = fp
241
242     def get_lower_name(self):
243         return string.lower(string.replace(self.objinfo.typecode,
244                                            '_TYPE_', '_', 1))
245
246     def get_field_accessor(self, fieldname):
247         raise NotImplementedError
248
249     def get_initial_class_substdict(self): return {}
250
251     def get_initial_constructor_substdict(self, constructor):
252         return { 'name': '%s.__init__' % self.objinfo.py_name,
253                  'errorreturn': '-1' }
254
255     def get_initial_method_substdict(self, method):
256         substdict = { 'name': '%s.%s' % (self.objinfo.py_name, method.name) }
257         if method.unblock_threads:
258             substdict['begin_allow_threads'] = 'pyg_begin_allow_threads;'
259             substdict['end_allow_threads'] = 'pyg_end_allow_threads;'
260         else:
261             substdict['begin_allow_threads'] = ''
262             substdict['end_allow_threads'] = ''
263         return substdict
264
265     def write_class(self):
266         if self.overrides.is_type_ignored(self.objinfo.c_name):
267             return
268         self.fp.write('\n/* ----------- %s ----------- */\n\n' %
269                       self.objinfo.c_name)
270         substdict = self.get_initial_class_substdict()
271         if not substdict.has_key('tp_flags'):
272             substdict['tp_flags'] = 'Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE'
273         substdict['typename'] = self.objinfo.c_name
274         if self.overrides.modulename:
275             substdict['classname'] = '%s.%s' % (self.overrides.modulename,
276                                            self.objinfo.name)
277         else:
278             substdict['classname'] = self.objinfo.name
279         substdict['tp_doc'] = self.objinfo.docstring
280
281         # Maybe this could be done in a nicer way, but I'll leave it as it is
282         # for now: -- Johan
283         if not self.overrides.slot_is_overriden('%s.tp_init' %
284                                                 self.objinfo.c_name):
285             substdict['tp_init'] = self.write_constructor()
286         substdict['tp_methods'] = self.write_methods()
287         substdict['tp_getset'] = self.write_getsets()
288
289         # handle slots ...
290         for slot in self.slots_list:
291
292             slotname = '%s.%s' % (self.objinfo.c_name, slot)
293             slotfunc = '_wrap_%s_%s' % (self.get_lower_name(), slot)
294             if slot[:6] == 'tp_as_':
295                 slotfunc = '&' + slotfunc
296             if self.overrides.slot_is_overriden(slotname):
297                 data = self.overrides.slot_override(slotname)
298                 self.write_function(slotname, data)
299                 substdict[slot] = slotfunc
300             else:
301                 if not substdict.has_key(slot):
302                     substdict[slot] = '0'
303
304         self.fp.write(self.type_tmpl % substdict)
305
306         self.write_virtuals()
307
308     def write_function_wrapper(self, function_obj, template,
309                                handle_return=0, is_method=0, kwargs_needed=0,
310                                substdict=None):
311         '''This function is the guts of all functions that generate
312         wrappers for functions, methods and constructors.'''
313         if not substdict: substdict = {}
314
315         info = argtypes.WrapperInfo()
316
317         substdict.setdefault('errorreturn', 'NULL')
318
319         # for methods, we want the leading comma
320         if is_method:
321             info.arglist.append('')
322
323         if function_obj.varargs:
324             raise argtypes.ArgTypeNotFoundError("varargs functions not supported")
325
326         for param in function_obj.params:
327             if param.pdflt != None and '|' not in info.parsestr:
328                 info.add_parselist('|', [], [])
329             handler = argtypes.matcher.get(param.ptype)
330             handler.write_param(param.ptype, param.pname, param.pdflt,
331                                 param.pnull, info)
332
333         substdict['setreturn'] = ''
334         if handle_return:
335             if function_obj.ret not in ('none', None):
336                 substdict['setreturn'] = 'ret = '
337             handler = argtypes.matcher.get(function_obj.ret)
338             handler.write_return(function_obj.ret,
339                                  function_obj.caller_owns_return, info)
340
341         if function_obj.deprecated != None:
342             deprecated = self.deprecated_tmpl % {
343                 'deprecationmsg': function_obj.deprecated,
344                 'errorreturn': substdict['errorreturn'] }
345         else:
346             deprecated = ''
347
348         # if name isn't set, set it to function_obj.name
349         substdict.setdefault('name', function_obj.name)
350
351         if function_obj.unblock_threads:
352             substdict['begin_allow_threads'] = 'pyg_begin_allow_threads;'
353             substdict['end_allow_threads'] = 'pyg_end_allow_threads;'
354         else:
355             substdict['begin_allow_threads'] = ''
356             substdict['end_allow_threads'] = ''
357
358         if self.objinfo:
359             substdict['typename'] = self.objinfo.c_name
360         substdict.setdefault('cname',  function_obj.c_name)
361         substdict['varlist'] = info.get_varlist()
362         substdict['typecodes'] = info.parsestr
363         substdict['parselist'] = info.get_parselist()
364         substdict['arglist'] = info.get_arglist()
365         substdict['codebefore'] = deprecated + (
366             string.replace(info.get_codebefore(),
367             'return NULL', 'return ' + substdict['errorreturn'])
368             )
369         substdict['codeafter'] = (
370             string.replace(info.get_codeafter(),
371                            'return NULL',
372                            'return ' + substdict['errorreturn']))
373
374         if info.parsestr or kwargs_needed:
375             substdict['parseargs'] = self.parse_tmpl % substdict
376             substdict['extraparams'] = ', PyObject *args, PyObject *kwargs'
377             flags = 'METH_VARARGS|METH_KEYWORDS'
378
379             # prepend the keyword list to the variable list
380             substdict['varlist'] = info.get_kwlist() + substdict['varlist']
381         else:
382             substdict['parseargs'] = ''
383             substdict['extraparams'] = ''
384             flags = 'METH_NOARGS'
385
386         return template % substdict, flags
387
388     def write_constructor(self):
389         initfunc = '0'
390         constructor = self.parser.find_constructor(self.objinfo,self.overrides)
391         if not constructor:
392             return self.write_default_constructor()
393
394         funcname = constructor.c_name
395         try:
396             if self.overrides.is_overriden(funcname):
397                 data = self.overrides.override(funcname)
398                 self.write_function(funcname, data)
399                 self.objinfo.has_new_constructor_api = (
400                     self.objinfo.typecode in
401                     self.overrides.newstyle_constructors)
402             else:
403                 # ok, a hack to determine if we should use
404                 # new-style constructores :P
405                 property_based = getattr(self,
406                                          'write_property_based_constructor',
407                                          None)
408                 if property_based:
409                     if (len(constructor.params) == 0 or
410                         isinstance(constructor.params[0],
411                                    definitions.Property)):
412                         # write_property_based_constructor is only
413                         # implemented in GObjectWrapper
414                         return self.write_property_based_constructor(
415                             constructor)
416                     else:
417                         sys.stderr.write(
418                             "Warning: generating old-style constructor for:" +
419                             constructor.c_name + '\n')
420
421                 # write constructor from template ...
422                 code = self.write_function_wrapper(constructor,
423                     self.constructor_tmpl,
424                     handle_return=0, is_method=0, kwargs_needed=1,
425                     substdict=self.get_initial_constructor_substdict(
426                     constructor))[0]
427                 self.fp.write(code)
428             initfunc = '_wrap_' + funcname
429         except argtypes.ArgTypeError, ex:
430             sys.stderr.write('Could not write constructor for %s: %s\n'
431                              % (self.objinfo.c_name, str(ex)))
432
433             initfunc = self.write_noconstructor()
434         return initfunc
435
436     def write_noconstructor(self):
437         # this is a hack ...
438         if not hasattr(self.overrides, 'no_constructor_written'):
439             self.fp.write(self.noconstructor)
440             self.overrides.no_constructor_written = 1
441         initfunc = 'pygobject_no_constructor'
442         return initfunc
443
444     def write_default_constructor(self):
445         return self.write_noconstructor()
446
447     def get_methflags(self, funcname):
448         if self.overrides.wants_kwargs(funcname):
449             flags = 'METH_VARARGS|METH_KEYWORDS'
450         elif self.overrides.wants_noargs(funcname):
451             flags = 'METH_NOARGS'
452         elif self.overrides.wants_onearg(funcname):
453             flags = 'METH_O'
454         else:
455             flags = 'METH_VARARGS'
456         if self.overrides.is_staticmethod(funcname):
457             flags += '|METH_STATIC'
458         elif self.overrides.is_classmethod(funcname):
459             flags += '|METH_CLASS'
460         return flags
461
462     def write_function(self, funcname, data):
463         lineno, filename = self.overrides.getstartline(funcname)
464         self.fp.setline(lineno, filename)
465         self.fp.write(data)
466         self.fp.resetline()
467         self.fp.write('\n\n')
468
469     def _get_class_virtual_substdict(self, meth, cname, parent):
470         substdict = self.get_initial_method_substdict(meth)
471         substdict['virtual'] = meth.name
472         substdict['cname'] = cname
473         substdict['class_cast_macro'] = parent.typecode.replace(
474             '_TYPE_', '_', 1) + "_CLASS"
475         substdict['typecode'] = self.objinfo.typecode
476         substdict['cast'] = string.replace(parent.typecode, '_TYPE_', '_', 1)
477         return substdict
478
479     def write_methods(self):
480         methods = []
481         klass = self.objinfo.c_name
482         # First, get methods from the defs files
483         for meth in self.parser.find_methods(self.objinfo):
484             method_name = meth.c_name
485             if self.overrides.is_ignored(method_name):
486                 continue
487             try:
488                 if self.overrides.is_overriden(method_name):
489                     if not self.overrides.is_already_included(method_name):
490                         data = self.overrides.override(method_name)
491                         self.write_function(method_name, data)
492
493                     methflags = self.get_methflags(method_name)
494                 else:
495                     # write constructor from template ...
496                     code, methflags = self.write_function_wrapper(meth,
497                         self.method_tmpl, handle_return=1, is_method=1,
498                         substdict=self.get_initial_method_substdict(meth))
499                     self.fp.write(code)
500                 methods.append(self.methdef_tmpl %
501                                { 'name':  fixname(meth.name),
502                                  'cname': '_wrap_' + method_name,
503                                  'flags': methflags,
504                                  'docstring': meth.docstring })
505                 methods_coverage.declare_wrapped()
506             except argtypes.ArgTypeError, ex:
507                 methods_coverage.declare_not_wrapped()
508                 sys.stderr.write('Could not write method %s.%s: %s\n'
509                                 % (klass, meth.name, str(ex)))
510
511         # Now try to see if there are any defined in the override
512         for method_name in self.overrides.get_defines_for(klass):
513             c_name = override.class2cname(klass, method_name)
514             if self.overrides.is_already_included(method_name):
515                 continue
516
517             try:
518                 data = self.overrides.define(klass, method_name)
519                 self.write_function(method_name, data)
520                 methflags = self.get_methflags(method_name)
521
522                 methods.append(self.methdef_tmpl %
523                                { 'name':  method_name,
524                                  'cname': '_wrap_' + c_name,
525                                  'flags': methflags,
526                                  'docstring': 'NULL' })
527                 methods_coverage.declare_wrapped()
528             except argtypes.ArgTypeError, ex:
529                 methods_coverage.declare_not_wrapped()
530                 sys.stderr.write('Could not write method %s.%s: %s\n'
531                                 % (klass, method_name, str(ex)))
532
533         # Add GObject virtual method accessors, for chaining to parent
534         # virtuals from subclasses
535         methods += self.write_virtual_accessors()
536
537         if methods:
538             methoddefs = '_Py%s_methods' % self.objinfo.c_name
539             # write the PyMethodDef structure
540             methods.append('    { NULL, NULL, 0, NULL }\n')
541             self.fp.write('static const PyMethodDef %s[] = {\n' % methoddefs)
542             self.fp.write(string.join(methods, ''))
543             self.fp.write('};\n\n')
544         else:
545             methoddefs = 'NULL'
546         return methoddefs
547
548     def write_virtual_accessors(self):
549         klass = self.objinfo.c_name
550         methods = []
551         for meth in self.parser.find_virtuals(self.objinfo):
552             method_name = self.objinfo.c_name + "__do_" + meth.name
553             if self.overrides.is_ignored(method_name):
554                 continue
555             try:
556                 if self.overrides.is_overriden(method_name):
557                     if not self.overrides.is_already_included(method_name):
558                         data = self.overrides.override(method_name)
559                         self.write_function(method_name, data)
560                     methflags = self.get_methflags(method_name)
561                 else:
562                     # temporarily add a 'self' parameter as first argument
563                     meth.params.insert(0, definitions.Parameter(
564                         ptype=(self.objinfo.c_name + '*'),
565                         pname='self', pdflt=None, pnull=None))
566                     try:
567                         # write method from template ...
568                         code, methflags = self.write_function_wrapper(
569                             meth, self.virtual_accessor_tmpl,
570                             handle_return=True, is_method=False,
571                             substdict=self._get_class_virtual_substdict(
572                             meth, method_name, self.objinfo))
573                         self.fp.write(code)
574                     finally:
575                         del meth.params[0]
576                 methods.append(self.methdef_tmpl %
577                                { 'name':  "do_" + fixname(meth.name),
578                                  'cname': '_wrap_' + method_name,
579                                  'flags': methflags + '|METH_CLASS',
580                                  'docstring': 'NULL'})
581                 vaccessors_coverage.declare_wrapped()
582             except argtypes.ArgTypeError, ex:
583                 vaccessors_coverage.declare_not_wrapped()
584                 sys.stderr.write(
585                     'Could not write virtual accessor method %s.%s: %s\n'
586                     % (klass, meth.name, str(ex)))
587         return methods
588
589     def write_virtuals(self):
590         '''
591         Write _wrap_FooBar__proxy_do_zbr() reverse wrapers for
592         GObject virtuals
593         '''
594         klass = self.objinfo.c_name
595         virtuals = []
596         for meth in self.parser.find_virtuals(self.objinfo):
597             method_name = self.objinfo.c_name + "__proxy_do_" + meth.name
598             if self.overrides.is_ignored(method_name):
599                 continue
600             try:
601                 if self.overrides.is_overriden(method_name):
602                     if not self.overrides.is_already_included(method_name):
603                         data = self.overrides.override(method_name)
604                         self.write_function(method_name, data)
605                 else:
606                     # write virtual proxy ...
607                     ret, props = argtypes.matcher.get_reverse_ret(meth.ret)
608                     wrapper = reversewrapper.ReverseWrapper(
609                         '_wrap_' + method_name, is_static=True)
610                     wrapper.set_return_type(ret(wrapper, **props))
611                     wrapper.add_parameter(reversewrapper.PyGObjectMethodParam(
612                         wrapper, "self", method_name="do_" + meth.name,
613                         c_type=(klass + ' *')))
614                     for param in meth.params:
615                         handler, props = argtypes.matcher.get_reverse(
616                             param.ptype)
617                         props["direction"] = param.pdir
618                         props["nullok"] = param.pnull
619                         wrapper.add_parameter(handler(wrapper,
620                                                       param.pname, **props))
621                     buf = reversewrapper.MemoryCodeSink()
622                     wrapper.generate(buf)
623                     self.fp.write(buf.flush())
624                 virtuals.append((fixname(meth.name), '_wrap_' + method_name))
625                 vproxies_coverage.declare_wrapped()
626             except argtypes.ArgTypeError, ex:
627                 vproxies_coverage.declare_not_wrapped()
628                 virtuals.append((fixname(meth.name), None))
629                 sys.stderr.write('Could not write virtual proxy %s.%s: %s\n'
630                                 % (klass, meth.name, str(ex)))
631         if virtuals:
632             # Write a 'pygtk class init' function for this object,
633             # except when the object type is explicitly ignored (like
634             # GtkPlug and GtkSocket on win32).
635             if self.overrides.is_ignored(self.objinfo.typecode):
636                 return
637             class_cast_macro = self.objinfo.typecode.replace(
638                 '_TYPE_', '_', 1) + "_CLASS"
639             cast_macro = self.objinfo.typecode.replace('_TYPE_', '_', 1)
640             funcname = "__%s_class_init" % klass
641             self.objinfo.class_init_func = funcname
642             have_implemented_virtuals = not not [True
643                                                  for name, cname in virtuals
644                                                      if cname is not None]
645             self.fp.write(
646             ('\nstatic int\n'
647              '%(funcname)s(gpointer gclass, PyTypeObject *pyclass)\n'
648              '{\n') % vars())
649
650             if have_implemented_virtuals:
651                 self.fp.write('    PyObject *o;\n')
652                 self.fp.write(
653                     '    %(klass)sClass *klass = '
654                     '%(class_cast_macro)s(gclass);\n'
655                     '    PyObject *gsignals = '
656                     'PyDict_GetItemString(pyclass->tp_dict, "__gsignals__");\n'
657                     % vars())
658
659             for name, cname in virtuals:
660                 do_name = 'do_' + name
661                 if cname is None:
662                     self.fp.write('\n    /* overriding %(do_name)s '
663                                   'is currently not supported */\n' % vars())
664                 else:
665                     self.fp.write('''
666     o = PyObject_GetAttrString((PyObject *) pyclass, "%(do_name)s");
667     if (o == NULL)
668         PyErr_Clear();
669     else {
670         if (!PyObject_TypeCheck(o, &PyCFunction_Type)
671             && !(gsignals && PyDict_GetItemString(gsignals, "%(name)s")))
672             klass->%(name)s = %(cname)s;
673         Py_DECREF(o);
674     }
675 ''' % vars())
676             self.fp.write('    return 0;\n}\n')
677
678     def write_getsets(self):
679         lower_name = self.get_lower_name()
680         getsets_name = lower_name + '_getsets'
681         getterprefix = '_wrap_' + lower_name + '__get_'
682         setterprefix = '_wrap_' + lower_name + '__set_'
683
684         # no overrides for the whole function.  If no fields,
685         # don't write a func
686         if not self.objinfo.fields:
687             return '0'
688         getsets = []
689         for ftype, cfname in self.objinfo.fields:
690             fname = cfname.replace('.', '_')
691             gettername = '0'
692             settername = '0'
693             attrname = self.objinfo.c_name + '.' + fname
694             if self.overrides.attr_is_overriden(attrname):
695                 code = self.overrides.attr_override(attrname)
696                 self.write_function(attrname, code)
697                 if string.find(code, getterprefix + fname) >= 0:
698                     gettername = getterprefix + fname
699                 if string.find(code, setterprefix + fname) >= 0:
700                     settername = setterprefix + fname
701             if gettername == '0':
702                 try:
703                     funcname = getterprefix + fname
704                     info = argtypes.WrapperInfo()
705                     handler = argtypes.matcher.get(ftype)
706                     # for attributes, we don't own the "return value"
707                     handler.write_return(ftype, 0, info)
708                     self.fp.write(self.getter_tmpl %
709                                   { 'funcname': funcname,
710                                     'varlist': info.varlist,
711                                     'field': self.get_field_accessor(cfname),
712                                     'codeafter': info.get_codeafter() })
713                     gettername = funcname
714                 except argtypes.ArgTypeError, ex:
715                     sys.stderr.write(
716                         "Could not write getter for %s.%s: %s\n"
717                         % (self.objinfo.c_name, fname, str(ex)))
718             if gettername != '0' or settername != '0':
719                 getsets.append('    { "%s", (getter)%s, (setter)%s },\n' %
720                                (fixname(fname), gettername, settername))
721
722         if not getsets:
723             return '0'
724         self.fp.write('static const PyGetSetDef %s[] = {\n' % getsets_name)
725         for getset in getsets:
726             self.fp.write(getset)
727         self.fp.write('    { NULL, (getter)0, (setter)0 },\n')
728         self.fp.write('};\n\n')
729
730         return getsets_name
731
732     def _write_get_symbol_names(self, writer, functions):
733         self.fp.write("""static PyObject *
734 _wrap__get_symbol_names(PyObject *self)
735 {
736     PyObject *pylist = PyList_New(0);
737
738 """)
739         for obj, bases in writer.get_classes():
740             self.fp.write('    PyList_Append(pylist, '
741                           'PyString_FromString("%s"));\n' % (obj.name))
742
743         for name, cname, flags, docstring in functions:
744             self.fp.write('    PyList_Append(pylist, '
745                           'PyString_FromString("%s"));\n' % (name))
746
747         for enum in writer.get_enums():
748             self.fp.write('    PyList_Append(pylist, '
749                           'PyString_FromString("%s"));\n' % (enum.name))
750             for nick, value in enum.values:
751                 name = value[len(self.overrides.modulename)+1:]
752                 self.fp.write('    PyList_Append(pylist, '
753                               'PyString_FromString("%s"));\n' % (name))
754
755         self.fp.write("    return pylist;\n}\n\n");
756
757     def _write_get_symbol(self, writer, functions):
758         self.fp.write("""static PyObject *
759 _wrap__get_symbol(PyObject *self, PyObject *args)
760 {
761     PyObject *d;
762     char *name;
763     static PyObject *modulename = NULL;
764     static PyObject *module = NULL;
765     static char *strip_prefix = "%s";
766
767     if (!PyArg_ParseTuple(args, "Os", &d, &name))
768         return NULL;
769
770     if (!modulename)
771        modulename = PyString_FromString("%s");
772
773     if (!module)
774        module = PyDict_GetItemString(d, "__module__");
775
776 """ % (self.overrides.modulename.upper() + '_',
777        self.overrides.modulename))
778
779         first = True
780         # Classes / GObjects
781         for obj, bases in writer.get_classes():
782             if first:
783                 self.fp.write('    if (!strcmp(name, "%s")) {\n' % obj.name)
784                 first = False
785             else:
786                 self.fp.write('    } else if (!strcmp(name, "%s")) {\n' % obj.name)
787             self.fp.write(
788                 '       return (PyObject*)pygobject_lookup_class(%s);\n' %
789                 obj.typecode)
790         self.fp.write('    }\n')
791
792         # Functions
793         for name, cname, flags, docstring in functions:
794             self.fp.write('    else if (!strcmp(name, "%s")) {\n' % name)
795             self.fp.write('        static PyMethodDef ml = { '
796                           '"%s", (PyCFunction)%s, %s, "%s"};\n' % (
797                 name, cname, flags, docstring))
798             self.fp.write('        return PyCFunction_NewEx(&ml, NULL, modulename);\n')
799             self.fp.write('    }\n')
800
801         # Enums
802         def write_enum(enum, returnobj=False):
803             if returnobj:
804                 ret = 'return '
805             else:
806                 ret = ''
807             if enum.deftype == 'enum':
808                 self.fp.write(
809                     '        %spyg_enum_add(module, "%s", strip_prefix, %s);\n'
810                     % (ret, enum.name, enum.typecode))
811             else:
812                 self.fp.write(
813                     '    %spyg_flags_add(module, "%s", strip_prefix, %s);\n'
814                     % (ret, enum.name, enum.typecode))
815
816         strip_len = len(self.overrides.modulename)+1 # GTK_
817         for enum in writer.get_enums():
818             # XXX: Implement without typecodes
819             self.fp.write('    else if (!strcmp(name, "%s")) {\n' % enum.name)
820             write_enum(enum, returnobj=True)
821             self.fp.write('    }\n')
822
823             for nick, value in enum.values:
824                 value = value[strip_len:]
825                 self.fp.write('    else if (!strcmp(name, "%s")) {\n' % value)
826                 write_enum(enum)
827                 self.fp.write('        return PyObject_GetAttrString(module, "%s");\n' %
828                               value)
829                 self.fp.write('    }\n')
830
831         self.fp.write('    return Py_None;\n}\n\n');
832
833     def _write_function_bodies(self):
834         functions = []
835         # First, get methods from the defs files
836         for func in self.parser.find_functions():
837             funcname = func.c_name
838             if self.overrides.is_ignored(funcname):
839                 continue
840             try:
841                 if self.overrides.is_overriden(funcname):
842                     data = self.overrides.override(funcname)
843                     self.write_function(funcname, data)
844
845                     methflags = self.get_methflags(funcname)
846                 else:
847                     # write constructor from template ...
848                     code, methflags = self.write_function_wrapper(func,
849                         self.function_tmpl, handle_return=1, is_method=0)
850                     self.fp.write(code)
851                 functions.append((func.name, '_wrap_' + funcname,
852                                   methflags, func.docstring))
853                 functions_coverage.declare_wrapped()
854             except argtypes.ArgTypeError, ex:
855                 functions_coverage.declare_not_wrapped()
856                 sys.stderr.write('Could not write function %s: %s\n'
857                                  % (func.name, str(ex)))
858
859         # Now try to see if there are any defined in the override
860         for funcname in self.overrides.get_functions():
861             try:
862                 data = self.overrides.function(funcname)
863                 self.write_function(funcname, data)
864                 methflags = self.get_methflags(funcname)
865                 functions.append((funcname, '_wrap_' + funcname,
866                                   methflags, 'NULL'))
867                 functions_coverage.declare_wrapped()
868             except argtypes.ArgTypeError, ex:
869                 functions_coverage.declare_not_wrapped()
870                 sys.stderr.write('Could not write function %s: %s\n'
871                                  % (funcname, str(ex)))
872         return functions
873
874     def write_functions(self, writer, prefix):
875         self.fp.write('\n/* ----------- functions ----------- */\n\n')
876         functions = []
877         func_infos = self._write_function_bodies()
878
879         # If we have a dynamic namespace, write symbol and attribute getter
880         if self.overrides.dynamicnamespace:
881             self._write_get_symbol_names(writer, func_infos)
882             self._write_get_symbol(writer, func_infos)
883             for obj, bases in writer.get_classes():
884                 self.fp.write("""static PyTypeObject *
885 %s_register_type(const gchar *name, PyObject *unused)
886 {
887     PyObject *m = PyImport_ImportModule("gtk");
888     PyObject *d = PyModule_GetDict(m);
889 """ % obj.c_name)
890                 writer.write_class(obj, bases, indent=1)
891                 self.fp.write(
892                     '    return (%s)PyDict_GetItemString(d, "%s");\n' % (
893                     'PyTypeObject*', obj.name))
894                 self.fp.write("}\n")
895
896             functions.append('    { "_get_symbol_names", '
897                              '(PyCFunction)_wrap__get_symbol_names, '
898                              'METH_NOARGS, NULL },\n')
899             functions.append('    { "_get_symbol", '
900                              '(PyCFunction)_wrap__get_symbol, '
901                              'METH_VARARGS, NULL },\n')
902         else:
903             for name, cname, flags, docstring in func_infos:
904                 functions.append(self.methdef_tmpl % dict(name=name,
905                                                           cname=cname,
906                                                           flags=flags,
907                                                           docstring=docstring))
908
909         # write the PyMethodDef structure
910         functions.append('    { NULL, NULL, 0, NULL }\n')
911
912         self.fp.write('const PyMethodDef ' + prefix + '_functions[] = {\n')
913         self.fp.write(string.join(functions, ''))
914         self.fp.write('};\n\n')
915
916 class GObjectWrapper(Wrapper):
917     constructor_tmpl = (
918         'static int\n'
919         '_wrap_%(cname)s(PyGObject *self%(extraparams)s)\n'
920         '{\n'
921         '%(varlist)s'
922         '%(parseargs)s'
923         '%(codebefore)s'
924         '    self->obj = (GObject *)%(cname)s(%(arglist)s);\n'
925         '%(codeafter)s\n'
926         '    if (!self->obj) {\n'
927         '        PyErr_SetString(PyExc_RuntimeError, '
928         '"could not create %(typename)s object");\n'
929         '        return -1;\n'
930         '    }\n'
931         '%(aftercreate)s'
932         '    pygobject_register_wrapper((PyObject *)self);\n'
933         '    return 0;\n'
934         '}\n\n'
935         )
936
937     method_tmpl = (
938         'static PyObject *\n'
939         '_wrap_%(cname)s(PyGObject *self%(extraparams)s)\n'
940         '{\n'
941         '%(varlist)s'
942         '%(parseargs)s'
943         '%(codebefore)s'
944         '    %(begin_allow_threads)s\n'
945         '    %(setreturn)s%(cname)s(%(cast)s(self->obj)%(arglist)s);\n'
946         '    %(end_allow_threads)s\n'
947         '%(codeafter)s\n'
948         '}\n\n'
949         )
950     def __init__(self, parser, objinfo, overrides, fp=FileOutput(sys.stdout)):
951         Wrapper.__init__(self, parser, objinfo, overrides, fp)
952         if self.objinfo:
953             self.castmacro = string.replace(self.objinfo.typecode,
954                                             '_TYPE_', '_', 1)
955
956     def get_initial_class_substdict(self):
957         return { 'tp_basicsize'      : 'PyGObject',
958                  'tp_weaklistoffset' : 'offsetof(PyGObject, weakreflist)',
959                  'tp_dictoffset'     : 'offsetof(PyGObject, inst_dict)' }
960
961     def get_field_accessor(self, fieldname):
962         castmacro = string.replace(self.objinfo.typecode, '_TYPE_', '_', 1)
963         return '%s(pygobject_get(self))->%s' % (castmacro, fieldname)
964
965     def get_initial_constructor_substdict(self, constructor):
966         substdict = Wrapper.get_initial_constructor_substdict(self,
967                                                               constructor)
968         if not constructor.caller_owns_return:
969             substdict['aftercreate'] = "    g_object_ref(self->obj);\n"
970         else:
971             substdict['aftercreate'] = ''
972         return substdict
973
974     def get_initial_method_substdict(self, method):
975         substdict = Wrapper.get_initial_method_substdict(self, method)
976         substdict['cast'] = string.replace(self.objinfo.typecode,
977                                            '_TYPE_', '_', 1)
978         return substdict
979
980     def write_default_constructor(self):
981         try:
982             parent = self.parser.find_object(self.objinfo.parent)
983         except ValueError:
984             parent = None
985         if parent is not None:
986             ## just like the constructor is inheritted, we should
987             # inherit the new API compatibility flag
988             self.objinfo.has_new_constructor_api = (
989                 parent.has_new_constructor_api)
990         elif self.objinfo.parent == 'GObject':
991             self.objinfo.has_new_constructor_api = True
992         return '0'
993
994     def write_property_based_constructor(self, constructor):
995         self.objinfo.has_new_constructor_api = True
996         out = self.fp
997         print >> out, "static int"
998         print >> out, '_wrap_%s(PyGObject *self, PyObject *args,' \
999               ' PyObject *kwargs)\n{' % constructor.c_name
1000         if constructor.params:
1001             s = "    GType obj_type = pyg_type_from_object((PyObject *) self);"
1002             print >> out, s
1003
1004         def py_str_list_to_c(arg):
1005             if arg:
1006                 return "{" + ", ".join(
1007                     map(lambda s: '"' + s + '"', arg)) + ", NULL }"
1008             else:
1009                 return "{ NULL }"
1010
1011         classname = '%s.%s' % (self.overrides.modulename,
1012                                self.objinfo.name)
1013
1014         if constructor.params:
1015             mandatory_arguments = [param for param in constructor.params
1016                                              if not param.optional]
1017             optional_arguments = [param for param in constructor.params
1018                                             if param.optional]
1019             arg_names = py_str_list_to_c(
1020             [param.argname
1021              for param in mandatory_arguments + optional_arguments])
1022
1023             prop_names = py_str_list_to_c(
1024             [param.pname
1025              for param in mandatory_arguments + optional_arguments])
1026
1027             print >> out, "    GParameter params[%i];" % \
1028                   len(constructor.params)
1029             print >> out, "    PyObject *parsed_args[%i] = {NULL, };" % \
1030                   len(constructor.params)
1031             print >> out, "    char *arg_names[] = %s;" % arg_names
1032             print >> out, "    char *prop_names[] = %s;" % prop_names
1033             print >> out, "    guint nparams, i;"
1034             print >> out
1035             if constructor.deprecated is not None:
1036                 out.write(
1037                     '    if (PyErr_Warn(PyExc_DeprecationWarning, '
1038                     '"%s") < 0)\n' %
1039                     constructor.deprecated)
1040                 print >> out, '        return -1;'
1041                 print >> out
1042             out.write("    if (!PyArg_ParseTupleAndKeywords(args, kwargs, ")
1043             template = '"'
1044             if mandatory_arguments:
1045                 template += "O"*len(mandatory_arguments)
1046             if optional_arguments:
1047                 template += "|" + "O"*len(optional_arguments)
1048             template += ':%s.__init__"' % classname
1049             print >> out, template, ", arg_names",
1050             for i in range(len(constructor.params)):
1051                 print >> out, ", &parsed_args[%i]" % i,
1052
1053             out.write(
1054                 "))\n"
1055                 "        return -1;\n"
1056                 "\n"
1057                 "    memset(params, 0, sizeof(GParameter)*%i);\n"
1058                 "    if (!pyg_parse_constructor_args(obj_type, arg_names,\n"
1059                 "                                    prop_names, params, \n"
1060                 "                                    &nparams, parsed_args))\n"
1061                 "        return -1;\n"
1062                 "    pygobject_constructv(self, nparams, params);\n"
1063                 "    for (i = 0; i < nparams; ++i)\n"
1064                 "        g_value_unset(&params[i].value);\n"
1065                 % len(constructor.params))
1066         else:
1067             out.write(
1068                 "    static char* kwlist[] = { NULL };\n"
1069                 "\n")
1070
1071             if constructor.deprecated is not None:
1072                 out.write(
1073                     '    if (PyErr_Warn(PyExc_DeprecationWarning, "%s") < 0)\n'
1074                     '        return -1;\n'
1075                     '\n' % constructor.deprecated)
1076
1077             out.write(
1078                 '    if (!PyArg_ParseTupleAndKeywords(args, kwargs,\n'
1079                 '                                     ":%s.__init__",\n'
1080                 '                                     kwlist))\n'
1081                 '        return -1;\n'
1082                 '\n'
1083                 '    pygobject_constructv(self, 0, NULL);\n' % classname)
1084         out.write(
1085             '    if (!self->obj) {\n'
1086             '        PyErr_SetString(\n'
1087             '            PyExc_RuntimeError, \n'
1088             '            "could not create %s object");\n'
1089             '        return -1;\n'
1090             '    }\n' % classname)
1091
1092         if not constructor.caller_owns_return:
1093             print >> out, "    g_object_ref(self->obj);\n"
1094
1095         out.write(
1096             '    return 0;\n'
1097             '}\n\n')
1098
1099         return "_wrap_%s" % constructor.c_name
1100
1101
1102 class GInterfaceWrapper(GObjectWrapper):
1103     virtual_accessor_tmpl = (
1104         'static PyObject *\n'
1105         '_wrap_%(cname)s(PyObject *cls%(extraparams)s)\n'
1106         '{\n'
1107         '    %(vtable)s *iface;\n'
1108         '%(varlist)s'
1109         '%(parseargs)s'
1110         '%(codebefore)s'
1111         '    iface = g_type_interface_peek('
1112         'g_type_class_peek(pyg_type_from_object(cls)), %(typecode)s);\n'
1113         '    if (iface->%(virtual)s)\n'
1114         '        %(setreturn)siface->%(virtual)s(%(arglist)s);\n'
1115         '    else {\n'
1116         '        PyErr_SetString(PyExc_NotImplementedError, '
1117         '"interface method %(name)s not implemented");\n'
1118         '        return NULL;\n'
1119         '    }\n'
1120         '%(codeafter)s\n'
1121         '}\n\n'
1122         )
1123
1124     def get_initial_class_substdict(self):
1125         return { 'tp_basicsize'      : 'PyObject',
1126                  'tp_weaklistoffset' : '0',
1127                  'tp_dictoffset'     : '0'}
1128
1129     def write_constructor(self):
1130         # interfaces have no constructors ...
1131         return '0'
1132     def write_getsets(self):
1133         # interfaces have no fields ...
1134         return '0'
1135
1136     def _get_class_virtual_substdict(self, meth, cname, parent):
1137         substdict = self.get_initial_method_substdict(meth)
1138         substdict['virtual'] = meth.name
1139         substdict['cname'] = cname
1140         substdict['typecode'] = self.objinfo.typecode
1141         substdict['vtable'] = self.objinfo.vtable
1142         return substdict
1143
1144     def write_virtuals(self):
1145         ## Now write reverse method wrappers, which let python code
1146         ## implement interface methods.
1147         # First, get methods from the defs files
1148         klass = self.objinfo.c_name
1149         proxies = []
1150         for meth in self.parser.find_virtuals(self.objinfo):
1151             method_name = self.objinfo.c_name + "__proxy_do_" + meth.name
1152             if self.overrides.is_ignored(method_name):
1153                 continue
1154             try:
1155                 if self.overrides.is_overriden(method_name):
1156                     if not self.overrides.is_already_included(method_name):
1157                         data = self.overrides.override(method_name)
1158                         self.write_function(method_name, data)
1159                 else:
1160                     # write proxy ...
1161                     ret, props = argtypes.matcher.get_reverse_ret(meth.ret)
1162                     wrapper = reversewrapper.ReverseWrapper(
1163                         '_wrap_' + method_name, is_static=True)
1164                     wrapper.set_return_type(ret(wrapper, **props))
1165                     wrapper.add_parameter(reversewrapper.PyGObjectMethodParam(
1166                         wrapper, "self", method_name="do_" + meth.name,
1167                         c_type=(klass + ' *')))
1168                     for param in meth.params:
1169                         handler, props = argtypes.matcher.get_reverse(
1170                             param.ptype)
1171                         props["direction"] = param.pdir
1172                         props["nullok"] = param.pnull
1173                         wrapper.add_parameter(
1174                             handler(wrapper, param.pname, **props))
1175                     buf = reversewrapper.MemoryCodeSink()
1176                     wrapper.generate(buf)
1177                     self.fp.write(buf.flush())
1178                 proxies.append((fixname(meth.name), '_wrap_' + method_name))
1179                 iproxies_coverage.declare_wrapped()
1180             except argtypes.ArgTypeError, ex:
1181                 iproxies_coverage.declare_not_wrapped()
1182                 proxies.append((fixname(meth.name), None))
1183                 sys.stderr.write('Could not write interface proxy %s.%s: %s\n'
1184                                 % (klass, meth.name, str(ex)))
1185
1186         if not proxies or not [cname for name, cname in proxies if cname]:
1187             return
1188
1189         ## Write an interface init function for this object
1190         funcname = "__%s__interface_init" % klass
1191         vtable = self.objinfo.vtable
1192         self.fp.write(
1193             '\nstatic void\n'
1194             '%(funcname)s(%(vtable)s *iface, PyTypeObject *pytype)\n'
1195             '{\n'
1196             '    %(vtable)s *parent_iface = '
1197             'g_type_interface_peek_parent(iface);\n'
1198             '    PyObject *py_method;\n'
1199             '\n'
1200             % vars())
1201
1202         for name, cname in proxies:
1203             do_name = 'do_' + name
1204             if cname is None:
1205                 continue
1206
1207             self.fp.write((
1208                 '    py_method = pytype? PyObject_GetAttrString('
1209                 '(PyObject *) pytype, "%(do_name)s") : NULL;\n'
1210                 '    if (py_method && !PyObject_TypeCheck(py_method, '
1211                 '&PyCFunction_Type)) {\n'
1212                 '        iface->%(name)s = %(cname)s;\n'
1213                 '    } else {\n'
1214                 '        PyErr_Clear();\n'
1215                 '        if (parent_iface) {\n'
1216                 '            iface->%(name)s = parent_iface->%(name)s;\n'
1217                 '        }\n'
1218                 '    Py_XDECREF(py_method);\n'
1219                 '    }\n'
1220                 ) % vars())
1221         self.fp.write('}\n\n')
1222         interface_info = "__%s__iinfo" % klass
1223         self.fp.write('''
1224 static const GInterfaceInfo %s = {
1225     (GInterfaceInitFunc) %s,
1226     NULL,
1227     NULL
1228 };
1229 ''' % (interface_info, funcname))
1230         self.objinfo.interface_info = interface_info
1231
1232 class GBoxedWrapper(Wrapper):
1233     constructor_tmpl = (
1234         'static int\n'
1235         '_wrap_%(cname)s(PyGBoxed *self%(extraparams)s)\n'
1236         '{\n'
1237         '%(varlist)s'
1238         '%(parseargs)s'
1239         '%(codebefore)s'
1240         '    self->gtype = %(typecode)s;\n'
1241         '    self->free_on_dealloc = FALSE;\n'
1242         '    self->boxed = %(cname)s(%(arglist)s);\n'
1243         '%(codeafter)s\n'
1244         '    if (!self->boxed) {\n'
1245         '        PyErr_SetString(PyExc_RuntimeError, '
1246         '"could not create %(typename)s object");\n'
1247         '        return -1;\n'
1248         '    }\n'
1249         '    self->free_on_dealloc = TRUE;\n'
1250         '    return 0;\n'
1251         '}\n\n'
1252         )
1253
1254     method_tmpl = (
1255         'static PyObject *\n'
1256         '_wrap_%(cname)s(PyObject *self%(extraparams)s)\n'
1257         '{\n'
1258         '%(varlist)s'
1259         '%(parseargs)s'
1260         '%(codebefore)s'
1261         '    %(begin_allow_threads)s\n'
1262         '    %(setreturn)s%(cname)s(pyg_boxed_get(self, '
1263         '%(typename)s)%(arglist)s);\n'
1264         '    %(end_allow_threads)s\n'
1265         '%(codeafter)s\n'
1266         '}\n\n'
1267         )
1268
1269     def get_initial_class_substdict(self):
1270         return { 'tp_basicsize'      : 'PyGBoxed',
1271                  'tp_weaklistoffset' : '0',
1272                  'tp_dictoffset'     : '0' }
1273
1274     def get_field_accessor(self, fieldname):
1275         return 'pyg_boxed_get(self, %s)->%s' % (self.objinfo.c_name, fieldname)
1276
1277     def get_initial_constructor_substdict(self, constructor):
1278         substdict = Wrapper.get_initial_constructor_substdict(
1279             self, constructor)
1280         substdict['typecode'] = self.objinfo.typecode
1281         return substdict
1282
1283 class GPointerWrapper(GBoxedWrapper):
1284     constructor_tmpl = (
1285         'static int\n'
1286         '_wrap_%(cname)s(PyGPointer *self%(extraparams)s)\n'
1287         '{\n'
1288         '%(varlist)s'
1289         '%(parseargs)s'
1290         '%(codebefore)s'
1291         '    self->gtype = %(typecode)s;\n'
1292         '    self->pointer = %(cname)s(%(arglist)s);\n'
1293         '%(codeafter)s\n'
1294         '    if (!self->pointer) {\n'
1295         '        PyErr_SetString(PyExc_RuntimeError, '
1296         '"could not create %(typename)s object");\n'
1297         '        return -1;\n'
1298         '    }\n'
1299         '    return 0;\n'
1300         '}\n\n'
1301         )
1302
1303     method_tmpl = (
1304         'static PyObject *\n'
1305         '_wrap_%(cname)s(PyObject *self%(extraparams)s)\n'
1306         '{\n'
1307         '%(varlist)s'
1308         '%(parseargs)s'
1309         '%(codebefore)s'
1310         '    %(setreturn)s%(cname)s(pyg_pointer_get(self, '
1311         '%(typename)s)%(arglist)s);\n'
1312         '%(codeafter)s\n'
1313         '}\n\n'
1314         )
1315
1316     def get_initial_class_substdict(self):
1317         return { 'tp_basicsize'      : 'PyGPointer',
1318                  'tp_weaklistoffset' : '0',
1319                  'tp_dictoffset'     : '0' }
1320
1321     def get_field_accessor(self, fieldname):
1322         return 'pyg_pointer_get(self, %s)->%s' % (self.objinfo.c_name,
1323                                                   fieldname)
1324
1325     def get_initial_constructor_substdict(self, constructor):
1326         substdict = Wrapper.get_initial_constructor_substdict(
1327             self, constructor)
1328         substdict['typecode'] = self.objinfo.typecode
1329         return substdict
1330
1331 class SourceWriter:
1332     def __init__(self, parser, overrides, prefix, fp=FileOutput(sys.stdout)):
1333         self.parser = parser
1334         self.overrides = overrides
1335         self.prefix = prefix
1336         self.fp = fp
1337
1338     def write(self, py_ssize_t_clean=False):
1339         argtypes.py_ssize_t_clean = py_ssize_t_clean
1340
1341         self.write_headers(py_ssize_t_clean)
1342         self.write_imports()
1343         self.write_type_declarations()
1344         self.write_body()
1345         self.write_classes()
1346
1347         wrapper = Wrapper(self.parser, None, self.overrides, self.fp)
1348         wrapper.write_functions(self, self.prefix)
1349
1350         if not self.overrides.dynamicnamespace:
1351             self.write_enums()
1352         self.write_extension_init()
1353         self.write_registers()
1354         
1355         argtypes.py_ssize_t_clean = False
1356
1357     def write_headers(self, py_ssize_t_clean):
1358         self.fp.write('/* -- THIS FILE IS GENERATED - DO NOT EDIT */')
1359         self.fp.write('/* -*- Mode: C; c-basic-offset: 4 -*- */\n\n')
1360         if py_ssize_t_clean:
1361             self.fp.write('#define PY_SSIZE_T_CLEAN\n')
1362         self.fp.write('#include <Python.h>\n\n\n')
1363         if py_ssize_t_clean:
1364             self.fp.write('''
1365
1366 #if PY_VERSION_HEX < 0x02050000
1367 typedef int Py_ssize_t;
1368 #define PY_SSIZE_T_MAX INT_MAX
1369 #define PY_SSIZE_T_MIN INT_MIN
1370 typedef inquiry lenfunc;
1371 typedef intargfunc ssizeargfunc;
1372 typedef intobjargproc ssizeobjargproc;
1373 #endif
1374
1375 ''')
1376         self.fp.write(self.overrides.get_headers())
1377         self.fp.resetline()
1378         self.fp.write('\n\n')
1379
1380     def write_imports(self):
1381         self.fp.write('/* ---------- types from other modules ---------- */\n')
1382         for module, pyname, cname, importing_for in self.overrides.get_imports():
1383             if importing_for is None or is_registered_object(importing_for):
1384                 self.fp.write('static PyTypeObject *_%s;\n' % cname)
1385                 self.fp.write('#define %s (*_%s)\n' % (cname, cname))
1386         self.fp.write('\n\n')
1387
1388     def write_type_declarations(self):
1389         #todo use 'static' if used only in one file
1390         self.fp.write('/* ---------- forward type declarations ---------- */\n')
1391         for obj in self.parser.boxes:
1392             if not self.overrides.is_type_ignored(obj.c_name):
1393                 self.fp.write('PyTypeObject G_GNUC_INTERNAL Py' + obj.c_name + '_Type;\n')
1394         for obj in self.parser.objects:
1395             if not self.overrides.is_type_ignored(obj.c_name):
1396                 self.fp.write('PyTypeObject G_GNUC_INTERNAL Py' + obj.c_name + '_Type;\n')
1397         for interface in self.parser.interfaces:
1398             if not self.overrides.is_type_ignored(interface.c_name):
1399                 self.fp.write('PyTypeObject G_GNUC_INTERNAL Py' + interface.c_name + '_Type;\n')
1400         self.fp.write('\n')
1401
1402     def write_body(self):
1403         self.fp.write(self.overrides.get_body())
1404         self.fp.resetline()
1405         self.fp.write('\n\n')
1406
1407     def _sort_parent_children(self, objects):
1408         objects = list(objects)
1409         modified = True
1410         while modified:
1411             modified = False
1412             parent_index = None
1413             child_index = None
1414             for i, obj in enumerate(objects):
1415                 if obj.parent == 'GObject':
1416                     continue
1417                 if obj.parent not in [info.c_name for info in objects[:i]]:
1418                     for j, info in enumerate(objects[i+1:]):
1419                         if info.c_name == obj.parent:
1420                             parent_index = i + 1 + j
1421                             child_index = i
1422                             break
1423                     else:
1424                         continue
1425                     break
1426             if child_index is not None and parent_index is not None:
1427                 if child_index != parent_index:
1428                     objects.insert(child_index, objects.pop(parent_index))
1429                     modified = True
1430         return objects
1431
1432     def write_classes(self):
1433         ## Sort the objects, so that we generate code for the parent types
1434         ## before their children.
1435         objects = self._sort_parent_children(self.parser.objects)
1436
1437         for klass, items in ((GBoxedWrapper, self.parser.boxes),
1438                              (GPointerWrapper, self.parser.pointers),
1439                              (GObjectWrapper, objects),
1440                              (GInterfaceWrapper, self.parser.interfaces)):
1441             for item in items:
1442                 instance = klass(self.parser, item, self.overrides, self.fp)
1443                 instance.write_class()
1444                 self.fp.write('\n')
1445
1446     def get_enums(self):
1447         enums = []
1448         for enum in self.parser.enums:
1449             if self.overrides.is_type_ignored(enum.c_name):
1450                 continue
1451             enums.append(enum)
1452         return enums
1453
1454     def write_enums(self):
1455         if not self.parser.enums:
1456             return
1457
1458         self.fp.write('\n/* ----------- enums and flags ----------- */\n\n')
1459         self.fp.write(
1460             'void\n' + self.prefix +
1461             '_add_constants(PyObject *module, const gchar *strip_prefix)\n{\n')
1462
1463         self.fp.write(
1464             '#ifdef VERSION\n'
1465             '    PyModule_AddStringConstant(module, "__version__", VERSION);\n'
1466             '#endif\n')
1467
1468         for enum in self.get_enums():
1469             if enum.typecode is None:
1470                 for nick, value in enum.values:
1471                     self.fp.write(
1472                         '    PyModule_AddIntConstant(module, '
1473                         '(char *) pyg_constant_strip_prefix("%s", strip_prefix), %s);\n'
1474                         % (value, value))
1475             else:
1476                 if enum.deftype == 'enum':
1477                     self.fp.write('  pyg_enum_add(module, "%s", strip_prefix, %s);\n'
1478                                   % (enum.name, enum.typecode))
1479                 else:
1480                     self.fp.write('  pyg_flags_add(module, "%s", strip_prefix, %s);\n'
1481                                   % (enum.name, enum.typecode))
1482
1483         self.fp.write('\n')
1484         self.fp.write('  if (PyErr_Occurred())\n')
1485         self.fp.write('    PyErr_Print();\n')
1486         self.fp.write('}\n\n')
1487
1488     def write_object_imports(self, retval=''):
1489         imports = self.overrides.get_imports()[:]
1490         if not imports:
1491             return
1492
1493         bymod = {}
1494         for module, pyname, cname, importing_for in imports:
1495             if importing_for is None or is_registered_object(importing_for):
1496                 bymod.setdefault(module, []).append((pyname, cname))
1497         self.fp.write('    PyObject *module;\n\n')
1498         for module in bymod:
1499             self.fp.write(
1500                 '    if ((module = PyImport_ImportModule("%s")) != NULL) {\n'
1501                 % module)
1502             #self.fp.write(
1503             #    '        PyObject *moddict = PyModule_GetDict(module);\n\n')
1504             for pyname, cname in bymod[module]:
1505                 #self.fp.write(
1506                 #    '        _%s = (PyTypeObject *)PyDict_GetItemString('
1507                 #    'moddict, "%s");\n' % (cname, pyname))
1508                 self.fp.write(
1509                     '        _%s = (PyTypeObject *)PyObject_GetAttrString('
1510                     'module, "%s");\n' % (cname, pyname))
1511                 self.fp.write('        if (_%s == NULL) {\n' % cname)
1512                 self.fp.write('            PyErr_SetString(PyExc_ImportError,\n')
1513                 self.fp.write('                "cannot import name %s from %s");\n'
1514                          % (pyname, module))
1515                 self.fp.write('            return %s;\n' % retval)
1516                 self.fp.write('        }\n')
1517             self.fp.write('    } else {\n')
1518             self.fp.write('        PyErr_SetString(PyExc_ImportError,\n')
1519             self.fp.write('            "could not import %s");\n' % module)
1520             self.fp.write('        return %s;\n' % retval)
1521             self.fp.write('    }\n')
1522         self.fp.write('\n')
1523
1524     def write_extension_init(self):
1525         self.fp.write('/* initialise stuff extension classes */\n')
1526         self.fp.write('void\n' + self.prefix + '_register_classes(PyObject *d)\n{\n')
1527         self.write_object_imports()
1528         self.fp.write(self.overrides.get_init() + '\n')
1529         self.fp.resetline()
1530
1531     def get_classes(self):
1532         objects = self.parser.objects[:]
1533         pos = 0
1534         while pos < len(objects):
1535             parent = objects[pos].parent
1536             for i in range(pos+1, len(objects)):
1537                 if objects[i].c_name == parent:
1538                     objects.insert(i+1, objects[pos])
1539                     del objects[pos]
1540                     break
1541             else:
1542                 pos = pos + 1
1543
1544         retval = []
1545         for obj in objects:
1546             if self.overrides.is_type_ignored(obj.c_name):
1547                 continue
1548             bases = []
1549             if obj.parent != None:
1550                 bases.append(obj.parent)
1551             bases = bases + obj.implements
1552             retval.append((obj, bases))
1553
1554         return retval
1555
1556     def write_registers(self):
1557         for boxed in self.parser.boxes:
1558             if not self.overrides.is_type_ignored(boxed.c_name):
1559                 self.fp.write('    pyg_register_boxed(d, "' + boxed.name +
1560                               '", ' + boxed.typecode +
1561                               ', &Py' + boxed.c_name +
1562                           '_Type);\n')
1563         for pointer in self.parser.pointers:
1564             if not self.overrides.is_type_ignored(pointer.c_name):
1565                 self.fp.write('    pyg_register_pointer(d, "' + pointer.name +
1566                               '", ' + pointer.typecode +
1567                               ', &Py' + pointer.c_name + '_Type);\n')
1568         for interface in self.parser.interfaces:
1569             if not self.overrides.is_type_ignored(interface.c_name):
1570                 self.fp.write('    pyg_register_interface(d, "'
1571                               + interface.name + '", '+ interface.typecode
1572                               + ', &Py' + interface.c_name + '_Type);\n')
1573                 if interface.interface_info is not None:
1574                     self.fp.write('    pyg_register_interface_info(%s, &%s);\n' %
1575                                   (interface.typecode, interface.interface_info))
1576
1577         if not self.overrides.dynamicnamespace:
1578             for obj, bases in self.get_classes():
1579                 self.write_class(obj, bases)
1580         else:
1581             for obj, bases in self.get_classes():
1582                 self.fp.write(
1583                     '    pyg_type_register_custom_callback("%s", '
1584                     '(PyGTypeRegistrationFunction)%s_register_type, d);\n' %
1585                     (obj.c_name, obj.c_name))
1586
1587         self.fp.write('}\n')
1588
1589     def _can_direct_ref(self, base):
1590         if not self.overrides.dynamicnamespace:
1591             return True
1592         if base == 'GObject':
1593             return True
1594         obj = get_object_by_name(base)
1595         if obj.module.lower() != self.overrides.modulename:
1596             return True
1597         return False
1598
1599     def write_class(self, obj, bases, indent=1):
1600         indent_str = ' ' * (indent * 4)
1601         if bases:
1602             bases_str = 'Py_BuildValue("(%s)"' % (len(bases) * 'O')
1603
1604             for base in bases:
1605                 if self._can_direct_ref(base):
1606                     bases_str += ', &Py%s_Type' % base
1607                 else:
1608                     baseobj = get_object_by_name(base)
1609                     bases_str += ', PyObject_GetAttrString(m, "%s")' % baseobj.name
1610             bases_str += ')'
1611         else:
1612             bases_str = 'NULL'
1613
1614         self.fp.write(
1615                 '%(indent)spygobject_register_class(d, "%(c_name)s", %(typecode)s, &Py%(c_name)s_Type, %(bases)s);\n'
1616                 % dict(indent=indent_str, c_name=obj.c_name, typecode=obj.typecode, bases=bases_str))
1617
1618         if obj.has_new_constructor_api:
1619             self.fp.write(
1620                 indent_str + 'pyg_set_object_has_new_constructor(%s);\n' %
1621                 obj.typecode)
1622         else:
1623             print >> sys.stderr, (
1624                 "Warning: Constructor for %s needs to be updated to new API\n"
1625                 "         See http://live.gnome.org/PyGTK_2fWhatsNew28"
1626                 "#update-constructors") % obj.c_name
1627
1628         if obj.class_init_func is not None:
1629             self.fp.write(
1630                 indent_str + 'pyg_register_class_init(%s, %s);\n' %
1631                 (obj.typecode, obj.class_init_func))
1632
1633 _objects = {}
1634
1635 def is_registered_object(c_name):
1636     return c_name in _objects
1637
1638 def get_object_by_name(c_name):
1639     global _objects
1640     return _objects[c_name]
1641
1642 def register_types(parser):
1643     global _objects
1644     for boxed in parser.boxes:
1645         argtypes.matcher.register_boxed(boxed.c_name, boxed.typecode)
1646         _objects[boxed.c_name] = boxed
1647     for pointer in parser.pointers:
1648         argtypes.matcher.register_pointer(pointer.c_name, pointer.typecode)
1649     for obj in parser.objects:
1650         argtypes.matcher.register_object(obj.c_name, obj.parent, obj.typecode)
1651         _objects[obj.c_name] = obj
1652     for iface in parser.interfaces:
1653         argtypes.matcher.register_object(iface.c_name, None, iface.typecode)
1654         _objects[iface.c_name] = iface
1655     for enum in parser.enums:
1656         if enum.deftype == 'flags':
1657             argtypes.matcher.register_flag(enum.c_name, enum.typecode)
1658         else:
1659             argtypes.matcher.register_enum(enum.c_name, enum.typecode)
1660
1661 usage = 'usage: codegen.py [-o overridesfile] [-p prefix] defsfile'
1662 def main(argv):
1663     o = override.Overrides()
1664     prefix = 'pygtk'
1665     outfilename = None
1666     errorfilename = None
1667     opts, args = getopt.getopt(argv[1:], "o:p:r:t:D:I:",
1668                         ["override=", "prefix=", "register=", "outfilename=",
1669                          "load-types=", "errorfilename=", "py_ssize_t-clean"])
1670     defines = {} # -Dkey[=val] options
1671     py_ssize_t_clean = False
1672     for opt, arg in opts:
1673         if opt in ('-o', '--override'):
1674             o = override.Overrides(arg)
1675         elif opt in ('-p', '--prefix'):
1676             prefix = arg
1677         elif opt in ('-r', '--register'):
1678             # Warning: user has to make sure all -D options appear before -r
1679             p = defsparser.DefsParser(arg, defines)
1680             p.startParsing()
1681             register_types(p)
1682             del p
1683         elif opt == '--outfilename':
1684             outfilename = arg
1685         elif opt == '--errorfilename':
1686             errorfilename = arg
1687         elif opt in ('-t', '--load-types'):
1688             globals = {}
1689             execfile(arg, globals)
1690         elif opt == '-D':
1691             nameval = arg.split('=')
1692             try:
1693                 defines[nameval[0]] = nameval[1]
1694             except IndexError:
1695                 defines[nameval[0]] = None
1696         elif opt == '-I':
1697             defsparser.include_path.insert(0, arg)
1698         elif opt == '--py_ssize_t-clean':
1699             py_ssize_t_clean = True
1700     if len(args) < 1:
1701         print >> sys.stderr, usage
1702         return 1
1703     if errorfilename:
1704         sys.stderr = open(errorfilename, "w")
1705     p = defsparser.DefsParser(args[0], defines)
1706     if not outfilename:
1707         outfilename = os.path.splitext(args[0])[0] + '.c'
1708
1709     p.startParsing()
1710
1711     register_types(p)
1712     sw = SourceWriter(p, o, prefix, FileOutput(sys.stdout, outfilename))
1713     sw.write(py_ssize_t_clean)
1714
1715     functions_coverage.printstats()
1716     methods_coverage.printstats()
1717     vproxies_coverage.printstats()
1718     vaccessors_coverage.printstats()
1719     iproxies_coverage.printstats()
1720
1721 if __name__ == '__main__':
1722     sys.exit(main(sys.argv))