gintro/tests/gen.nim
Stefan Salewski 8a59ea33d0 various fixes
2019-04-14 12:56:38 +02:00

2179 lines
90 KiB
Nim

# High level gobject-introspection based GTK3 bindings for the Nim programming language
# v 0.4.12 2019-APR-14
# (c) S. Salewski 2018
# https://wiki.gnome.org/Projects/GObjectIntrospection
# https://developer.gnome.org/gi/1.50/index.html
# https://mail.gnome.org/archives/gtk-devel-list/2005-April/msg00095.html
# /usr/share/gir-1.0/GLib-2.0.gir
# you may also compare the currently unmaintained work of
# https://github.com/jdmansour/nim-smartgi
# This module itself is still based on the low level GTK 3.22 wrappers at
# https://github.com/StefanSalewski/oldgtk3
# Currently we intentionally do not free any resources!
# First goal is creating low level bindings similar to current oldgtk3. #XXX DONE
# Then we will add the high level wrapper similar as done in Nim's libui wrapper. #XXX Mostly DONE
# What remains is carefully inspecting the generated code, adding special like list/array results
# and of course a lot of testing.
# Known gobject-introspection related issues:
# - gFieldInfoGetSize() is always zero, so we have no bitfield support yet.
# - ParamSpec is reported as object, but has no parent
# - gBaseInfoGetName() is "" for g_iconv()
# - dirSep is wrong for unix -- that is an already reported gi bug
# - well there are more than 180 open issues about gobject introspection in gnome bugzilla :-(
# -
# This module is really ugly currently -- the first goal was to get a working gi solution
from os import `/`
import gir
import glib
import strutils
import sequtils
import streams
import sets
import bitops
import tables
import algorithm
from combinatorics import combinations
template isCallbackInfo(info: untyped): untyped =
(gBaseInfoGetType(cast[GIBaseInfo](info)) == GIInfoType.Callback)
template isFunctionInfo(info: untyped): untyped =
(gBaseInfoGetType(cast[GIBaseInfo](info)) == GIInfoType.Function)
const EM = "*"
const RecSep = "!" # Record separator for entries in gisup.nim, also defined in gimpl.nim
# hope that will work reliable
proc cut(s: var StringStream; pos: int) =
assert(pos >= 0 and pos <= s.getPosition)
s.setPosition(pos)
s.data.setLen(pos)
s.setPosition(pos)
var moduleNamespace: string
let libprag: string = "libprag"
let keywords = """
addr and as asm atomic bind block break case cast concept const continue converter
defer discard distinct div do elif else end enum except export finally for from func
generic if import in include interface is isnot iterator let macro method mixin mod
nil not notin object of or out proc ptr raise ref return shl shr static template try tuple
type using var when while with without xor yield
"""
let nims = """
int int8 int16 int32 int64 uint uint8 uint16 uint32 uint64 float float32 float64 pointer false true string char bool
"""
proc mysnakeToCamel(s: cstring): string =
var i, j: int
result = newString(s.len)
if s[i] == '_': inc(i)
while true:
if s[i] == '_' and (s[i + 1] == '\0' or s[i + 1] == '_'):
inc(i)
elif (s[i] == '_' or s[i] == '-') and s[i + 1].isLowerAscii and not s[i - 1].isUpperAscii:
inc(i)
result[j] = toUpperAscii(s[i])
inc(i)
inc(j)
else:
result[j] = s[i]
inc(i)
inc(j)
if s[i] == '\0':
result.setLen(j)
break
if result[0] == '\0': # this may result, so we emit a dummy name as marker
result = "QQQ"
#assert(false)
proc renumber(s: var string; i: int) =
var h = ""
if s[^1].isDigit:
h.add(s[^1])
setLen(s, s.len - 1)
s.add($i)
s.add(h)
var defaultParameters = newTable[string, string]()
var fixedProcNames = newTable[string, string]()
var mangledNames = newTable[string, string]()
var gdkKeys = newTable[string, seq[string]]()
var allSyms: HashSet[string]
var provInt = newTable[string, seq[string]]()
var interfaceProvider = newTable[string, seq[string]]()
var priList: seq[string]
var knownSyms: HashSet[string]
var suppressType = false
var suppressRaise = false
var droppedSyms = initHashSet[string]()
var callerAlloc = initHashSet[string]()
var callerAllocCollector = initHashSet[string]()
var privStr = initHashSet[string]()
var processedFunctions = initHashSet[string]()
var delayedMethods: seq[(GIBaseInfo, GIFunctionInfo)]
var classList: seq[GIBaseInfo]
var ct: CountTable[string]
fixedProcNames.add("gtk_button_new_with_label", "newButton")
fixedProcNames.add("pango_font_description_from_string", "newFontDescription")
fixedProcNames.add("pango_language_from_string", "languageFromString")
fixedProcNames.add("atk_role_register", "registerAtkRole")
fixedProcNames.add("atk_state_type_register", "registerStateType")
fixedProcNames.add("atk_relation_type_register", "registerRelationType")
fixedProcNames.add("atk_text_attribute_register", "registerTextAttribute")
fixedProcNames.add("atk_role_for_name", "roleForName")
fixedProcNames.add("atk_state_type_for_name", "stateTypeForName")
fixedProcNames.add("atk_relation_type_for_name", "relationTypeForName")
fixedProcNames.add("atk_text_attribute_for_name", "textAttributeForName")
fixedProcNames.add("gtk_settings_get_for_screen", "getSettingsForScreen")
fixedProcNames.add("gtk_icon_theme_get_for_screen", "getIconThemeForScreen")
fixedProcNames.add("gtk_requisition_new", "newRequisition")
fixedProcNames.add("gtk_text_attributes_new", "newTextAttributes")
fixedProcNames.add("pango_script_for_unichar", "scriptForUnichar")
fixedProcNames.add("pango_bidi_type_for_unichar", "bidiTypeForUnichar")
defaultParameters.add("gtk_window_new", "`type` WindowType WindowType.toplevel")
defaultParameters.add("gtk_application_new", "flags gio.ApplicationFlags {}")
for i in keywords.split: mangledNames.add(i, '`' & i & '`')
mangledNames.add("CSET_A_2_Z", "CSET_A_2_Z_U")
mangledNames.add("CSET_a_2_z", "CSET_a_2_z_L")
mangledNames.add("2big", "tooBig")
mangledNames.add("2buttonPress", "twoButtonPress")
mangledNames.add("3buttonPress", "threeButtonPress")
mangledNames.add("result", "resu")
proc gBaseInfoGetName(info: GIBaseInfo): string =
result = $(gir.gBaseInfoGetName(info))
let h = $(gir.gBaseInfoGetNamespace(info))
if h == "Gio" and result == "Application":
result = "GApplication"
proc mangleName(s: cstring): string =
result = mysnakeToCamel(s)
if mangledNames.contains(result):
result = mangledNames[result]
if result == "``":
# assert(false)
result = "xxx" # XXX
var mangledTypes = newTable[string, string]()
mangledTypes.add("gint8", "int8")
mangledTypes.add("gint16", "int16")
mangledTypes.add("gint32", "int32")
mangledTypes.add("gint64", "int64")
mangledTypes.add("guint8", "uint8")
mangledTypes.add("guint16", "uint16")
mangledTypes.add("guint32", "uint32")
mangledTypes.add("guint64", "uint64")
mangledTypes.add("gfloat", "cfloat")
mangledTypes.add("gdouble", "cdouble")
mangledTypes.add("ptr void", "pointer")
#mangledTypes.add("ptr filename", "ucstring") # WRONG, var deleted to make it compile!
mangledTypes.add("ptr filename", "cstring")
mangledTypes.add("ptr error", "ptr Error00")
mangledTypes.add("ptr ghash", "ptr HashTable00")
mangledTypes.add("ptr glist", "ptr pointer")
mangledTypes.add("ptr gslist", "ptr pointer")
mangledTypes.add("ptr utf8", "cstring")
droppedSyms.incl("MININT8")
droppedSyms.incl("MININT16")
droppedSyms.incl("MININT32")
droppedSyms.incl("MININT64")
# we may have to add digits to avoid name conflicts due to inheritance
privStr.incl("privat")
privStr.incl("priv")
privStr.incl("padding")
privStr.incl("pad")
privStr.incl("unused")
privStr.incl("privateData")
callerAlloc.incl("atk.Rectangle") # ATK has TextRectangle and Rectangle!
callerAlloc.incl("pango.Color") # we have to add these manually -- maybe there are more plain structs to add
const CA_Items = """
pango.Style
pango.Stretch
glib.MarkupParser
glib.TimeVal
gtk.TextIter
pango.Weight
gdk.Rectangle
gtk.AccelKey
gtksource.RegionIter
gtk.TextAttributes
gobject.Value
gobject.SignalQuery
gobject.TypeQuery
gtk.TreeIter
gtk.StockItem
glib.String
gdk.Atom
rsvg.PositionData
rsvg.DimensionData
pango.Variant
gdk.Color
gtk.Border
atk.TextRectangle
gdk.RGBA
pango.Rectangle
gtk.Requisition
"""
for i in CA_Items.split:
callerAlloc.incl(i)
type
UndefEx = object of Exception
proc mangleType(s: cstring): string =
result = mangleName(s)
if mangledTypes.contains(result):
result = mangledTypes[result]
if allSyms.contains(result) and not knownSyms.contains(result):
if not suppressRaise:
pri_list.add(result)
raise newException(UndefEx, "forward declaration")
else:
echo "!!!", result
var output: StringStream
var supmod: StringStream
var methodBuffer: StringStream
var signalBuffer: StringStream
proc genP(info: GICallableInfo; genProxy = false; binfo: GIBaseInfo = nil): (string, string, TableRef[string, string])
proc isString(t: GITypeInfo): bool =
let tag = gTypeInfoGetTag(t)
tag == GITypeTag.UTF8 or tag == GITypeTag.FILENAME
# recursive investigate that type -- resolve Arrays and Interfaces
proc genRec(t: GITypeInfo; genProxy = false; fullQualified: bool = false): string =
var rawmark = ""
var proxyResult = false#callerAllocCollector
let p = gTypeInfoIsPointer(t)
let tag = gTypeInfoGetTag(t)
if tag == GITypeTag.ARRAY:
let toa = gTypeInfoGetArrayType(t) # type of array
if toa == GIArrayType.ARRAY: result = "GArray00"
elif toa == GIArrayType.PTR_ARRAY: result = "PtrArray00"
elif toa == GIArrayType.BYTE_ARRAY: result = "ByteArray00"
elif toa == GIArrayType.C:
let arrayType = gTypeInfoGetParamType(t, 0)
let arrayTag = gTypeInfoGetTag(arrayType)
let arrayFixedSize = gTypeInfoGetArrayFixedSize(t)
let arrayLength = gTypeInfoGetArrayLength(t)
let xxx = genRec(arrayType)
let child = mangleType(mangleName(genRec(arrayType)))
result = "array[$1, $2]" % [$arrayFixedSize, child]
if arrayFixedSize == -1:
result = child & "Array"
return
elif tag == GITypeTag.INTERFACE:
let iface = gTypeInfoGetInterface(t)
if gBaseInfoGetType(iface) == GIInfoType.CALLBACK:
if gBaseInfoGetName(iface)[0].isLowerAscii:
result = "proc" & genP(iface)[0] & " {.cdecl.}"
else:
result = mangleName(gBaseInfoGetName(iface))
else:
var ns = ($gBaseInfoGetNamespace(iface)).toLowerAscii
result = mangleName($gBaseInfoGetName(iface))
if ns == "cairo" and moduleNamespace == "pangocairo" and result == "FontType": return result # GI bug?
if gBaseInfoGetType(iface) == GIInfoType.Object or gBaseInfoGetType(iface) == GIInfoType.STRUCT or gBaseInfoGetType(iface) == GIInfoType.UNION or gBaseInfoGetType(iface) == GIInfoType.INTERFACE:
proxyResult = genProxy
if not (genProxy or callerAlloc.contains(ns & '.' & result)):
rawmark = "00"
if fullQualified or ns != moduleNamespace:
result = ns & '.' & result
else:
result = $gTypeTagToString(tag)
result = mangleType(result)
if p and (not proxyResult):
result = "ptr " & result
result = mangleType(result) & rawmark
proc isProxyCandidate(t: GITypeInfo): bool =
let tag = gTypeInfoGetTag(t)
#let tag = gTypeInfoGetTag(t)
#if tag == GITypeTag.ARRAY:
# let toa = gTypeInfoGetArrayType(t) # type of array
# if toa == GIArrayType.ARRAY: return true#result = "Array00"
if tag == GITypeTag.INTERFACE:
let iface = gTypeInfoGetInterface(t)
var ns = ($gBaseInfoGetNamespace(iface)).toLowerAscii
if callerAlloc.contains(ns & '.' & $gBaseInfoGetName(iface)): return false
if ns == "cairo" and moduleNamespace == "pangocairo" and $gBaseInfoGetName(iface) == "FontType": return false # GI bug?
result = gBaseInfoGetType(iface) in {GIInfoType.Object, GIInfoType.STRUCT, GIInfoType.UNION, GIInfoType.INTERFACE}
proc needProxyProc(info: GICallableInfo): bool =
result = gCallableInfoIsMethod(info)
let m = gCallableInfoGetNArgs(info) - 1
for j in 0.cint .. m:
let arg = gCallableInfoGetArg(info, j)
let t = gArgInfoGetType(arg)
if isProxyCandidate(t): result = true
var ret = gCallableInfoGetReturnType(info)
assert(ret != nil)
let tag = gTypeInfoGetTag(ret)
if isFunctionInfo(info):
if (gFunctionInfoGetFlags(info).int and GIFunctionInfoFlags.IS_CONSTRUCTOR.int) != 0:
let h = gBaseInfoGetContainer(info)
if gBaseInfoGetType(h) == GIInfoType.OBJECT:
result = true
return result
if isProxyCandidate(ret): result = true
var ct2nt = newTable[string, string]()
ct2nt.add("uint32", "int")
ct2nt.add("int32", "int")
ct2nt.add("cstring", "string")
ct2nt.add("gboolean", "bool")
proc ct3nt(s: string): string =
if not ct2nt.contains(s): return s
assert(ct2nt.contains(s))
result =
case s:
of "cstring": "$"
of "gboolean": "toBool"
else: ct2nt[s]
proc genP(info: GICallableInfo; genProxy = false; binfo: GIBaseInfo = nil): (string, string, TableRef[string, string]) =
var cutat = 50
var arglist: string
var resul: string
var replist = newTable[string, string]()
let m = gCallableInfoGetNArgs(info) - 1
var sym = ""
if isFunctionInfo(info):
sym = $gFunctionInfoGetSymbol(info)
if binfo.isNil or not gCallableInfoIsMethod(info):
resul = "("
arglist = "("
else:
var ns = ($gBaseInfoGetNamespace(binfo)).toLowerAscii
if callerAlloc.contains(ns & '.' & manglename(gBaseInfoGetName(binfo))):
resul = "(self: " & manglename(gBaseInfoGetName(binfo))
arglist = "(self"
else:
arglist = "(cast[ptr " & manglename(gBaseInfoGetName(binfo)) & "00](" & "self.impl)"
if genProxy:
var h = manglename(gBaseInfoGetName(binfo))
if interfaceProvider.contains(h):
let provider = interfaceProvider[h]
for i in provider: discard mangleType(i)
h = h & " | " & provider.join(" | ")
if (sym.startsWith("gdk_events_get_") or sym.startsWith("gdk_event_get_")) and h == "Event":
h = "SomeEvent"
resul = "(self: " & h
else:
resul = "(self: ptr " & manglename(gBaseInfoGetName(binfo)) & "00"
if m >= 0:
resul.add("; ")
arglist.add(", ")
for j in 0 .. m:
let arg = gCallableInfoGetArg(info, j)
let t = gArgInfoGetType(arg)
let mayBeNil = gArgInfoMayBeNull(arg)
if gArgInfoIsCallerAllocates(arg):
callerAllocCollector.incl(genRec(t, true, true))
var str = genRec(t, genProxy and not gArgInfoIsCallerAllocates(arg))
if (sym.startsWith("gtk_widget_set_events") or sym.startsWith("gtk_widget_add_events")) and str == "int32":
str = "gdk.EventMask"
if isSignalInfo(info) and isProxyCandidate(t) and not genProxy:
str.insert("ptr ")
var userAlloc: bool
if callerAlloc.contains(genRec(t, true, true)):
userAlloc = true
str = genRec(t, true)
if genProxy:
let tag = gTypeInfoGetTag(t)
if tag == GITypeTag.INTERFACE:
let iface = gTypeInfoGetInterface(t)
if gBaseInfoGetType(iface) == GIInfoType.INTERFACE:
if interfaceProvider.contains(str):
let provider = interfaceProvider[str]
for i in provider: discard mangleType(i)
str = str & " | " & provider.join(" | ")
if gArgInfoGetDirection(arg) == GIDirection.OUT or gArgInfoGetDirection(arg) == GIDirection.INOUT:
str.insert("(")
str.add(")")
let name = mangleName(gBaseInfoGetName(arg))
if isProxyCandidate(t) and not gArgInfoIsCallerAllocates(arg) and not userAlloc:
if mayBeNil and gArgInfoGetDirection(arg) != GIDirection.OUT:
arglist.add("if " & name & ".isNil: nil else: cast[" & genRec(t, false) & "](" & name & ".impl)")
else:
if gArgInfoGetDirection(arg) == GIDirection.OUT:
arglist.add("cast[var " & genRec(t, false) & "](addr " & name & ".impl)")
else:
arglist.add("cast[" & genRec(t, false) & "](" & name & ".impl)")
else:
if ct2nt.contains(str) and (gArgInfoGetDirection(arg) == GIDirection.OUT or gArgInfoGetDirection(arg) == GIDirection.INOUT):
let kk = if name[0] == '`': name[1 .. ^2] else: name
arglist.add(kk & "_00")
elif ct2nt.contains(str):
if str == "cstring" and mayBeNil:
arglist.add("safeStringToCString" & '(' & name & ')')################################################
else:
if str != "string" and str != "cstring": # v0.4.11
arglist.add(str & '(' & name & ')')
else:
arglist.add(name)
else:
arglist.add(name)
#if not genProxy and ct2nt.contains(str) and str != "cstring": # new in 0.4.11: for var pass Nim string, not cstring yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
if not genProxy and ct2nt.contains(str) and (str != "cstring" or (gArgInfoGetDirection(arg) == GIDirection.OUT or gArgInfoGetDirection(arg) == GIDirection.INOUT)):
replist.add($name, $str)
if genProxy and ct2nt.contains(str):
if gArgInfoGetDirection(arg) == GIDirection.OUT or gArgInfoGetDirection(arg) == GIDirection.INOUT:
replist.add($name, $str)
if gArgInfoGetDirection(arg) == GIDirection.OUT or gArgInfoGetDirection(arg) == GIDirection.INOUT or str != "cstring": # new in 0.4.11 -- allow passing cstring if not a var
str = ct2nt[str]
if gArgInfoGetDirection(arg) == GIDirection.OUT or gArgInfoGetDirection(arg) == GIDirection.INOUT: # caution cstringArray
str.insert("var ")
if genProxy and defaultParameters.contains(sym):
var h1, h2, h3: string
(h1, h2, h3) = defaultParameters[sym].split
if name == h1 and str == h2:
str.add(" = " & h3)
if genProxy and (str == "string" or str == "cstring") and mayBeNil: # v0.4.11
#str.add(" = nil")
str.add(" = \"\"")
if genProxy and m == 0:
if sym.contains("_set_") and str == "bool":
#echo "TTTTTTTTTT", sym
str.add(" = true")
if genProxy and isProxyCandidate(t) and mayBeNil:
#if not str.contains("|") and (gArgInfoGetDirection(arg) == GIDirection.OUT or gArgInfoGetDirection(arg) == GIDirection.INOUT):
# str.add(" = cast[" & str & "](nil)")
if gArgInfoGetDirection(arg) notin {GIDirection.OUT, GIDirection.INOUT}:
#if gArgInfoGetDirection(arg) == GIDirection.OUT or gArgInfoGetDirection(arg) == GIDirection.INOUT:
# discard
#else:
str.add(" = nil")
#str.add(" = \"\"")
if (genProxy or sym == "pango_extents_to_pixels") and isFunctionInfo(info) and (gFunctionInfoGetFlags(info).int and GIFunctionInfoFlags.WRAPS_VFUNC.ord) == 0:
if userAlloc and mayBeNil:
var h = str
if h.startsWith("var "): h = h[4 .. ^1]
str.add(" = cast[ptr " & h & "](nil)[]")
if (sym.startsWith("gdk_events_get_") or sym.startsWith("gdk_event_get_")) and str == "Event":
str = "SomeEvent"
resul.add(name & ": " & str)
if j < m:
resul.add("; ")
arglist.add(", ")
if resul.len > cutat:
cutat = 3 * cutat
resul.add("\n ")
if not genProxy and gCallableInfoCanThrowGerror(info):
if resul[^1] != '(': resul.add("; ")
resul.add("error: ptr ptr Error00 = nil")
resul.add(')')
arglist.add(')')
var ret = gCallableInfoGetReturnType(info)
assert(ret != nil)
let tag = gTypeInfoGetTag(ret)
if isFunctionInfo(info):
if (gFunctionInfoGetFlags(info).int and GIFunctionInfoFlags.IS_CONSTRUCTOR.int) != 0:
let h = gBaseInfoGetContainer(info)
if gBaseInfoGetType(h) == GIInfoType.OBJECT:
if genProxy:
resul.add(": " & mangleType(mangleName(gBaseInfoGetName(h))))
else:
resul.add(": ptr " & mangleType(mangleName(gBaseInfoGetName(h))) & "00")
return (resul, arglist, replist)
var r = genRec(ret, genProxy)
if gTypeInfoIsPointer(ret) and callerAlloc.contains(genRec(ret, true, true)) and (not r.startsWith("ptr")):
r = "ptr " & r
if r != "void":
if genProxy and ct2nt.contains(r):
r = ct2nt[r]
resul.add(": " & r)
return (resul, arglist, replist)
proc writeMethod(info: GIBaseInfo; minfo: GIFunctionInfo; genProxy = false) =
assert(isCallableInfo(mInfo))
assert(isFunctionInfo(mInfo))
var plist, arglist: string
var replist: TableRef[string, string]
let p = methodBuffer.getPosition
let sym = $gFunctionInfoGetSymbol(mInfo)
if sym[^1] == '_': return
if sym.contains("__"): return
if processedFunctions.contains(sym): return
if sym == "gtk_text_iter_copy": return
if sym == "gtk_widget_destroyed": return
if sym == "g_error_new_literal": return
#if not gCallableInfoIsMethod(minfo) and gCallableInfoGetNArgs(minfo) == 1:
# let arg = gCallableInfoGetArg(minfo, 0)
# let t = gArgInfoGetType(arg)
# if isString(t) and gTypeInfoGetTag(gCallableInfoGetReturnType(minfo)) != GITypeTag.VOID:
# echo "===#" & sym & " " & $manglename(gBaseInfoGetName(info))
for j in 0.cint ..< gCallableInfoGetNArgs(minfo):
let arg = gCallableInfoGetArg(minfo, j)
let t = gArgInfoGetType(arg)
if sym == "g_iconv":
return
try:
(plist, arglist, replist) = genP(mInfo, genProxy, info)
methodBuffer.write("\nproc " & sym & EM & plist)
methodBuffer.writeLine(" {.\n importc: \"", sym, "\", ", libprag, ".}")
processedFunctions.incl(sym)
if sym.contains("vte_regex_unref"): # this function is special, as it returns the object
methodBuffer.writeLine("\nproc unref*(self: Regex) =")
methodBuffer.writeLine(" discard vte_regex_unref(cast[ptr Regex00](self.impl))")
return
if sym.contains("g_param_spec_") or sym.contains("g_type_interface_") or sym.contains("g_object_interface_"): return # or sym.contains("g_value_"): return
if sym.contains("gtk_widget_class_find_style_property") or sym.contains("gtk_container_class_find_child_property"): return
#if sym.contains("gtk_cell_area_class_fi$manglename(gBaseInfoGetName(info)))nd_cell_property"): return
if sym.contains("gtk_cell_area_class_find_cell_property"): return
var asym = manglename(gBaseInfoGetName(mInfo))
if asym == "errorQuark" or asym == "quark": return
#[
# this does not work really well, so we do proc renaming manually using fixedProcNames seq.
if not info.isNil and not gCallableInfoIsMethod(minfo) and gCallableInfoGetNArgs(minfo) == 1:
let arg = gCallableInfoGetArg(minfo, 0)
let t = gArgInfoGetType(arg)
if isString(t) and gTypeInfoGetTag(gCallableInfoGetReturnType(minfo)) != GITypeTag.VOID:
echo "===#" & sym & " " & $manglename(gBaseInfoGetName(info))
asym[0] = asym[0].toUpperAscii
asym = $manglename(gBaseInfoGetName(info)) & asym
asym[0] = asym[0].toLowerAscii
]#
if asym == "get" or asym == "getDefault" or asym == "from" or asym == "fromString": # maybe we should relax this later a bit for the case that first parameter type == gBaseInfoGetName(info)
asym.add($manglename(gBaseInfoGetName(info)))
if sym == "gtk_buildable_get_name": asym = "buildableGetName" # conflict with gtk_widget_get_name()
if sym == "gtk_buildable_set_name": asym = "buildableSetName"
if keywords.split.contains(asym) or nims.split.contains(asym): asym.add('P')
var ret2 = gCallableInfoGetReturnType(minfo)
#var ret22 = gCallableInfoGetReturnType(minfo)
for run in 0 .. 1:
#if run == 0:
# if asym.startsWith("set"):
# if gCallableInfoGetNArgs(minfo) == 1 or (gCallableInfoIsMethod(minfo) and gCallableInfoGetNArgs(minfo) == 2):
# echo "XXXXXXXXXX", asym, " ", gCallableInfoGetNArgs(minfo)
if run == 1:
#if not (asym != "errorQuark" and asym != "getPlugin" and asym != "quark"): continue
if fixedProcNames.contains(sym): continue
if not (asym.startsWith("get") or asym.startsWith("set")) or asym == "getPlugin" or asym.len < 4: continue
if asym.startsWith("get") and gTypeInfoGetTag(ret2) == GITypeTag.VOID: continue
if asym.startsWith("set"):
if gCallableInfoGetNArgs(minfo) > 2:
continue
if gCallableInfoIsMethod(minfo) and gCallableInfoGetNArgs(minfo) > 1:
continue
if asym.startsWith("get"):
asym = asym[3 .. ^1]
asym[0] = asym[0].toLowerAscii
if asym.startsWith("set"):
#if plist.contains(" = true"):
#echo "ZZZZZZ ", plist, " ", arglist
plist = plist.replace(": bool = true", ": bool")
asym = asym[3 .. ^1]
asym[0] = asym[0].toLowerAscii
asym = '`' & asym & '=' & '`'
if keywords.split.contains(asym) or nims.split.contains(asym): continue
if needProxyProc(mInfo) or isString(ret2) or replist.len > 0 or ct2nt.contains(genRec(ret2)): # new in 0.4.11: return bool/int instead of gboolenan/int32#################################
var isGObject = false
let tag = gTypeInfoGetTag(ret2)
if tag == GITypeTag.INTERFACE:
let iface = gTypeInfoGetInterface(ret2)
if gBaseInfoGetType(iface) == GIInfoType.Object and gBaseInfoGetName(iface) != "ParamSpec":
isGObject = true
(plist, arglist, replist) = genP(mInfo, true, info)
if asym[^2] == '=':
plist = plist.replace(": bool = true", ": bool")
if (gFunctionInfoGetFlags(mInfo).int and GIFunctionInfoFlags.IS_CONSTRUCTOR.int) != 0:
if info != nil:
asym = asym.replace("new", "new" & manglename(gBaseInfoGetName(info)))
if fixedProcNames.contains(sym):
asym = fixedProcNames[sym]
for i in 0 .. 1:
#if i > 0 and isGObject:
# echo "XYZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA ", asym
var hhh = "\nproc " & asym & EM & plist
if i > 0:
let semi = if hhh.contains("()"): "" else: "; "
let p = hhh.find("): ")
hhh.setLen(p + 1)
hhh = hhh.replace("new", "init")
hhh = hhh.replace("*(", "*[T](result: var T" & semi)
methodBuffer.writeLine(hhh & " =")
if true:#needProxyProc(mInfo):
for j in 0.cint ..< gCallableInfoGetNArgs(minfo):
let arg = gCallableInfoGetArg(minfo, j)
let t = gArgInfoGetType(arg)
if gArgInfoGetDirection(arg) == GIDirection.OUT:# and not callerAlloc.contains(genRec(t, true, true)): #and not gArgInfoIsCallerAllocates(arg)
assert(false)
let h2 = mangleName(gBaseInfoGetName(arg))
methodBuffer.writeLine(" if " & h2 & ".isNil: " & h2 & " = new type(" & h2 & ")")
if gCallableInfoCanThrowGerror(minfo):
methodBuffer.writeLine(" var gerror: ptr Error00")
if i == 0: arglist.insert(", addr gerror", arglist.high)
if i > 0:
methodBuffer.writeLine(" assert(result is $1)" % [manglename(gBaseInfoGetName(info))])
assert(replist.len == 0)
for k, v in replist:
let kk = if k[0] == '`': k[1 .. ^2] else: k
methodBuffer.writeLine(" var $1_00 = $2($3)" % [kk, v, k])
#[
if isGObject:
methodBuffer.writeLine(" new(result, finalizeGObject)")
else:
methodBuffer.writeLine(" new(result)")
methodBuffer.writeLine(" result.impl = " & sym & arglist)
for k, v in replist:
let kk = if k[0] == '`': k[1 .. ^2] else: k
methodBuffer.writeLine(" $1 = $2($3_00)" % [k, ct3nt(v), kk])
if isGObject:
methodBuffer.writeLine(" GC_ref(result)")
methodBuffer.writeLine(" discard g_object_ref_sink(result.impl)")
methodBuffer.writeLine(" g_object_add_toggle_ref(result.impl, toggleNotify, addr(result[]))")
methodBuffer.writeLine(" g_object_unref(result.impl)")
methodBuffer.writeLine(" assert(g_object_get_qdata(result.impl, Quark) == nil)")
methodBuffer.writeLine(" g_object_set_qdata(result.impl, Quark, addr(result[]))")
]#
if isGObject:
assert (gCallableInfoGetCallerOwns(minfo) in {GITransfer.NOTHING, GITransfer.EVERYTHING}) # both occur, we dont care
# CAUTION: some procs are advertised as constructor but do not construct new objects,
# they just return existing ones as gdk_cursor_new_from_name()
methodBuffer.writeLine(" let gobj = " & sym & arglist)
methodBuffer.writeLine(" if g_object_get_qdata(gobj, Quark) != nil:")
let h = gBaseInfoGetContainer(minfo)
var rt: string
if gBaseInfoGetType(h) == GIInfoType.OBJECT:
rt = mangleType(mangleName(gBaseInfoGetName(h)))
else:
rt = genRec(ret2, true)
#methodBuffer.writeLine(" result = cast[$1](g_object_get_qdata(gobj, Quark))" % [rt])
methodBuffer.writeLine(" result = cast[type(result)](g_object_get_qdata(gobj, Quark))" % [rt])
methodBuffer.writeLine(" assert(result.impl == gobj)")
methodBuffer.writeLine(" else:") # I guess this will never get called...
if sym == "g_object_ref" or sym == "g_object_ref_sink":
methodBuffer.writeLine(" assert(false)")
else:
methodBuffer.writeLine(" new(result, finalizeGObject)")
methodBuffer.writeLine(" result.impl = gobj")
methodBuffer.writeLine(" GC_ref(result)")
methodBuffer.writeLine(" discard g_object_ref_sink(result.impl)")
methodBuffer.writeLine(" g_object_add_toggle_ref(result.impl, toggleNotify, addr(result[]))")
methodBuffer.writeLine(" g_object_unref(result.impl)")
methodBuffer.writeLine(" assert(g_object_get_qdata(result.impl, Quark) == nil)")
methodBuffer.writeLine(" g_object_set_qdata(result.impl, Quark, addr(result[]))")
elif gCallableInfoGetCallerOwns(minfo) == GITransfer.CONTAINER:
assert false
elif gCallableInfoGetCallerOwns(minfo) == GITransfer.EVERYTHING:
if sym == "g_closure_new_simple":
let nMethods = gStructInfoGetNMethods(info)
for j in 0.cint ..< nMethods:
echo "yes there is unref method! ", $gBaseInfoGetName(gStructInfoGetMethod(info, j))
#assert(gStructInfoFindMethod(info, "unref") != nil) # TODO GI bug?
assert info != nil
var freeMe: GIFunctionInfo
if gBaseInfoGetType(info) == GIInfoType.UNION:
freeMe = gUnionInfoFindMethod(info, "free")
if freeMe.isNil:
freeMe = gUnionInfoFindMethod(info, "unref")
else:
assert gBaseInfoGetType(info) == GIInfoType.STRUCT
freeMe = gStructInfoFindMethod(info, "free")
if freeMe.isNil:
freeMe = gStructInfoFindMethod(info, "unref")
var freeMeName: string
if freeMe == nil:
echo "Caution: No free/unref found for ", ' ', " (", sym, ')' # Mostly missing cairo functions...
else:
freeMeName = $gBaseInfoGetName(freeMe)
if sym == "g_closure_new_simple" or sym == "g_closure_new_object": freeMeName = "unref" # TODO GI bug?
assert(gCallableInfoGetCallerOwns(minfo) in {GITransfer.EVERYTHING, GITransfer.NOTHING})
if freeMeName == "":
methodBuffer.writeLine(" new(result)")
else:
methodBuffer.writeLine(" new(result, $1)" % freeMeName)
methodBuffer.writeLine(" result.impl = " & sym & arglist)
else:
assert gCallableInfoGetCallerOwns(minfo) == GITransfer.NOTHING
methodBuffer.writeLine(" new(result)")
methodBuffer.writeLine(" result.impl = " & sym & arglist)
#else:
# assert false
for k, v in replist:
let kk = if k[0] == '`': k[1 .. ^2] else: k
methodBuffer.writeLine(" $1 = $2($3_00)" % [k, ct3nt(v), kk])
elif isProxyCandidate(ret2):
assert (gCallableInfoGetCallerOwns(minfo) in {GITransfer.NOTHING, GITransfer.EVERYTHING}) # both occur
#if gCallableInfoGetCallerOwns(minfo) == GITransfer.EVERYTHING: echo "OOO1"
#if gCallableInfoGetCallerOwns(minfo) == GITransfer.CONTAINER: echo "OOO2"
#if gCallableInfoGetCallerOwns(minfo) == GITransfer.NOTHING: echo "OOO3"
if info != nil:
asym = asym.replace("new", "new" & manglename(gBaseInfoGetName(info)))
if fixedProcNames.contains(sym):
asym = fixedProcNames[sym]
methodBuffer.writeLine("\nproc " & asym & EM & plist & " =")
if gCallableInfoCanThrowGerror(minfo):
methodBuffer.writeLine(" var gerror: ptr Error00")
arglist.insert(", addr gerror", arglist.high)
for k, v in replist:
let kk = if k[0] == '`': k[1 .. ^2] else: k
methodBuffer.writeLine(" var $1_00 = $2($3)" % [kk, v, k])
if isGObject:
assert (gCallableInfoGetCallerOwns(minfo) in {GITransfer.NOTHING, GITransfer.EVERYTHING}) # both occur
#if gCallableInfoGetCallerOwns(minfo) == GITransfer.EVERYTHING: echo "OOO1"
#if gCallableInfoGetCallerOwns(minfo) == GITransfer.CONTAINER: echo "OOO2"
#if gCallableInfoGetCallerOwns(minfo) == GITransfer.NOTHING: echo "OOO3"
methodBuffer.writeLine(" let gobj = " & sym & arglist)
methodBuffer.writeLine(" if g_object_get_qdata(gobj, Quark) != nil:")
methodBuffer.writeLine(" result = cast[$1](g_object_get_qdata(gobj, Quark))" % [genRec(ret2, true)])
methodBuffer.writeLine(" assert(result.impl == gobj)")
methodBuffer.writeLine(" else:") # I guess this will never get called...
if sym == "g_object_ref" or sym == "g_object_ref_sink":
methodBuffer.writeLine(" assert(false)")
else:
methodBuffer.writeLine(" new(result, finalizeGObject)")
methodBuffer.writeLine(" result.impl = gobj")
methodBuffer.writeLine(" GC_ref(result)")
methodBuffer.writeLine(" discard g_object_ref_sink(result.impl)")
methodBuffer.writeLine(" g_object_add_toggle_ref(result.impl, toggleNotify, addr(result[]))")
methodBuffer.writeLine(" g_object_unref(result.impl)")
methodBuffer.writeLine(" assert(g_object_get_qdata(result.impl, Quark) == nil)")
methodBuffer.writeLine(" g_object_set_qdata(result.impl, Quark, addr(result[]))")
elif gCallableInfoGetCallerOwns(minfo) == GITransfer.EVERYTHING:
let tag = gTypeInfoGetTag(ret2)
assert tag == GITypeTag.INTERFACE
var iface = gTypeInfoGetInterface(ret2)
if gBaseInfoGetType(iface) == GIInfoType.INTERFACE:
iface = gInterfaceInfoGetIfaceStruct(iface)
methodBuffer.writeLine(" new(result, gobject.genericGObjectUnref)")
methodBuffer.writeLine(" result.impl = " & sym & arglist)
else:
let nMethods = gStructInfoGetNMethods(iface)
var freeMeName: string
for j in 0.cint ..< nMethods:
let h = $gBaseInfoGetName(gStructInfoGetMethod(iface, j))
if h.endsWith("free"):
freeMeName = "free"
break
elif h.endsWith("unref"):
freeMeName = "unref"
break
if freeMeName == "":
# assert false # TODO we have to fix this case manually
echo "Caution: No free/unref found for ", ' ', gBaseInfoGetName(iface), " (", sym, ')'
methodBuffer.writeLine(" new(result)")
else:
methodBuffer.writeLine(" new(result, $1)" % freeMeName)
methodBuffer.writeLine(" result.impl = " & sym & arglist)
else:
assert gCallableInfoGetCallerOwns(minfo) == GITransfer.NOTHING
methodBuffer.writeLine(" new(result)")
methodBuffer.writeLine(" result.impl = " & sym & arglist)
for k, v in replist:
let kk = if k[0] == '`': k[1 .. ^2] else: k
methodBuffer.writeLine(" $1 = $2($3_00)" % [k, ct3nt(v), kk])
else:
#assert gCallableInfoGetCallerOwns(minfo) == GITransfer.NOTHING
if asym == "newFromStreamAsync" and sym.contains("gdk_pixbuf_animation_new"):
asym = "newAnimationFromStreamAsync"
methodBuffer.writeLine("\nproc " & asym & EM & plist & " =")
var freeMeName: string
for j in 0.cint ..< gCallableInfoGetNArgs(minfo):
freeMeName = ""
let arg = gCallableInfoGetArg(minfo, j)
let t = gArgInfoGetType(arg)
if gArgInfoGetDirection(arg) == GIDirection.OUT and isProxyCandidate(t) and not callerAlloc.contains(genRec(t, true, true)) and not gArgInfoIsCallerAllocates(arg):
#let h1 = genRec(arg)
let tag = gTypeInfoGetTag(t)
assert(tag == GITypeTag.INTERFACE)
assert gArgInfoGetOwnershipTransfer(arg) != GITransfer.CONTAINER
if gArgInfoGetOwnershipTransfer(arg) == GITransfer.EVERYTHING:
#if tag == GITypeTag.INTERFACE:
# let iface = gTypeInfoGetInterface(t)
# if gBaseInfoGetType(iface) notin {GIInfoType.STRUCT, GIInfoType.OBJECT}:#, GIInfoType.UNION, GIInfoType.OBJECT}:
# echo "OOPS", gBaseInfoGetName(iface), sym
let iface = gTypeInfoGetInterface(t)
if gBaseInfoGetType(iface) == GIInfoType.OBJECT:
freeMeName = "finalizeGObject" # TODO: investigate, we may need the full toggleRef stuff!
else:
let info = iface
var freeMe: GIFunctionInfo
if gBaseInfoGetType(info) == GIInfoType.UNION:
freeMe = gUnionInfoFindMethod(info, "free")
if freeMe.isNil:
freeMe = gUnionInfoFindMethod(info, "unref")
else:
assert gBaseInfoGetType(info) == GIInfoType.STRUCT
freeMe = gStructInfoFindMethod(info, "free")
if freeMe.isNil:
freeMe = gStructInfoFindMethod(info, "unref")
if freeMe == nil:
echo "Caution: No free/unref found for ", ' ', " (", sym, ')' # Mostly missing cairo functions...
else:
freeMeName = $gBaseInfoGetName(freeMe)
let h2 = mangleName(gBaseInfoGetName(arg))
if freeMeName == "":
methodBuffer.writeLine(" new(" & h2 & ")")
else:
methodBuffer.writeLine(" new(" & h2 & ", " & freeMeName & ")")
if gCallableInfoCanThrowGerror(minfo):
methodBuffer.writeLine(" var gerror: ptr Error00")
arglist.insert(", addr gerror", arglist.high)
for k, v in replist:
let kk = if k[0] == '`': k[1 .. ^2] else: k
methodBuffer.writeLine(" var $1_00 = $2($3)" % [kk, v, k])
if isString(ret2):
methodBuffer.write(" let resul0 = ")
methodBuffer.writeLine(sym & arglist)
methodBuffer.writeLine(" result = $resul0")
assert(gCallableInfoGetCallerOwns(minfo) in {GITransfer.EVERYTHING, GITransfer.NOTHING})
if gCallableInfoGetCallerOwns(minfo) == GITransfer.EVERYTHING:
methodBuffer.writeLine(" cogfree(resul0)")
elif (replist.len > 0 or gCallableInfoCanThrowGerror(minfo)) and genRec(ret2) != "void":
methodBuffer.write(" result = ")
if ct2nt.contains(genRec(ret2)):
methodBuffer.writeLine(ct3nt(genRec(ret2)) & '(' & sym & arglist & ')')
else:
methodBuffer.writeLine(sym & arglist)
elif ct2nt.contains(genRec(ret2)):
methodBuffer.writeLine(" " & ct3nt(genRec(ret2)) & '(' & sym & arglist & ')')
else:
methodBuffer.writeLine(" " & sym & arglist)
for k, v in replist:
let kk = if k[0] == '`': k[1 .. ^2] else: k
methodBuffer.writeLine(" $1 = $2($3_00)" % [k, ct3nt(v), kk])
if gCallableInfoCanThrowGerror(minfo):
methodBuffer.writeLine(" if gerror != nil:")
methodBuffer.writeLine(" let msg = $gerror.message")
methodBuffer.writeLine(" g_error_free(gerror)")
methodBuffer.writeLine(" raise newException(GException, msg)")
else:
if fixedProcNames.contains(sym):
asym = fixedProcNames[sym]
(plist, arglist, replist) = genP(mInfo, genProxy, info)
if asym != "errorQuark" and asym != "getPlugin" and asym != "quark":
methodBuffer.write("\nproc " & asym & EM & plist)
methodBuffer.writeLine(" {.\n importc: \"", sym, "\", ", libprag, ".}")
if sym == "gtk_window_set_default_size":
methodBuffer.writeLine("\nproc `defaultSize=`*(self: Window; dim: tuple[width: int; height: int]) =")
methodBuffer.writeLine(" gtk_window_set_default_size(cast[ptr Window00](self.impl), int32(dim[0]), int32(dim[1]))")
if sym == "g_object_unref":
methodBuffer.writeLine("\nproc genericGObjectUnref*[T](self: T) =")
methodBuffer.writeLine(" g_object_unref(cast[ptr Object00](self.impl))")
except UndefEx:
#######echo "delay ", sym#, delayedMethods.len
processedFunctions.excl(sym)
delayedMethods.add((info, minfo))
methodBuffer.cut(p)
proc writeUnion(info: GIUnionInfo) =
if not suppressType:
output.writeLine("type")
#output.writeLine(" ", mangleName(gBaseInfoGetName(info)) & "00" & EM, " = object {.union.}")
output.writeLine(" ", mangleName(gBaseInfoGetName(info)) & "00" & EM, " {.union.} = object")
let n = info.gUnionInfoGetNFields()
for j in 0.cint ..< n:
let field = info.gUnionInfoGetField(j)
let name = manglename(gBaseInfoGetName(field)) & EM
let t = gFieldInfoGetType(field)
output.writeLine(" ", name, ": ", genRec(t))
output.writeLine(" ", mangleName(gBaseInfoGetName(info)) & EM & " = ref object")
output.writeLine(" impl*: ptr " & mangleName(gBaseInfoGetName(info)) & "00")
if mangleName(gBaseInfoGetName(info)) == "Event" and moduleNamespace == "gdk":
output.writeLine("type")
output.writeLine(" SomeEvent* = Event | EventAny | EventKey | EventButton | EventTouch | EventScroll | EventMotion | EventExpose | EventVisibility |")
output.writeLine(" EventCrossing | EventFocus | EventConfigure | EventProperty | EventSelection | EventDND | EventProximity | EventWindowState | EventSetting |")
output.writeLine(" EventOwnerChange | EventGrabBroken | EventTouchpadSwipe | EventTouchpadPinch | EventPadButton | EventPadAxis | EventPadGroupMode")
let nMethods = gUnionInfoGetNMethods(info)
var mseq = newSeq[GIFunctionInfo]()
var freePos = -1
for j in 0.cint ..< nMethods:
mseq.add(gUnionInfoGetMethod(info, j))
if freePos < 0 and gBaseInfoGetName(gUnionInfoGetMethod(info, j)) == "free":
freePos = j
if freePos < 0 and gBaseInfoGetName(gUnionInfoGetMethod(info, j)) == "unref":
freePos = j
if freePos > 0: swap(mseq[0], mseq[freePos])
for mInfo in mseq:
writeMethod(info, minfo)
proc writeStruct(info: GIStructInfo) =
if not suppressType:
output.writeLine("type")
if callerAlloc.contains(($gBaseInfoGetNamespace(info)).toLowerAscii & '.' & mangleName(gBaseInfoGetName(info))):
output.writeLine(" ", mangleName(gBaseInfoGetName(info)) & EM & " {.pure, byRef.} = object")
else:
output.writeLine(" ", mangleName(gBaseInfoGetName(info)) & "00" & EM & " {.pure.} = object")
let n = info.gStructInfoGetNFields()
for j in 0.cint ..< n:
let field = info.gStructInfoGetField(j)
let name = manglename(gBaseInfoGetName(field)) & EM
let t = gFieldInfoGetType(field)
output.writeLine(" ", name, ": ", genRec(t))
# let tag = gTypeInfoGetTag(t) # XXX: gFieldInfoGetSize() is always zero!
#if typeTagIsBasic(tag):
# echo "XXXXXXXXXXXXX", gFieldInfoGetOffset(field)
# echo "XXXXXXXXXXXXX", gFieldInfoGetSize(field)
#if mangleName(gBaseInfoGetName(info)) != "TextIter":
if not callerAlloc.contains(($gBaseInfoGetNamespace(info)).toLowerAscii & '.' & mangleName(gBaseInfoGetName(info))):
output.writeLine(" ", mangleName(gBaseInfoGetName(info)) & EM & " = ref object")
output.writeLine(" impl*: ptr " & mangleName(gBaseInfoGetName(info)) & "00")
let nMethods = gStructInfoGetNMethods(info)
var mseq = newSeq[GIFunctionInfo]()
var freePos = -1
for j in 0.cint ..< nMethods:
mseq.add(gStructInfoGetMethod(info, j))
if freePos < 0 and gBaseInfoGetName(gStructInfoGetMethod(info, j)) == "free":
freePos = j
if freePos < 0 and gBaseInfoGetName(gStructInfoGetMethod(info, j)) == "unref":
freePos = j
if freePos > 0: swap(mseq[0], mseq[freePos])
for mInfo in mseq:
writeMethod(info, minfo)
proc writeInterface(info: GIInterfaceInfo) =
if not suppressType:
output.writeLine("type")
# we made interfaces a gobject now...
output.writeLine(" ", mangleName(gBaseInfoGetName(info)) & "00" & EM & " = object of gobject.Object00")
output.writeLine(" ", mangleName(gBaseInfoGetName(info)) & EM & " = ref object of gobject.Object")
#output.writeLine(" ", mangleName(gBaseInfoGetName(info)) & "00" & EM & " {.pure.} = object")
#output.writeLine(" ", mangleName(gBaseInfoGetName(info)) & EM & " = ref object")
#output.writeLine(" impl*: ptr " & mangleName(gBaseInfoGetName(info)) & "00")
################################
let numsig = info.gInterfaceInfoGetNSignals
if numsig > 0: signalbuffer.writeLine("")
for j in 0.cint ..< numsig:
let signalInfo = gInterfaceInfoGetSignal(info, j)
#let c = gSignalInfoGetClassClosure(signalInfo)
#if not c.isNil: echo "maybe we should process class closures!"
#if gBaseInfoGetName(signalInfo) == "notify":
# continue # XXX fix later
var h = genP(signalInfo, false)[0][1..^1]
let zzzu = gCallableInfoGetReturnType(signalinfo)
if gCallableInfoGetNArgs(signalInfo) > 0 or gTypeInfoGetTag(zzzu) != GITypeTag.VOID:
var memo = ""
memo.add(gCallableInfoGetNArgs(signalInfo))
memo.add(RecSep)
var plist, arglist: string
var replist: TableRef[string, string]
(plist, arglist, replist) = genP(signalInfo, true, info)
memo.add(plist)
memo.add(RecSep)
(plist, arglist, replist) = genP(signalInfo, false, info)
memo.add(plist)
memo = memo.replace("\n ", "")
memo = memo.replace("\"", "\\\"")
supmod.writeLine(" \"" & ($gBaseInfoGetName(signalInfo)).replace("-", "_") & RecSep & $gBaseInfoGetName(info) & RecSep & memo & "\",")
if gCallableInfoGetNArgs(signalInfo) > 0:
var plist, arglist: string
var replist: TableRef[string, string]
(plist, arglist, replist) = genP(signalInfo, false, nil)
#######echo plist
#######echo arglist
#[
if replist.len > 0:
for k, v in replist:
stdout.write(k & "--" & v & " ")
stdout.writeLine("")
]#
#######echo "PPP ", gBaseInfoGetName(signalInfo), gCallableInfoGetNArgs(signalInfo)
h = h.replace(")", "; xdata: pointer)")
else:
h = h.replace(")", "xdata: pointer)")
var xxx = mangleName(gBaseInfoGetName(info))
let yyy = xxx
if interfaceProvider.contains(xxx):
let provider = interfaceProvider[xxx]
for i in provider: discard mangleType(i)
xxx = xxx & " | " & provider.join(" | ")
signalbuffer.write("proc " & mangleName("sc_" & $gBaseInfoGetName(signalInfo)) & EM & "(self: " & xxx & "; ")
if gCallableInfoGetNArgs(signalInfo) > 0 or gTypeInfoGetTag(zzzu) != GITypeTag.VOID:
signalbuffer.writeLine(" p: proc (self: ptr " & yyy & "00; " & h & " {.cdecl.}, xdata: pointer = nil): culong =")
else:
signalbuffer.writeLine(" p: proc (self: ptr gobject.Object00; " & h & " {.cdecl.}, xdata: pointer = nil): culong =")
signalbuffer.write(" g_signal_connect_data(self.impl, \"")
signalbuffer.write($gBaseInfoGetName(signalInfo))
signalbuffer.writeLine("\", cast[GCallback](p), xdata, nil, cast[ConnectFlags](0))")
let nMethods = gInterfaceInfoGetNMethods(info)
for j in 0.cint ..< nMethods:
let mInfo = gInterfaceInfoGetMethod(info, j)
writeMethod(info, minfo)
# write a few of the strange enum sets
proc writeModifierType(info: GIEnumInfo) =
let we = gBaseInfoGetName(info)
type T = tuple[v: int64; n: string]
var s = newSeq[T]()
var alias = newSeq[string]()
var flags = true#($gBaseInfoGetName(info)).endsWith("Flags")
output.writeLine("type")
let n = info.gEnumInfoGetNValues()
for j in 0.cint ..< n:
let value = info.gEnumInfoGetValue(j)
var name = mangleName(gBaseInfoGetName(value))
name.removeSuffix("Mask")
#if name.startsWith("modifierReserved_"): name = name[17 .. ^1]
let v = gValueInfoGetValue(value)
if bitops.popCount(v) == 1:
s.add((v, name))
s.sort do (x, y: T) -> int:
result = cmp(x.v, y.v)
if result == 0:
result = cmp(x.n, y.n)
for j in 0 .. s.high:
if s[j].v < 0: flags = false
if j == 0 and s[j].v == 0: continue
if bitops.popCount(s[j].v) != 1: flags = false
if s.len <= 1: flags = false
var tname = mangleName(gBaseInfoGetName(info))
if flags: tname.removeSuffix("Mask")
if flags: tname.removeSuffix("Type")
if flags: tname.removeSuffix("Flags")
if flags: tname.removeSuffix("Options")
if flags:
output.writeLine(" ", tname & "Flag" & EM, " {.size: sizeof(cint), pure.} = enum")
if s[0].v != 0 and s[0].v != 1: # flags may start with none = 0 or with flag1 = 1
output.writeLine(" ignoreThisDummyValue = 0") # Nim needs start with 0 for these low level sets
else:
output.writeLine(" ", tname & EM, " {.size: sizeof(cint), pure.} = enum")
var k: T
for j in 0 .. s.high:
let i = s[j]
var val = i.v
if flags and j == 0 and val == 0: continue
if j > 0 and i.v == k.v:
if i.n != k.n:
alias.add(" " & tname & i.n.capitalizeAscii & EM & " = " & tname & '.' & k.n)
continue
if flags:
val = countTrailingZeroBits(val)
output.writeLine(" ", i.n, " = ", val)
k = i
if alias.len > 0:
output.writeLine("\nconst")
for i in alias:
output.writeLine(i)
if flags:
if we == "ModifierType":
output.writeLine("\n ", tname & "Type" & EM, " {.size: sizeof(cint).} = set[$1Flag]" % [tname])
elif we == "EventMask":
output.writeLine("\n ", tname & "Mask" & EM, " {.size: sizeof(cint).} = set[$1Flag]" % [tname])
elif we == "AccelFlags":
output.writeLine("\n ", tname & "Flags" & EM, " {.size: sizeof(cint).} = set[$1Flag]" % [tname])
elif we == "AttachOptions":
output.writeLine("\n ", tname & "Options" & EM, " {.size: sizeof(cint).} = set[$1Flag]" % [tname])
if we == "ModifierType":
output.writeLine("\nconst ModifierMask* = {ModifierFlag.shift .. ModifierFlag.button5, ModifierFlag.super .. ModifierFlag.meta, ModifierFlag.release}")
elif we == "EventMask":
output.writeLine("\nconst AllEventsMask* = {EventFlag.exposure .. EventFlag.smoothScroll}")
#elif we == "AccelFlags":
# output.writeLine("\nconst AccelFlagsMask* = AccelFlags(7)")
let nMethods = gEnumInfoGetNMethods(info)
for j in 0.cint ..< nMethods:
let mInfo = gEnumInfoGetMethod(info, j)
writeMethod(info, minfo)
proc writeEnum(info: GIEnumInfo) =
if mangleName(gBaseInfoGetName(info)) in ["ModifierType", "EventMask", "AccelFlags", "AttachOptions"]:
writeModifierType(info)
return
type T = tuple[v: int64; n: string]
var s = newSeq[T]()
var alias = newSeq[string]()
var flags = ($gBaseInfoGetName(info)).endsWith("Flags")
output.writeLine("type")
let n = info.gEnumInfoGetNValues()
for j in 0.cint ..< n:
let value = info.gEnumInfoGetValue(j)
let name = mangleName(gBaseInfoGetName(value))
let v = gValueInfoGetValue(value)
s.add((v, name))
s.sort do (x, y: T) -> int:
result = cmp(x.v, y.v)
if result == 0:
result = cmp(x.n, y.n)
for j in 0 .. s.high:
if s[j].v < 0: flags = false
if j == 0 and s[j].v == 0: continue
if bitops.popCount(s[j].v) != 1: flags = false
if s.len <= 1: flags = false
var tname = mangleName(gBaseInfoGetName(info))
if flags: tname = tname[0 .. ^6]
if flags:
output.writeLine(" ", tname & "Flag" & EM, " {.size: sizeof(cint), pure.} = enum")
# if s[0].v != 1 and s[1].v != 1: # wrong for 0, 2, ...
if s[0].v != 0 and s[0].v != 1: # flags may start with none = 0 or with flag1 = 1
output.writeLine(" ignoreThisDummyValue = 0") # Nim needs start with 0 for these low level sets
else:
output.writeLine(" ", tname & EM, " {.size: sizeof(cint), pure.} = enum")
var k: T
for j in 0 .. s.high:
let i = s[j]
var val = i.v
if flags and j == 0 and val == 0: continue
if j > 0 and i.v == k.v:
if i.n != k.n:
alias.add(" " & tname & i.n.capitalizeAscii & EM & " = " & tname & '.' & k.n)
continue
if flags:
val = countTrailingZeroBits(val) # firstSetBit(val)
output.writeLine(" ", i.n, " = ", val)
k = i
if alias.len > 0:
output.writeLine("\nconst")
for i in alias:
output.writeLine(i)
if flags:
output.writeLine("\n ", tname & "Flags" & EM, " {.size: sizeof(cint).} = set[$1Flag]" % [tname])
let nMethods = gEnumInfoGetNMethods(info)
for j in 0.cint ..< nMethods:
let mInfo = gEnumInfoGetMethod(info, j)
writeMethod(info, minfo)
proc writeObj(info: GIObjectInfo) =
assert(gBaseInfoGetType(info) == GIInfoType.OBJECT)
let ninterfaces = info.gObjectInfoGetNInterfaces
let class = gObjectInfoGetClassStruct(info)
let n = info.gObjectInfoGetNFields
let parent = gObjectInfoGetParent(info) # nil for Object of module gobject!
var pname: string
var oof: string
var ns: string
var cnt: int
if parent.isNil:
assert(gBaseInfoGetName(info) == "Object" or gBaseInfoGetName(info) == "ParamSpec")
oof = "{.inheritable, pure.} = object"
ns = ""
pname = ""
cnt = 0
else:
cnt = 1
oof = " = object of "
pName = manglename(gBaseInfoGetName(parent))
if ct.hasKey(pname):
cnt = ct[pname]
ns = ($gBaseInfoGetNamespace(parent)).toLowerAscii
if ns == moduleNamespace: ns = "" else: ns.add('.')
if ns == "gio." and gBaseInfoGetName(info) == "Application": # a few special cases for gtk.nim
cnt = 9
if ns == "gio." and gBaseInfoGetName(info) == "MountOperation":
cnt = 9
if ns == "gio." and gBaseInfoGetName(info) == "NumerableIcon":
cnt = 9
if moduleNamespace == "gtksource" and gBaseInfoGetName(info) == "Buffer":
cnt = 9
if moduleNamespace == "gtksource" and gBaseInfoGetName(info) == "Mark":
cnt = 9
if moduleNamespace == "gtksource" and gBaseInfoGetName(info) == "CompletionInfo":
cnt = 9
if moduleNamespace == "gtksource" and gBaseInfoGetName(info) == "View":
cnt = 9
if not suppressType:
output.writeLine("type")
if ns == "" and pname != "": # check forward exeption for parent name!
discard mangleType(pname)
if mangleName(gBaseInfoGetName(info)) == "Object" and moduleNamespace == "gobject":
discard
elif gBaseInfoGetName(info) == "ParamSpec":
output.writeLine(" ", mangleName(gBaseInfoGetName(info)) & EM & " = ref object of RootRef")
output.writeLine(" impl*: ptr ParamSpec00")
else:
output.writeLine(" ", mangleName(gBaseInfoGetName(info)) & EM & " = ref object of " & ns & pname)
if pname != "": pname.add("00")
output.writeLine(" ", mangleName(gBaseInfoGetName(info)) & "00" & EM, oof, ns & $pname)
if mangleName(gBaseInfoGetName(info)) != "InitiallyUnowned":
for j in 0.cint ..< n:
let field = info.gObjectInfoGetField(j)
var name = mangleName(gBaseInfoGetName(field))
if privStr.contains(name) and cnt > 0:
renumber(name, cnt)
else:
name.add(EM)
let t = gFieldInfoGetType(field)
let h = genRec(t)
if j == 0 and parent != nil:
continue
output.writeLine(" ", name, ": ", h)
if mangleName(gBaseInfoGetName(info)) == "Object" and moduleNamespace == "gobject":
output.writeLine("type")
output.writeLine(" GToggleNotify* = proc (data: pointer; obj: ptr Object00; isLastRef: gboolean) {.cdecl.}\n")
output.writeLine("proc g_object_add_toggle_ref*(obj: ptr Object00; notify: GToggleNotify; data: pointer) {.")
output.writeLine(" importc: \"g_object_add_toggle_ref\", libprag.}")
output.writeLine("proc g_object_remove_toggle_ref*(obj: ptr Object00; notify: GToggleNotify; data: pointer) {.")
output.writeLine(" importc: \"g_object_remove_toggle_ref\", libprag.}")
output.writeLine("\nproc g_object_set_qdata*(self: ptr Object00; quark: uint32; p: pointer) {.")
output.writeLine(" importc: \"g_object_set_qdata\", libprag.}")
output.writeLine("proc toggleNotify*(data: pointer; obj: ptr Object00; isLastRef: gboolean) {.cdecl.} =")
output.writeLine(" if isLastRef.int == 0:")
output.writeLine(" GC_ref(cast[RootRef](data))")
###output.writeLine(" echo \"GC_ref(cast[RootRef](data)\"")
output.writeLine(" else:")
output.writeLine(" GC_unref(cast[RootRef](data))")
###output.writeLine(" echo \"GC_unref(cast[RootRef](data)\"")
###output.writeLine(" echo \"toggleNotify\"")
###output.writeLine(" echo obj.ref_count")
output.writeLine("\nproc finalizeGObject*[T](o: T) =")
###methodBuffer.writeLine(" echo(\"finalizeGObject\")")
output.writeLine(" g_object_remove_toggle_ref(o.impl, toggleNotify, addr(o[]))")
let numsig = info.gObjectInfoGetNSignals
if numsig > 0: signalbuffer.writeLine("")
for j in 0.cint ..< numsig:
let signalInfo = gObjectInfoGetSignal(info, j)
let c = gSignalInfoGetClassClosure(signalInfo)
if not c.isNil: echo "maybe we should process class closures!"
if gBaseInfoGetName(signalInfo) == "notify":
continue # XXX fix later
var h = genP(signalInfo, false)[0][1..^1]
let zzzu = gCallableInfoGetReturnType(signalinfo)
if gCallableInfoGetNArgs(signalInfo) > 0 or gTypeInfoGetTag(zzzu) != GITypeTag.VOID:
var memo = ""
memo.add(gCallableInfoGetNArgs(signalInfo))
memo.add(RecSep)
var plist, arglist: string
var replist: TableRef[string, string]
(plist, arglist, replist) = genP(signalInfo, true, info)
memo.add(plist)
memo.add(RecSep)
(plist, arglist, replist) = genP(signalInfo, false, info)
memo.add(plist)
memo = memo.replace("\n ", "")
memo = memo.replace("\"", "\\\"")
supmod.writeLine(" \"" & ($gBaseInfoGetName(signalInfo)).replace("-", "_") & RecSep & $gBaseInfoGetName(info) & RecSep & memo & "\",")
if gCallableInfoGetNArgs(signalInfo) > 0:
var plist, arglist: string
var replist: TableRef[string, string]
(plist, arglist, replist) = genP(signalInfo, false, nil)
#######echo plist
#######echo arglist
#[
if replist.len > 0:
for k, v in replist:
stdout.write(k & "--" & v & " ")
stdout.writeLine("")
]#
#######echo "PPP ", gBaseInfoGetName(signalInfo), gCallableInfoGetNArgs(signalInfo)
h = h.replace(")", "; xdata: pointer)")
else:
h = h.replace(")", "xdata: pointer)")
var xxx = mangleName(gBaseInfoGetName(info))
let yyy = xxx
if interfaceProvider.contains(xxx):
let provider = interfaceProvider[xxx]
for i in provider: discard mangleType(i)
xxx = xxx & " | " & provider.join(" | ")
signalbuffer.write("proc " & mangleName("sc_" & $gBaseInfoGetName(signalInfo)) & EM & "(self: " & xxx & "; ")
if gCallableInfoGetNArgs(signalInfo) > 0 or gTypeInfoGetTag(zzzu) != GITypeTag.VOID:
signalbuffer.writeLine(" p: proc (self: ptr " & yyy & "00; " & h & " {.cdecl.}, xdata: pointer = nil): culong =")
else:
signalbuffer.writeLine(" p: proc (self: ptr gobject.Object00; " & h & " {.cdecl.}, xdata: pointer = nil): culong =")
signalbuffer.write(" g_signal_connect_data(self.impl, \"")
signalbuffer.write($gBaseInfoGetName(signalInfo))
signalbuffer.writeLine("\", cast[GCallback](p), xdata, nil, cast[ConnectFlags](0))")
let nMethods = gObjectInfoGetNMethods(info)
for j in 0.cint ..< nMethods:
let mInfo = gObjectInfoGetMethod(info, j)
writeMethod(info, minfo)
if class != nil and not allSyms.contains(mangleName(gBaseInfoGetName(class))):
classList.add(class)
ct.inc($gBaseInfoGetName(info), cnt + 1)
if gBaseInfoGetName(info) == "Object" and moduleNamespace == "gobject":
output.writeLine("type\n Object* = ref object of RootRef")
output.writeLine(" impl*: ptr Object00")
proc extractFromUnion(tag: GITypeTag; arg: GIArgumentObj): string =
result =
case tag:
#of GITypeTag.VOID: $arg.
of GITypeTag.BOOLEAN: $arg.vBoolean
of GITypeTag.INT8: $arg.vInt8 & "'i8"
of GITypeTag.UINT8: $arg.vUint8 & "'u8"
of GITypeTag.INT16: $arg.vInt16 & "'i16"
of GITypeTag.UINT16: $arg.vUint16 & "'u16"
of GITypeTag.INT32: $arg.vInt32 & "'i32"
of GITypeTag.UINT32: $arg.vUint32 & "'u32"
of GITypeTag.INT64: $arg.vInt64 & "'i64"
of GITypeTag.UINT64: $arg.vUint64 & "'u64"
of GITypeTag.FLOAT: $arg.vFloat & "'f32"
of GITypeTag.DOUBLE: $arg.vDouble & "'f64"
#of GITypeTag.GTYPE: $arg.
of GITypeTag.UTF8: '"' & $arg.vstring & '"'
#of GITypeTag.FILENAME: $arg.
#of GITypeTag.ARRAY: $arg.
#of GITypeTag.INTERFACE: $arg.
#of GITypeTag.GLIST: $arg.
#of GITypeTag.GSLIST: $arg.
#of GITypeTag.GHASH: $arg.
#of GITypeTag.ERROR: $arg.
#of GITypeTag.UNICHAR: $arg.
else: "XXX"
proc writeConst(info: GIConstantInfo) =
var tg = ""
var arg: GIArgumentObj
let t = gConstantInfoGetType(info)
let tag = gTypeInfoGetTag(t)
let s = gConstantInfoGetValue(info, addr(arg)) # TODO: we should check the size s!
var str = extractFromUnion(tag, arg)
if str == """"\"""": str = """"\\""""
var h = $gBaseInfoGetName(info)
if h.replace("_", "").toLowerAscii == "keych":
h.add(str[^5])
if gdkKeys.contains(h.toLowerAscii):
var s = gdkKeys[h.toLowerAscii]
if s.len > 1:
if s.len == 2:
if h == s[0]:
tg = "U"
elif h == s[1]:
discard
else:
assert(false)
elif s.len == 3: # eth and thorn
if h == s[0]:
tg = "X"
elif h == s[2]:
discard
elif h == s[1]:
tg = "U"
else:
assert(false)
output.writeLine("const ", tg, h & EM, " = ", str)
else:
output.writeLine("const ", mangleName(h) & EM, " = ", str)
proc processInfo(i: GIBaseInfo) =
if not isFunctionInfo(i):
output.write("\n")
if isCallableInfo(i):
if isFunctionInfo(i):
let s = $gFunctionInfoGetSymbol(i)
if s[^1] != '_' and not processedFunctions.contains(s) and not s.contains("__") and s != "g_type_add_interface_dynamic" and
s != "g_type_get_plugin" and s != "g_type_register_dynamic":
writeMethod(nil, i)
else:
assert(isCallbackInfo(i))
if not suppressType:
output.write("type\n")
output.writeLine(" ", mangleName(gBaseInfoGetName(i)) & "* = proc " & genP(i)[0] & " {.cdecl.}")
elif gBaseInfoGetType(i) == GIInfoType.OBJECT:
writeObj(i)
elif gBaseInfoGetType(i) == GIInfoType.UNION:
writeUnion(i)
elif gBaseInfoGetType(i) == GIInfoType.INTERFACE:
let h = gInterfaceInfoGetIfaceStruct(i)
if true:#h != nil: # Needed for FileChooser, AppChooser
writeInterface(i)
elif gBaseInfoGetType(i) == GIInfoType.STRUCT:
writeStruct(i)
elif isEnumInfo(i):
writeEnum(i)
elif gBaseInfoGetType(i) == GIInfoType.CONSTANT:
writeConst(i)
else: assert(false)
# Gtk objects builder may provide. Only for Gtk module, so Gtk prefix is assume.
# Other objects loke gtkSourceView are separated!
# This a guessed list, so it may be inaccurate.
const GtkBuilderObjects = """
AboutDialog
AccelLabel
ActionBar
ActionGroup
Alignment
AppChooserButton
AppChooserDialog
AppChooserWidget
Application
ApplicationWindow
Arrow
AspectFrame
Assistant
Box
Builder
Button
ButtonBox
Calendar
CellAreaBox
CellView
CheckButton
CheckMenuItem
ColorButton
ColorChooserDialog
ColorChooserWidget
ColorSelectionDialog
ComboBox
ComboBoxText
Dialog
DrawingArea
Entry
EntryCompletion
EventBox
Expander
FileChooserButton
FileChooserNative
FileChooserWidget
FileFilter
Fixed
FlowBox
FontButton
FontChooserDialog
FontChooserWidget
FontSelection
FontSelectionDialog
Frame
GLArea
Grid
HandleBox
HBox
HButtonBox
HeaderBar
HPaned
HScale
HScrollbar
HSeparator
IconView
ImageMenuItem
InfoBar
Invisible
Label
Layout
LevelBar
LinkButton
ListBox
ListBoxRow
ListStore
LockButton
Menu
MenuBar
MenuButton
MenuItem
MenuToolButton
ModelButton
Notebook
OffscreenWindow
Overlay
Paned
PlacesSidebar
Popover
PopoverMenu
ProgressBar
RadioButton
RadioMenuItem
RadioToolButton
RecentChooserMenu
RecentChooserWidget
RecentManager
Revealer
Scale
ScaleButton
Scrollbar
ScrolledWindow
SearchBar
SearchEntry
Separator
SeparatorMenuItem
SeparatorToolItem
ShortcutLabel
SizeGroup
SpinButton
Spinner
Stack
StackSidebar
StackSwitcher
Statusbar
Style
Switch
Table
TearoffMenuItem
TextView
ToggleButton
ToggleToolButton
Toolbar
ToolButton
ToolItem
ToolItemGroup
ToolPalette
TreeStore
TreeView
TreeViewColumn
VBox
VButtonBox
Viewport
VolumeButton
VPaned
VScrollbar
VSeparator
Window
"""
const GTK_SOURCE_EPI = """
proc getView(builder: Builder; name: string): View =
new result
let gt = g_type_from_name("GSource")
assert(gt != 0)
result.impl = gtk_builder_get_object(cast[ptr Builder00](builder.impl), name)
assert(toBool(g_type_check_instance_is_a(cast[ptr TypeInstance00](result.impl), gt)))
proc completionContextGetType*(): GType {.importc: "gtk_source_completion_context_get_type", libprag.}
proc completionProviderGetType*(): GType {.importc: "gtk_source_completion_provider_get_type", libprag.}
proc completionWordsGetType*(): GType {.importc: "gtk_source_completion_words_get_type", libprag.}
proc bufferGetType*(): GType {.importc: "gtk_source_buffer_get_type", libprag.}
proc completionGetType*(): GType {.importc: "gtk_source_completion_get_type", libprag.}
proc completionInfoGetType*(): GType {.importc: "gtk_source_completion_info_get_type", libprag.}
proc completionItemGetType*(): GType {.importc: "gtk_source_completion_item_get_type", libprag.}
proc completionProposalGetType*(): GType {.importc: "gtk_source_completion_proposal_get_type", libprag.}
proc encodingGetType*(): GType {.importc: "gtk_source_encoding_get_type", libprag.}
proc fileGetType*(): GType {.importc: "gtk_source_file_get_type", libprag.}
proc fileLoaderGetType*(): GType {.importc: "gtk_source_file_loader_get_type", libprag.}
proc fileSaverGetType*(): GType {.importc: "gtk_source_file_saver_get_type", libprag.}
proc gutterGetType*(): GType {.importc: "gtk_source_gutter_get_type", libprag.}
proc gutterRendererGetType*(): GType {.importc: "gtk_source_gutter_renderer_get_type", libprag.}
proc gutterRendererTextGetType*(): GType {.importc: "gtk_source_gutter_renderer_text_get_type", libprag.}
proc gutterRendererPixbufGetType*(): GType {.importc: "gtk_source_gutter_renderer_pixbuf_get_type", libprag.}
proc languageGetType*(): GType {.importc: "gtk_source_language_get_type", libprag.}
proc languageManagerGetType*(): GType {.importc: "gtk_source_language_manager_get_type", libprag.}
proc viewGetType*(): GType {.importc: "gtk_source_view_get_type", libprag.}
proc mapGetType*(): GType {.importc: "gtk_source_map_get_type", libprag.}
proc markGetType*(): GType {.importc: "gtk_source_mark_get_type", libprag.}
proc markAttributesGetType*(): GType {.importc: "gtk_source_mark_attributes_get_type", libprag.}
proc printCompositorGetType*(): GType {.importc: "gtk_source_print_compositor_get_type", libprag.}
proc regionGetType*(): GType {.importc: "gtk_source_region_get_type", libprag.}
proc searchContextGetType*(): GType {.importc: "gtk_source_search_context_get_type", libprag.}
proc searchSettingsGetType*(): GType {.importc: "gtk_source_search_settings_get_type", libprag.}
proc spaceDrawerGetType*(): GType {.importc: "gtk_source_space_drawer_get_type", libprag.}
proc styleGetType*(): GType {.importc: "gtk_source_style_get_type", libprag.}
proc styleSchemeGetType*(): GType {.importc: "gtk_source_style_scheme_get_type", libprag.}
proc styleSchemeChooserGetType*(): GType {.importc: "gtk_source_style_scheme_chooser_get_type", libprag.}
proc styleSchemeChooserButtonGetType*(): GType {.importc: "gtk_source_style_scheme_chooser_button_get_type", libprag.}
proc styleSchemeChooserWidgetGetType*(): GType {.importc: "gtk_source_style_scheme_chooser_widget_get_type", libprag.}
proc styleSchemeManagerGetType*(): GType {.importc: "gtk_source_style_scheme_manager_get_type", libprag.}
proc tagGetType*(): GType {.importc: "gtk_source_tag_get_type", libprag.}
proc undoManagerGetType*(): GType {.importc: "gtk_source_undo_manager_get_type", libprag.}
proc completionWordsProposalGetType*(): GType {.importc: "gtk_source_completion_words_proposal_get_type", libprag.}
proc completionWordsLibraryGetType*(): GType {.importc: "gtk_source_completion_words_library_get_type", libprag.}
proc completionWordsBufferGetType*(): GType {.importc: "gtk_source_completion_words_buffer_get_type", libprag.}
# register the GObject types so builder can use them, see
# https://mail.gnome.org/archives/gtk-list/2015-March/msg00016.html
discard viewGetType()
discard completionInfoGetType()
discard styleSchemeChooserButtonGetType()
"""
const GDK_EPI = """
proc gdk_window_invalidate_nilrect(self: ptr Window00; rect: ptr Rectangle; invalidateChildren: gboolean) {.
importc: "gdk_window_invalidate_rect", libprag.}
proc invalidateRect*(self: Window; rect: ptr Rectangle = nil; invalidateChildren: bool = false) =
gdk_window_invalidate_nilrect(cast[ptr Window00](self.impl), rect, gboolean(invalidateChildren))
proc fixednewCursorFromName*(display: Display; name: string): Cursor =
new(result, finalizeGObject)
result.impl = gdk_cursor_new_from_name(cast[ptr Display00](display.impl), cstring(name))
GC_ref(result)
discard g_object_ref_sink(result.impl)
g_object_add_toggle_ref(result.impl, toggleNotify, addr(result[]))
g_object_unref(result.impl)
#assert(g_object_get_qdata(result.impl, Quark) == nil)
g_object_set_qdata(result.impl, Quark, addr(result[]))
proc getAngle*(self: SomeEvent; event2: SomeEvent): cdouble =
if not toBool(gdk_events_get_angle(cast[ptr Event00](self.impl), cast[ptr Event00](event2.impl), result)):
raise newException(Defect, "Events do not support getAngle().")
proc getCenter*(self: SomeEvent; event2: SomeEvent): (cdouble, cdouble) =
if not toBool(gdk_events_get_center(cast[ptr Event00](self.impl), cast[ptr Event00](event2.impl), result[0], result[1])):
raise newException(Defect, "Events do not support getCenter().")
proc getDistance*(self: SomeEvent; event2: SomeEvent): cdouble =
if not toBool(gdk_events_get_distance(cast[ptr Event00](self.impl), cast[ptr Event00](event2.impl), result)):
raise newException(Defect, "Events do not support getDistance().")
proc getAxis*(self: SomeEvent; axisUse: AxisUse): cdouble =
if not toBool(gdk_event_get_axis(cast[ptr Event00](self.impl), axisUse, result)):
raise newException(Defect, "Event does not support getAxis().")
proc getButton*(self: SomeEvent): int =
var button: uint32
if not toBool(gdk_event_get_button(cast[ptr Event00](self.impl), button)):
raise newException(Defect, "Event don't has a button field.")
return int(button)
proc getClickCount*(self: SomeEvent): int =
var clickCount_00: uint32
if not toBool(gdk_event_get_click_count(cast[ptr Event00](self.impl), clickCount_00)):
raise newException(Defect, "Event does not support getClickCount().")
return int(clickCount_00)
proc getCoords*(self: SomeEvent): (cdouble, cdouble) =
if not toBool(gdk_event_get_coords(cast[ptr Event00](self.impl), result[0], result[1])):
raise newException(Defect, "This event don't has a coordinate field.")
proc getKeyval*(self: SomeEvent): int =
var keyval_00 = uint32
if not toBool(gdk_event_get_keyval(cast[ptr Event00](self.impl), keyval_00)):
raise newException(Defect, "This event don't has a keyval field.")
return int(keyval_00)
proc getRootCoords*(self: SomeEvent): (cdouble, cdouble) =
if not toBool(gdk_event_get_root_coords(cast[ptr Event00](self.impl), result[0], result[1])):
raise newException(Defect, "This event don't has a rootCoordinate field.")
proc getScrollDeltas*(self: SomeEvent): (cdouble, cdouble) =
if not toBool(gdk_event_get_scroll_deltas(cast[ptr Event00](self.impl), result[0], result[1])):
raise newException(Defect, "This event don't has a scrollDeltas field.")
proc getScrollDirection*(self: SomeEvent): ScrollDirection =
if not toBool(gdk_event_get_scroll_direction(cast[ptr Event00](self.impl), result)):
raise newException(Defect, "Event don't has a scrollDirection field.")
proc getState*(self: SomeEvent): ModifierType =
if not toBool(gdk_event_get_state(cast[ptr Event00](self.impl), result)):
raise newException(Defect, "Event don't has a state field.")
"""
const GIO_EPI = """
proc run*(self: GApplication): int =
int(g_application_run(cast[ptr GApplication00](self.impl), 0, nil))
"""
const GTK_EPI = """
proc init* =
var argc: int32 = 0
var argv: cstringArray = nil
gtk_init(argc, argv)
proc loadFromData*(self: CssProvider; data: cstring): bool =
loadFromData(self, uint8Array(data), -1)
proc gtk_file_chooser_dialog_new*(title: cstring; parent: ptr Window00; action: FileChooserAction;
firstButtonText: cstring = nil): ptr FileChooserDialog00 {.varargs,
importc: "gtk_file_chooser_dialog_new", libprag.}
proc newFileChooserDialog*(title: string = ""; parent: Window = nil; action: FileChooserAction): FileChooserDialog =
let gobj = gtk_file_chooser_dialog_new(safeStringToCString(title), if parent.isNil: nil else: cast[ptr Window00](parent.impl), action)
if g_object_get_qdata(gobj, Quark) != nil:
result = cast[type(result)](g_object_get_qdata(gobj, Quark))
assert(result.impl == gobj)
else:
new(result, finalizeGObject)
result.impl = gobj
GC_ref(result)
discard g_object_ref_sink(result.impl)
g_object_add_toggle_ref(result.impl, toggleNotify, addr(result[]))
g_object_unref(result.impl)
assert(g_object_get_qdata(result.impl, Quark) == nil)
g_object_set_qdata(result.impl, Quark, addr(result[]))
proc initFileChooserDialog*[T](result: var T; title: string = ""; parent: Window = nil; action: FileChooserAction) =
assert(result is FileChooserDialog)
let gobj = gtk_file_chooser_dialog_new(safeStringToCString(title), if parent.isNil: nil else: cast[ptr Window00](parent.impl), action)
if g_object_get_qdata(gobj, Quark) != nil:
result = cast[type(result)](g_object_get_qdata(gobj, Quark))
assert(result.impl == gobj)
else:
new(result, finalizeGObject)
result.impl = gobj
GC_ref(result)
discard g_object_ref_sink(result.impl)
g_object_add_toggle_ref(result.impl, toggleNotify, addr(result[]))
g_object_unref(result.impl)
assert(g_object_get_qdata(result.impl, Quark) == nil)
g_object_set_qdata(result.impl, Quark, addr(result[]))
import macros, strutils
include gisup
include gimpl
"""
proc main(namespace: string) =
priList = newSeq[string]()
suppressType = false
suppressRaise = false
delayedMethods = newSeq[(GIBaseInfo, GIFunctionInfo)]()
classList = newSeq[GIBaseInfo]()
output = newStringStream()
methodBuffer = newStringStream()
var error: GError
ct = initCountTable[string]()
var delayedSyms = newSeq[GIBaseInfo]()
allSyms = initHashSet[string]()
provInt.clear
interfaceProvider.clear
var ig = initHashSet[string]()
knownSyms = initHashSet[string]()
let gi = gIrepositoryGetDefault()
assert(gi != nil)
moduleNamespace = namespace.toLowerAscii
let version: cstring = nil # latest
let typelib = gi.gIrepositoryRequire(namespace, version, cast[GIRepositoryLoadFlags](0), error)
if typelib.isNil:
echo error.message
echo "Maybe for your OS you have to install additional GTK related packages?"
echo "We continue with the remaining packages..."
#quit()
return
let dep: cstringArray = gi.gIrepositoryGetDependencies(namespace)
output.writeLine("# dependencies:")
var importedModules = ""
for j in 0 .. 9:
if dep[j].isNil: break
if j == 0:
importedModules = "import "
output.writeLine("# ", dep[j])
importedModules.add(($dep[j]).split('-',2)[0].toLowerAscii & ", ")
importedModules.removeSuffix(", ")
strfreev(dep)
let idep: cstringArray = gi.gIrepositoryGetImmediateDependencies(namespace)
output.writeLine("# immediate dependencies:")
for j in 0 .. 9:
if idep[j].isNil: break
output.writeLine("# ", idep[j])
strfreev(idep)
let libs = gi.gIrepositoryGetSharedLibrary(namespace)
output.writeLine("# libraries:")
output.writeLine("# ", libs)
output.writeLine("{.deadCodeElim: on.}")
output.writeLine(importedModules)
var Lib = if libs.isNil: "" else: ($libs).split(',', 2)[0]
if namespace == "PangoCairo" and Lib.startsWith("libpango-"): Lib = Lib.replace("libpango-", "libpangocairo-") # GI bug?
output.writeLine("const Lib* = \"$1\"" % Lib)
output.writeLine("{.pragma: libprag, cdecl, dynlib: Lib.}")
if namespace == "GObject": # declare array types to make it compile -- procs using these will need special care!
output.writeLine("type\n GCallback* = proc () {.cdecl.}")
output.writeLine("type\n Parameter00Array* = pointer")
output.writeLine("type\n Object00Array* = pointer")
output.writeLine("type\n Value00Array* = pointer")
output.writeLine("type\n GTypeArray* = pointer")
output.writeLine("type\n ParamSpec00Array* = pointer")
output.writeLine("type\n TypePlugin00Array* = pointer")
output.writeLine("type\n uint32Array* = pointer")
output.writeLine("type\n VaClosureMarshal* = pointer")
#output.writeLine("type\n TypePlugin00* = object")
elif namespace == "GLib":
output.writeLine("type\n GException* = object of Exception")
output.writeLine("type\n OptionEntry00Array* = pointer")
output.writeLine("type\n GArray00* = pointer")
output.writeLine("type\n int8Array* = pointer")
output.writeLine("type\n uintArray* = pointer")
output.writeLine("type\n gbooleanArray* = pointer")
output.writeLine("type\n cdoubleArray* = pointer")
output.writeLine("type\n int32Array* = pointer")
output.writeLine("type\n PollFD00Array* = pointer")
output.writeLine("type\n Variant00Array* = pointer")
output.writeLine("type\n Regex00Array* = pointer")
output.writeLine("type\n LogField00Array* = pointer")
output.writeLine("type\n VariantType00Array* = pointer")
output.writeLine("type\n DebugKey00Array* = pointer")
output.writeLine("type\n utf8Array* = pointer")
output.writeLine("type\n uint8Array* = pointer")
output.writeLine("type\n ucstringArray* = pointer")
output.writeLine("type\n ucstring* = distinct cstring")
output.writeLine("type\n gboolean* = distinct cint")
output.writeLine("const\n GLIB_SIZEOF_VOID_P = sizeof(pointer)")
output.writeLine("const\n GLIB_SIZEOF_SIZE_T* = GLIB_SIZEOF_VOID_P")
output.writeLine("const\n GLIB_SIZEOF_LONG* = sizeof(clong)")
output.writeLine("type\n Gssize* = csize")
output.writeLine("type\n Gsize* = csize # note: csize is signed in Nim!")
#output.writeLine("type\n GType* = distinct cint") # wrong
#stefan@nuc ~/Downloads/glib-2.53.3/gobject $ grep -A5 GLIB_SIZEOF_S *.h
#gtype.h:#if GLIB_SIZEOF_SIZE_T != GLIB_SIZEOF_LONG || !defined __cplusplus
#gtype.h-typedef gsize GType;
#gtype.h-#else /* for historic reasons, C++ links against gulong GTypes */
#gtype.h-typedef gulong GType;
#gtype.h-#endif
output.writeLine("when GLIB_SIZEOF_SIZE_T != GLIB_SIZEOF_LONG or not defined(cpp):")
output.writeLine(" type\n GType* = Gsize")
output.writeLine("else:")
output.writeLine(" type\n GType* = culong")
output.writeLine("type\n gunichar* = uint32")
output.writeLine("type\n utf8* = char")
output.writeLine("const GFalse = gboolean(0)")
output.writeLine("const GTrue = gboolean(1)")
output.writeLine("proc cogfree*(mem: pointer) {.importc: \"g_free\", libprag.}")
output.writeLine("proc toBool*(g: gboolean): bool = g.int != 0")
output.writeLine("proc safeStringToCString*(s: cstring): cstring = (if s.len == 0: nil else: s)")
elif namespace == "Gdk":
output.writeLine("type\n AtomArray* = pointer")
output.writeLine("type\n KeymapKey00Array* = pointer")
output.writeLine("type\n VisualTypeArray* = pointer") # enums!
output.writeLine("type\n RGBAArray* = pointer")
output.writeLine("type\n AxisUseArray* = pointer")
output.writeLine("type\n ColorArray* = pointer")
output.writeLine("type\n Point00Array* = pointer")
elif namespace == "Gtk":
output.writeLine("type\n TargetEntry00Array* = pointer")
output.writeLine("type\n AccelGroupEntry00Array* = pointer")
output.writeLine("type\n BindingArg00Array* = pointer")
output.writeLine("type\n StockItemArray* = pointer")
output.writeLine("type\n PageRange00Array* = pointer")
output.writeLine("type\n PadActionEntry00Array* = pointer")
output.writeLine("type\n Array* = pointer")
elif namespace == "Atk":
output.writeLine("type\n StateTypeArray* = pointer") # enums!
output.writeLine("type\n TextRange00Array* = pointer")
#output.writeLine("type\n PtrArray* = pointer")
elif namespace == "Pango":
output.writeLine("type\n GlyphInfo00Array* = pointer")
output.writeLine("type\n LogAttr00Array* = pointer")
output.writeLine("type\n FontDescription00Array* = pointer")
output.writeLine("type\n FontFamily00Array* = pointer")
output.writeLine("type\n FontFace00Array* = pointer")
output.writeLine("type\n ScriptArray* = pointer") # array of enums!
elif namespace == "Gio":
output.writeLine("type\n ActionEntry00Array* = pointer")
output.writeLine("type\n DBusAnnotationInfo00Array* = pointer")
output.writeLine("type\n DBusArgInfo00Array* = pointer")
output.writeLine("type\n DBusMethodInfo00Array* = pointer")
output.writeLine("type\n DBusSignalInfo00Array* = pointer")
output.writeLine("type\n DBusPropertyInfo00Array* = pointer")
output.writeLine("type\n DBusInterfaceInfo00Array* = pointer")
output.writeLine("type\n DBusNodeInfo00Array* = pointer")
output.writeLine("type\n DBusErrorEntry00Array* = pointer")
output.writeLine("type\n InputVector00Array* = pointer")
output.writeLine("type\n SocketControlMessage00Array* = pointer")
output.writeLine("type\n InputMessage00Array* = pointer")
output.writeLine("type\n OutputMessage00Array* = pointer")
output.writeLine("type\n utf8ArrayArray* = pointer")
output.writeLine("type\n cstringArrayArray* = pointer")
output.writeLine("type\n File00Array* = pointer")
output.writeLine("type\n Array* = pointer")
output.writeLine("type\n OutputVector00Array* = pointer")
elif namespace == "GtkSource":
output.writeLine("import glib")
elif namespace == "Vte":
output.writeLine("import glib\n")
output.writeLine("type\n Regex00Array* = pointer")
if namespace == "GObject":
output.writeLine("\nimport times")
output.writeLine("var qt = \"NGIQ\" & $epochTime()")
output.writeLine("if g_quark_try_string(qt) != 0:")
output.writeLine(" qt = \"NGIQ\" & $epochTime()")
output.writeLine("let Quark* = g_quark_from_static_string(qt)")
var n = gi.gIrepositoryGetNInfos(namespace)
var s = newSeq[GIBaseInfo]()
for i in 0.cint ..< n:
if not droppedSyms.contains(mangleName(gBaseInfoGetName(gi.gIrepositoryGetInfo(namespace, i)))):
s.add(gi.gIrepositoryGetInfo(namespace, i))
for i in s:
if gBaseInfoGetType(i) == GIInfoType.OBJECT or gBaseInfoGetType(i) == GIInfoType.INTERFACE or gBaseInfoGetType(i) == GIInfoType.STRUCT or gBaseInfoGetType(i) == GIInfoType.UNION or isEnumInfo(i) or isCallbackInfo(i):
allSyms.incl(mangleName(gBaseInfoGetName(i)))
for i in 0 .. s.high:
if namespace == "GLib" and gBaseInfoGetType(s[i]) == GIInfoType.STRUCT and gBaseInfoGetName(s[i]) == "Error":
let h = s[i]
s.delete(i, i)
s.insert([h])
break
for info in s:
if gBaseInfoGetType(info) == GIInfoType.OBJECT:
let ninterfaces = info.gObjectInfoGetNInterfaces
if ninterfaces > 0:
var interf = newSeq[string]()
let name = $gBaseInfoGetName(info)
for i in 0.cint ..< ninterfaces:
interf.add($gBaseInfoGetName(info.gObjectInfoGetInterface(i)))
if provInt.contains(name):
assert false
else:
provInt[name] = interf
for obj, ifaces in provInt:
for i in ifaces:
if not interfaceProvider.contains(i):
interfaceProvider[i] = @[obj]
else:
interfaceProvider[i].add(obj)
if namespace == "Gdk": # special care for gdk keys due to nim's style insensitivity!
for i in s:
var h = $gBaseInfoGetName(i)
if h.startsWith("KEY_"):
if gdkKeys.contains(h.toLowerAscii):
#gdkKeys.mget(h.toLowerAscii).add(h)
gdkKeys[h.toLowerAscii].add(h)
else:
gdkKeys.add(h.toLowerAscii, @[h])
for el in mvalues(gdkKeys):
sort(el, system.cmp)
var i: GIBaseInfo
var unp = newSeq[GIBaseInfo]()
reverse(s)
var more_runs = 50
while s.len > 0 or more_runs > 0:
if s.len == 0: dec(more_runs)
if namespace == "GObject" and not knownSyms.contains("g_signal_connect_data"):
if knownSyms.contains("ClosureNotify") and knownSyms.contains("ConnectFlags"):
knownSyms.incl("g_signal_connect_data")
output.writeLine("proc g_signal_connect_data*(instance: pointer; detailedSignal: cstring; cHandler: GCallback;")
output.writeLine(" data: pointer; destroyData: ClosureNotify; connectFlags: ConnectFlags): culong {.")
output.writeLine(" importc: \"g_signal_connect_data\", libprag.}")
while priList.len > 0: # move missing symbols to top, but only once!
let h = priList.pop
if ig.contains(h): continue
ig.incl(h)
#######echo h
var k = -1
for p, el in s:
if (gBaseInfoGetType(el) == GIInfoType.OBJECT or gBaseInfoGetType(el) == GIInfoType.INTERFACE or gBaseInfoGetType(el) == GIInfoType.STRUCT or isEnumInfo(el)) and gBaseInfoGetName(el) == h:
k = p
if k >= 0:
#######echo "moved"
s.add(s[k])
s.delete(k)
if s.len > 0:
i = s.pop
delayedSyms.insert(i)
if classList.len > 0:
delayedSyms.insert(classList.pop)
unp.setLen(0)
for k in delayedSyms:
var pos = output.getPosition
var supmodpos = supmod.getPosition
try:
#echo "try process ", mangleName(gBaseInfoGetName(k))
knownSyms.incl(mangleName(gBaseInfoGetName(k)))
methodBuffer = newStringStream()
signalBuffer = newStringStream()
processInfo(k)
output.write(signalBuffer.data)
output.write(methodBuffer.data)
#######echo "----------", gBaseInfoGetName(k)
except UndefEx:
unp.add(k)
knownSyms.excl(mangleName(gBaseInfoGetName(k)))
output.cut(pos)
supmod.cut(supmodpos)
delayedSyms = unp
block myb:
for a in 1 .. 2: # process clustered symbols into one single type section
if delayedSyms.len > a:
suppressType = true
methodBuffer = newStringStream()
signalBuffer = newStringStream()
unp = delayedSyms
for t in unp.combinations(a + 1):
var pos = output.getPosition
var supmodpos = supmod.getPosition
methodBuffer = newStringStream()
signalBuffer = newStringStream()
let x = delayedMethods.len
try:
var h = false
for k in t:
if gBaseInfoGetType(k) != GIInfoType.INTERFACE and gBaseInfoGetType(k) != GIInfoType.OBJECT and gBaseInfoGetType(k) != GIInfoType.STRUCT and gBaseInfoGetType(k) != GIInfoType.UNION and not isCallbackInfo(k):
h = true
if h: continue
output.writeLine("type")
for k in t:
knownSyms.incl(mangleName(gBaseInfoGetName(k)))
for k in t:
processInfo(k)
for k in t:
delayedSyms.keepItIf(mangleName(gBaseInfoGetName(k)) != mangleName(gBaseInfoGetName(it)))
suppressType = false
output.write(signalBuffer.data)
output.write(methodBuffer.data)
break myb
except UndefEx:
for k in t:
knownSyms.excl(mangleName(gBaseInfoGetName(k)))
output.setPosition(pos)
supmod.cut(supmodpos)
assert delayedMethods.len >= x
delayedMethods.setLen(x)
suppressType = false
methodBuffer = newStringStream()
var h = delayedMethods
#delayedMethods.setLen(0)
delayedMethods = newSeq[(GIBaseInfo, GIFunctionInfo)]()
for el in h:
writeMethod(el[0], el[1])
output.write(methodBuffer.data)
suppressRaise = true
output.writeLine("# === remaining symbols:") # in best case there is nothing left
for i in delayedSyms:
processInfo(i)
if namespace == "Gtk":
output.write(GTK_EPI)
for i in GtkBuilderObjects.split:
if i == "": continue
output.write("""
proc get$1*(builder: Builder; name: string): $1 =
new result
let gt = g_type_from_name("Gtk$1")
assert(gt != 0)
result.impl = gtk_builder_get_object(cast[ptr Builder00](builder.impl), name)
assert(toBool(g_type_check_instance_is_a(cast[ptr TypeInstance00](result.impl), gt)))
""" % [i])
output.write("")
if namespace == "Gio":
output.write(GIO_EPI)
if namespace == "Gdk":
output.write(GDK_EPI)
if namespace == "GtkSource":
output.write(GTK_SOURCE_EPI)
output.flush
var o = open("nim_gi" / (namespace.toLowerAscii) & ".nim", fmWrite)
o.write(output.data)
o.close()
output.close
echo "Remaining delayed methods: ", delayedMethods.len
for el in delayedMethods:
echo gBaseInfoGetName(el[1])
# when isMainModule:
#scfilter = initHashSet[string]()
supmod = newStringStream()
supmod.writeLine("const\n SCA = [")
main("fontconfig")
#main("nothing")
main("freetype2")
main("PangoCairo")
main("PangoFT2")
main("GLib")
main("GObject")
main("GModule")
main("xlib")
main("Gio")
main("Atk")
main("Pango")
## main("cairo") # that file is now hand crafted
main("GdkPixbuf")
main("Rsvg")
main("Gdk")
main("Gtk")
main("GtkSource")
main("Vte")
main("Notify")
supmod.writeLine(" ]")
supmod.flush
var o = open("nim_gi" / "gisup.nim", fmWrite)
o.write(supmod.data)
o.close()
supmod.close
#for i in callerAllocCollector: echo i
# 1743 lines