some fixes for better GTK4 support

This commit is contained in:
Stefan Salewski 2020-07-07 19:48:29 +02:00
commit 7d982645e6
4 changed files with 222 additions and 93 deletions

View file

@ -1,6 +1,6 @@
= High level GTK3 (and GTK4) bindings for the Nim programming language = High level GTK3 (and GTK4) bindings for the Nim programming language
(c) Stefan Salewski (c) Stefan Salewski
//Version 0.7.7 //Version 0.7.8
:experimental: :experimental:
:imagesdir: http://ssalewski.de/tmp :imagesdir: http://ssalewski.de/tmp
:source-highlighter: pygments :source-highlighter: pygments
@ -25,7 +25,12 @@ with code inserted from files directly.
NOTE: This work is partly based on earlier works of J. Mansour and has been supported by A. Rumpf, E. Bassi and other _Nim_ and _GTK/Gnome_ developers. NOTE: This work is partly based on earlier works of J. Mansour and has been supported by A. Rumpf, E. Bassi and other _Nim_ and _GTK/Gnome_ developers.
The `combinatorics` module was kindly provided by R. Behrends. The `combinatorics` module was kindly provided by R. Behrends.
NOTE: This is version 0.7.7 which contains the fixes from https://github.com/StefanSalewski/gintro/issues/75. NOTE: This is version 0.7.8 which contains again some changes. The two GTK4 examples from http://ssalewski.de/gtkprogramming.html
should work now, and the existing GTK3 examples seems still to work. But maybe other programs don't work any
more now?
NOTE: Version 0.7.7 contains the fixes from https://github.com/StefanSalewski/gintro/issues/75.
Mr lscrd has tested it already by use of nimble install gintro@#head some weeks ago, so we may assume that Mr lscrd has tested it already by use of nimble install gintro@#head some weeks ago, so we may assume that
it works properly. Next version will again have serious modifications for GTK4, see http://ssalewski.de/gtkprogramming.html. it works properly. Next version will again have serious modifications for GTK4, see http://ssalewski.de/gtkprogramming.html.
So it may be a good idea to have a version 0.7.7 available as a fallback. So it may be a good idea to have a version 0.7.7 available as a fallback.

View file

@ -1,6 +1,6 @@
# Package # Package
version = "0.7.7" version = "0.7.8"
author = "Stefan Salewski" author = "Stefan Salewski"
description = "High level GObject-Introspection based GTK3/GTK4 bindings" description = "High level GObject-Introspection based GTK3/GTK4 bindings"
license = "MIT" license = "MIT"

View file

@ -154,6 +154,7 @@ proc $1$2 {.cdecl.} =
r1s.add(" var " & names[i] & "1 {.global.}: " & types[i] & "\n") r1s.add(" var " & names[i] & "1 {.global.}: " & types[i] & "\n")
r1s.add(" if " & names[i] & "1" & ".isNil:\n") r1s.add(" if " & names[i] & "1" & ".isNil:\n")
r1s.add(" new " & names[i] & "1" & "\n") r1s.add(" new " & names[i] & "1" & "\n")
r1s.add(" GC_ref(" & names[i] & "1)" & "\n") # never call destroy/finalizer on this global variable
r1s.add(" " & names[i] & "1.ignoreFinalizer = true" & "\n") r1s.add(" " & names[i] & "1.ignoreFinalizer = true" & "\n")
r1s.add(" " & names[i] & "1.impl = " & names[i] & "\n") r1s.add(" " & names[i] & "1.impl = " & names[i] & "\n")
if not ignoreArg.boolVal: if not ignoreArg.boolVal:

View file

@ -1,6 +1,6 @@
# High level gobject-introspection based GTK3/GTK4 bindings for the Nim programming language # High level gobject-introspection based GTK3/GTK4 bindings for the Nim programming language
# nimpretty --maxLineLen:130 gen.nim # nimpretty --maxLineLen:130 gen.nim
# v 0.7.7 2020-JUN-01 # v 0.7.8 2020-JUL-07
# (c) S. Salewski 2018 # (c) S. Salewski 2018
# https://wiki.gnome.org/Projects/GObjectIntrospection # https://wiki.gnome.org/Projects/GObjectIntrospection
@ -44,6 +44,7 @@ import sets
import bitops import bitops
import tables import tables
import algorithm import algorithm
# from sugar import dup
from combinatorics import combinations from combinatorics import combinations
template isCallbackInfo(info: untyped): untyped = template isCallbackInfo(info: untyped): untyped =
@ -82,6 +83,11 @@ template try tuple type using var when while xor yield
int int8 int16 int32 int64 uint uint8 uint16 uint32 uint64 float float32 float64 pointer false true string char bool int int8 int16 int32 int64 uint uint8 uint16 uint32 uint64 float float32 float64 pointer false true string char bool
""".split """.split
# for Nim < v1.2, avoid use of sugar.dup()
proc prefixRemoved(s, prefix: string): string =
result = s
result.removePrefix(prefix)
proc unCap(s: var string) = proc unCap(s: var string) =
s[0] = s[0].toLowerAscii s[0] = s[0].toLowerAscii
@ -161,6 +167,7 @@ var fixedDestroyNames: Table[string, string]
var mangledNames: Table[string, string] var mangledNames: Table[string, string]
var mangledTypes: Table[string, string] var mangledTypes: Table[string, string]
var arrayCollector: HashSet[string]
var allSyms: HashSet[string] var allSyms: HashSet[string]
var droppedSyms: HashSet[string] var droppedSyms: HashSet[string]
var privStr: HashSet[string] var privStr: HashSet[string]
@ -398,14 +405,23 @@ proc genRec(t: GITypeInfo; genProxy = false; fullQualified: bool = false): (stri
elif gTypeInfoIsZeroTerminated(t): elif gTypeInfoIsZeroTerminated(t):
result[0] = child & "Array" result[0] = child & "Array"
result[1] = intA0 result[1] = intA0
if result[0].find('.') < 0:
# arrayCollector.incl(result[0].dup(removePrefix("ptr ")))
arrayCollector.incl(result[0].prefixRemoved("ptr "))
return return
else: else:
if child in UnnamedArrayCandidates: if child in UnnamedArrayCandidates:
result[1] = intA0 # yes we need this result[1] = intA0 # yes we need this
result[0] = child & "Array" result[0] = child & "Array"
if result[0].find('.') < 0:
# arrayCollector.incl(result[0].dup(removePrefix("ptr ")))
arrayCollector.incl(result[0].prefixRemoved("ptr "))
return # we call it Array and return -- so we mark it for now, but it does not really help :-( return # we call it Array and return -- so we mark it for now, but it does not really help :-(
else: else:
result[0] = child & "Array" result[0] = child & "Array"
if result[0].find('.') < 0:
# arrayCollector.incl(result[0].dup(removePrefix("ptr ")))
arrayCollector.incl(result[0].prefixRemoved("ptr "))
return # we call it Array and return -- so we mark it for now, but it does not really help :-( return # we call it Array and return -- so we mark it for now, but it does not really help :-(
elif tag == GITypeTag.INTERFACE: elif tag == GITypeTag.INTERFACE:
let iface = gTypeInfoGetInterface(t) let iface = gTypeInfoGetInterface(t)
@ -716,7 +732,8 @@ proc writeMethod(info: GIBaseInfo; minfo: GIFunctionInfo) =
methodBuffer.writeLine(" g_error_free(gerror[])") methodBuffer.writeLine(" g_error_free(gerror[])")
methodBuffer.writeLine(" raise newException(GException, msg)") methodBuffer.writeLine(" raise newException(GException, msg)")
template gobjectTemp(): untyped = template oldgobjectTemp(): untyped =
assert sym notin ["g_object_ref_sink", "g_object_ref"]
assert(gCallableInfoGetCallerOwns(minfo) in {GITransfer.NOTHING, EVERYTHING}) # both occur assert(gCallableInfoGetCallerOwns(minfo) in {GITransfer.NOTHING, EVERYTHING}) # both occur
methodBuffer.writeLine(" let gobj = " & sym & arglist) methodBuffer.writeLine(" let gobj = " & sym & arglist)
checkForGerror() checkForGerror()
@ -724,22 +741,77 @@ proc writeMethod(info: GIBaseInfo; minfo: GIFunctionInfo) =
methodBuffer.writeLine(" if gobj.isNil:") methodBuffer.writeLine(" if gobj.isNil:")
methodBuffer.writeLine(" return nil") # https://github.com/StefanSalewski/gintro/issues/63 methodBuffer.writeLine(" return nil") # https://github.com/StefanSalewski/gintro/issues/63
methodBuffer.writeLine(" let qdata = g_object_get_qdata(gobj, Quark)") methodBuffer.writeLine(" let qdata = g_object_get_qdata(gobj, Quark)")
methodBuffer.writeLine(" if qdata != nil:") methodBuffer.writeLine(" if qdata != nil:") # gtk_widget_get_toplevel, gdk_display_get_default, gtk_widget_get_window
#if (gFunctionInfoGetFlags(mInfo).int and GIFunctionInfoFlags.IS_CONSTRUCTOR.int) != 0:
# methodBuffer.writeLine(" assert false") # caution: i.e. gdk_cursor_new_from_name ()
methodBuffer.writeLine(" result = cast[type(result)](qdata)") methodBuffer.writeLine(" result = cast[type(result)](qdata)")
methodBuffer.writeLine(" assert(result.impl == gobj)") methodBuffer.writeLine(" assert(result.impl == gobj)")
#methodBuffer.writeLine(" echo \"<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\"")
#methodBuffer.writeLine(" echo \"YXC $1 \", result.refCount" % [sym])
methodBuffer.writeLine(" else:") methodBuffer.writeLine(" else:")
if sym == "g_object_ref" or sym == "g_object_ref_sink": if (gFunctionInfoGetFlags(mInfo).int and GIFunctionInfoFlags.IS_CONSTRUCTOR.int) == 0 and
methodBuffer.writeLine(" assert(false)") gCallableInfoGetCallerOwns(minfo) == GITransfer.NOTHING:
assert false methodBuffer.writeLine(" fnew(result, $1finalizeGObject)" % [mprefix])
methodBuffer.writeLine(" result.impl = gobj")
# methodBuffer.writeLine(" assert(g_object_is_floating(result.impl).cint == 0)") # can't assert due to gst
# https://discourse.gnome.org/t/got-assert-error-for-nim-version-of-gst-basic-tutorial/3732
methodBuffer.writeLine(" assert(g_object_get_qdata(result.impl, Quark) == nil)")
methodBuffer.writeLine(" g_object_set_qdata(result.impl, Quark, addr(result[]))")
methodBuffer.writeLine(" result.ignoreFinalizer = true")
else: else:
assert((gFunctionInfoGetFlags(mInfo).int and GIFunctionInfoFlags.IS_CONSTRUCTOR.int) != 0 or
gCallableInfoGetCallerOwns(minfo) == GITransfer.EVERYTHING)
methodBuffer.writeLine(" fnew(result, $1finalizeGObject)" % [mprefix]) methodBuffer.writeLine(" fnew(result, $1finalizeGObject)" % [mprefix])
methodBuffer.writeLine(" result.impl = gobj") methodBuffer.writeLine(" result.impl = gobj")
methodBuffer.writeLine(" GC_ref(result)") methodBuffer.writeLine(" GC_ref(result)")
methodBuffer.writeLine(" if g_object_is_floating(result.impl).cint != 0.cint:")
methodBuffer.writeLine(" discard g_object_ref_sink(result.impl)")
methodBuffer.writeLine(" g_object_add_toggle_ref(result.impl, toggleNotify, addr(result[]))")
if sym in ["gtk_window_new", "gtk_application_window_new"]: # GC_ref() so we never free the main window!
methodBuffer.writeLine(" GC_ref(result)")
methodBuffer.writeLine(" result.ignoreFinalizer = true")
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[]))")
#methodBuffer.writeLine(" echo \"YXC $1 \", result.refCount" % [sym])
# new for v0.7.8: we ref all gobjects now, even if transfer is none. So result.ignoreFinalizer = false always for gobjects!
template gobjectTemp(): untyped =
assert sym notin ["g_object_ref_sink", "g_object_ref"]
assert(gCallableInfoGetCallerOwns(minfo) in {GITransfer.NOTHING, EVERYTHING}) # both occur
methodBuffer.writeLine(" let gobj = " & sym & arglist)
checkForGerror()
if gCallableInfoMayReturnNull(minfo):
methodBuffer.writeLine(" if gobj.isNil:")
methodBuffer.writeLine(" return nil") # https://github.com/StefanSalewski/gintro/issues/63
methodBuffer.writeLine(" let qdata = g_object_get_qdata(gobj, Quark)")
methodBuffer.writeLine(" if qdata != nil:") # gtk_widget_get_toplevel, gdk_display_get_default, gtk_widget_get_window
#if (gFunctionInfoGetFlags(mInfo).int and GIFunctionInfoFlags.IS_CONSTRUCTOR.int) != 0:
# methodBuffer.writeLine(" assert false") # constructors should always allocate new objects -- lets verify that
# no, will fail i.e. for gdk_cursor_new_from_name()
methodBuffer.writeLine(" result = cast[type(result)](qdata)")
methodBuffer.writeLine(" assert(result.impl == gobj)")
#methodBuffer.writeLine(" echo \"<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\"")
#methodBuffer.writeLine(" echo \"YXC $1 \", result.refCount" % [sym])
methodBuffer.writeLine(" else:")
#assert((gFunctionInfoGetFlags(mInfo).int and GIFunctionInfoFlags.IS_CONSTRUCTOR.int) != 0 or
# gCallableInfoGetCallerOwns(minfo) == GITransfer.EVERYTHING)
methodBuffer.writeLine(" fnew(result, $1finalizeGObject)" % [mprefix])
methodBuffer.writeLine(" result.impl = gobj")
methodBuffer.writeLine(" GC_ref(result)")
if sym in ["gtk_window_new", "gtk_application_window_new"]: # GC_ref() so we never free the main window!
methodBuffer.writeLine(" GC_ref(result)")
methodBuffer.writeLine(" result.ignoreFinalizer = true")
elif gCallableInfoGetCallerOwns(minfo) == GITransfer.NOTHING:
methodBuffer.writeLine(" discard g_object_ref_sink(result.impl)")
else:
methodBuffer.writeLine(" if g_object_is_floating(result.impl).int != 0:")
methodBuffer.writeLine(" discard g_object_ref_sink(result.impl)") 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_add_toggle_ref(result.impl, toggleNotify, addr(result[]))")
methodBuffer.writeLine(" g_object_unref(result.impl)") methodBuffer.writeLine(" g_object_unref(result.impl)")
methodBuffer.writeLine(" assert(g_object_get_qdata(result.impl, Quark) == nil)") methodBuffer.writeLine(" assert(g_object_get_qdata(result.impl, Quark) == nil)")
methodBuffer.writeLine(" g_object_set_qdata(result.impl, Quark, addr(result[]))") methodBuffer.writeLine(" g_object_set_qdata(result.impl, Quark, addr(result[]))")
#methodBuffer.writeLine(" echo \"YXC $1 \", result.refCount" % [sym])
# prefer gboxed_free() but fall back for GVariant # prefer gboxed_free() but fall back for GVariant
template findFreeProc(info: GIBaseInfo; noWarning: bool): untyped = template findFreeProc(info: GIBaseInfo; noWarning: bool): untyped =
@ -884,12 +956,13 @@ proc writeMethod(info: GIBaseInfo; minfo: GIFunctionInfo) =
asym = asym[3 .. ^1].unCap asym = asym[3 .. ^1].unCap
asym = '`' & asym & '=' & '`' asym = '`' & asym & '=' & '`'
if keywords.contains(asym) or nims.contains(asym): continue if keywords.contains(asym) or nims.contains(asym): continue
if asym == "`tings=`": continue # result of get_settings
# the large proxy block BLOCK7 { # the large proxy block BLOCK7 {
let b7 = needProxyProc(mInfo) or isString(ret2) or replist.len > 0 or ct2nt.contains(genRec(ret2)[0]) let b7 = needProxyProc(mInfo) or isString(ret2) or replist.len > 0 or ct2nt.contains(genRec(ret2)[0])
# export only low level symbols that are needed internally -- maybe we should export only a private name for them # export only low level symbols that are needed internally -- maybe we should export only a private name for them
if run == 0: if run == 0:
if sym in ["g_quark_from_static_string", "g_error_free", "g_object_get_qdata", "g_object_ref_sink", "g_object_unref", if sym in ["g_quark_from_static_string", "g_error_free", "g_object_get_qdata", "g_object_ref_sink", "g_object_unref",
"g_timeout_add_full", "g_timeout_add_full", "g_object_is_floating",
"g_type_from_name", "g_type_check_instance_is_a", "g_idle_add_full", "g_quark_try_string", "vte_regex_unref", "g_type_from_name", "g_type_check_instance_is_a", "g_idle_add_full", "g_quark_try_string", "vte_regex_unref",
"gtk_builder_get_object"]: "gtk_builder_get_object"]:
methodBuffer.write("\nproc " & sym & EM & plist) methodBuffer.write("\nproc " & sym & EM & plist)
@ -959,9 +1032,9 @@ proc writeMethod(info: GIBaseInfo; minfo: GIFunctionInfo) =
# CAUTION: some procs are advertised as constructor but do not construct new objects, # CAUTION: some procs are advertised as constructor but do not construct new objects,
# they just return existing ones as gdk_cursor_new_from_name() # they just return existing ones as gdk_cursor_new_from_name()
gobjectTemp() gobjectTemp()
if (gFunctionInfoGetFlags(mInfo).int and GIFunctionInfoFlags.IS_CONSTRUCTOR.int) == 0 and ###if (gFunctionInfoGetFlags(mInfo).int and GIFunctionInfoFlags.IS_CONSTRUCTOR.int) == 0 and
gCallableInfoGetCallerOwns(minfo) == GITransfer.NOTHING: ### gCallableInfoGetCallerOwns(minfo) == GITransfer.NOTHING:
methodBuffer.writeLine(" result.ignoreFinalizer = true") # as we have always to attach one with ARC. ### methodBuffer.writeLine(" result.ignoreFinalizer = true") # as we have always to attach one with ARC.
elif gCallableInfoGetCallerOwns(minfo) == GITransfer.CONTAINER: elif gCallableInfoGetCallerOwns(minfo) == GITransfer.CONTAINER:
assert false assert false
elif gCallableInfoGetCallerOwns(minfo) == GITransfer.EVERYTHING or elif gCallableInfoGetCallerOwns(minfo) == GITransfer.EVERYTHING or
@ -1005,6 +1078,7 @@ proc writeMethod(info: GIBaseInfo; minfo: GIFunctionInfo) =
gCallableInfoGetCallerOwns(minfo) == GITransfer.NOTHING) or gCallableInfoGetCallerOwns(minfo) == GITransfer.NOTHING) or
((gFunctionInfoGetFlags(mInfo).int and GIFunctionInfoFlags.IS_CONSTRUCTOR.int) != 0 and ((gFunctionInfoGetFlags(mInfo).int and GIFunctionInfoFlags.IS_CONSTRUCTOR.int) != 0 and
gBaseInfoGetName(info) == "Variant"): gBaseInfoGetName(info) == "Variant"):
assert((gFunctionInfoGetFlags(mInfo).int and GIFunctionInfoFlags.IS_CONSTRUCTOR.int) != 0)
methodBuffer.writeLine(" result.ignoreFinalizer = true") # as we have always to attach one with ARC. methodBuffer.writeLine(" result.ignoreFinalizer = true") # as we have always to attach one with ARC.
else: else:
echo "skipped ", sym echo "skipped ", sym
@ -1062,7 +1136,7 @@ proc writeMethod(info: GIBaseInfo; minfo: GIFunctionInfo) =
methodBuffer.writeLine(" result.impl = impl0") methodBuffer.writeLine(" result.impl = impl0")
else: else:
methodBuffer.writeLine(" result.impl = " & sym & arglist) methodBuffer.writeLine(" result.impl = " & sym & arglist)
if gCallableInfoGetCallerOwns(minfo) == GITransfer.NOTHING: if gCallableInfoGetCallerOwns(minfo) == GITransfer.NOTHING: # for the none gobjects
methodBuffer.writeLine(" result.ignoreFinalizer = true") # as we have always to attach one with ARC. methodBuffer.writeLine(" result.ignoreFinalizer = true") # as we have always to attach one with ARC.
elif false: #else: elif false: #else:
assert gCallableInfoGetCallerOwns(minfo) == GITransfer.NOTHING assert gCallableInfoGetCallerOwns(minfo) == GITransfer.NOTHING
@ -1105,7 +1179,6 @@ proc writeMethod(info: GIBaseInfo; minfo: GIFunctionInfo) =
methodBuffer.writeLine(" new(" & h2 & ")") methodBuffer.writeLine(" new(" & h2 & ")")
else: else:
methodBuffer.writeLine(" fnew(" & h2 & ", " & freeMeName & ")") methodBuffer.writeLine(" fnew(" & h2 & ", " & freeMeName & ")")
#if gCallableInfoGetCallerOwns(minfo) == GITransfer.NOTHING:
if gArgInfoGetOwnershipTransfer(arg) == GITransfer.NOTHING: if gArgInfoGetOwnershipTransfer(arg) == GITransfer.NOTHING:
methodBuffer.writeLine(" " & h2 & ".ignoreFinalizer = true") # as we have always to attach one with ARC. methodBuffer.writeLine(" " & h2 & ".ignoreFinalizer = true") # as we have always to attach one with ARC.
if gCallableInfoCanThrowGerror(minfo): if gCallableInfoCanThrowGerror(minfo):
@ -1771,6 +1844,8 @@ proc writeObj(info: GIObjectInfo) =
output.writeLine(" else:") output.writeLine(" else:")
output.writeLine(" GC_unref(cast[RootRef](data))") output.writeLine(" GC_unref(cast[RootRef](data))")
output.writeLine("\nproc finalizeGObject*[T](o: ref T) =") output.writeLine("\nproc finalizeGObject*[T](o: ref T) =")
#output.writeLine(" echo ")
output.writeLine(" g_object_set_qdata(o.impl, Quark, nil)")
output.writeLine("\n if not o.ignoreFinalizer:") output.writeLine("\n if not o.ignoreFinalizer:")
output.writeLine(" g_object_remove_toggle_ref(o.impl, toggleNotify, addr(o[]))") output.writeLine(" g_object_remove_toggle_ref(o.impl, toggleNotify, addr(o[]))")
@ -1782,7 +1857,6 @@ proc writeObj(info: GIObjectInfo) =
output.writeLine("{.importc, " & libprag & ".}") output.writeLine("{.importc, " & libprag & ".}")
let numsig = info.gObjectInfoGetNSignals let numsig = info.gObjectInfoGetNSignals
#if numsig > 0: signalbuffer.writeLine("")
for j in 0.cint ..< numsig: for j in 0.cint ..< numsig:
let signalInfo = gObjectInfoGetSignal(info, j) let signalInfo = gObjectInfoGetSignal(info, j)
let c = gSignalInfoGetClassClosure(signalInfo) let c = gSignalInfoGetClassClosure(signalInfo)
@ -1801,10 +1875,20 @@ proc writeObj(info: GIObjectInfo) =
output.writeLine("type\n Object* = ref object of RootRef") output.writeLine("type\n Object* = ref object of RootRef")
output.writeLine(" impl*: ptr Object00") output.writeLine(" impl*: ptr Object00")
output.writeLine(" ignoreFinalizer*: bool") output.writeLine(" ignoreFinalizer*: bool")
output.writeLine("\nproc refCount*(o: gobject.Object): int =")
output.writeLine(" let p = cast[ptr cuint](cast[int](o.impl) + sizeof(pointer))")
output.writeLine(" return p[].int")
if gObjectInfoGetFundamental(info) == GFalse: # guess work, ignore fake GObjects like GParamSpec and such if gObjectInfoGetFundamental(info) == GFalse: # guess work, ignore fake GObjects like GParamSpec and such
#output.writeLine("\nwhen compileOption(\"gc\", \"arc\"):") #output.writeLine("\nwhen compileOption(\"gc\", \"arc\"):")
#if not (mangleName(gBaseInfoGetName(info)) == "Window" and moduleNamespace == "gtk"):
if not (mangleName(gBaseInfoGetName(info)) in ["Window", "ApplicationWindow"] and moduleNamespace == "gtk"):
output.writeLine("\nwhen defined(gcDestructors):") output.writeLine("\nwhen defined(gcDestructors):")
output.writeLine(" proc `=destroy`*(self: var typeof(" & mangleName(gBaseInfoGetName(info)) & "()[])) =") output.writeLine(" proc `=destroy`*(self: var typeof(" & mangleName(gBaseInfoGetName(info)) & "()[])) =")
output.writeLine(" when defined(gintroDebug):")
output.writeLine(" echo \"destroy \", $typeof(self), ' ', cast[int](unsafeaddr self)")
output.writeLine(" g_object_set_qdata(self.impl, Quark, nil)")
output.writeLine(" if not self.ignoreFinalizer and self.impl != nil:") output.writeLine(" if not self.ignoreFinalizer and self.impl != nil:")
output.writeLine(" g_object_remove_toggle_ref(self.impl, toggleNotify, addr(self))") output.writeLine(" g_object_remove_toggle_ref(self.impl, toggleNotify, addr(self))")
output.writeLine(" self.impl = nil") output.writeLine(" self.impl = nil")
@ -1844,6 +1928,7 @@ proc writeObj(info: GIObjectInfo) =
output.writeLine("\nproc generic_$1*(self: $2) =" % [freeMeName, n]) output.writeLine("\nproc generic_$1*(self: $2) =" % [freeMeName, n])
output.writeLine(" if not self.ignoreFinalizer:") output.writeLine(" if not self.ignoreFinalizer:")
output.writeLine(" $1(self.impl)" % [freeMeName]) output.writeLine(" $1(self.impl)" % [freeMeName])
#if not (mangleName(gBaseInfoGetName(info)) == "Window" and moduleNamespace == "gtk"):
output.writeLine("\nwhen defined(gcDestructors):") output.writeLine("\nwhen defined(gcDestructors):")
output.writeLine(" proc `=destroy`*(self: var typeof(" & mangleName(gBaseInfoGetName(info)) & "()[])) =") output.writeLine(" proc `=destroy`*(self: var typeof(" & mangleName(gBaseInfoGetName(info)) & "()[])) =")
output.writeLine(" if not self.ignoreFinalizer and self.impl != nil:") output.writeLine(" if not self.ignoreFinalizer and self.impl != nil:")
@ -2075,6 +2160,14 @@ proc run*(self: GApplication): int =
""" """
const GObject_EPI = """
#proc refCount*(o: gobject.Object): int =
# let p = cast[ptr cuint](cast[int](o.impl) + sizeof(pointer))
# return p[].int
"""
const GTK3_EPI = """ const GTK3_EPI = """
proc mainQuit*(w: Window) = mainQuit() proc mainQuit*(w: Window) = mainQuit()
@ -2142,6 +2235,7 @@ proc main(namespace: string; version: cstring = nil) =
ct = initCountTable[string]() ct = initCountTable[string]()
var delayedSyms: seq[GIBaseInfo] var delayedSyms: seq[GIBaseInfo]
allSyms = initHashSet[string]() allSyms = initHashSet[string]()
arrayCollector = initHashSet[string]()
provInt.clear provInt.clear
interfaceProvider.clear interfaceProvider.clear
var ig: HashSet[string] var ig: HashSet[string]
@ -2193,15 +2287,18 @@ proc main(namespace: string; version: cstring = nil) =
Lib = Lib.replace("libpango-", "libpangocairo-") # GI bug? Lib = Lib.replace("libpango-", "libpangocairo-") # GI bug?
output.writeLine("const Lib = \"$1\"" % Lib) output.writeLine("const Lib = \"$1\"" % Lib)
output.writeLine("{.pragma: libprag, cdecl, dynlib: Lib.}") output.writeLine("{.pragma: libprag, cdecl, dynlib: Lib.}")
output.writeLine("\nPutAllTheArrayTypesHere")
if namespace == "GObject": # declare array types to make it compile -- procs using these will need special care! 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 GCallback* = proc () {.cdecl.}")
output.writeLine("type\n Parameter00Array* = pointer") #output.writeLine("type\n Parameter00Array* = pointer")
output.writeLine("type\n Object00Array* = pointer") output.writeLine("type\n Object00Array* = pointer")
output.writeLine("type\n Value00Array* = pointer") #output.writeLine("type\n Value00Array* = pointer")
output.writeLine("type\n GTypeArray* = pointer") #output.writeLine("type\n GTypeArray* = pointer")
output.writeLine("type\n ParamSpec00Array* = pointer") #output.writeLine("type\n ParamSpec00Array* = pointer")
output.writeLine("type\n TypePlugin00Array* = pointer") #output.writeLine("type\n TypePlugin00Array* = pointer")
output.writeLine("type\n uint32Array* = pointer") #output.writeLine("type\n uint32Array* = pointer")
output.writeLine("type\n VaClosureMarshal* = pointer") output.writeLine("type\n VaClosureMarshal* = pointer")
output.writeLine("\nproc boxedFree*(boxedType: GType; boxed: pointer) {.") output.writeLine("\nproc boxedFree*(boxedType: GType; boxed: pointer) {.")
@ -2216,22 +2313,22 @@ proc main(namespace: string; version: cstring = nil) =
#output.writeLine("type\n GException* = object of Exception") #output.writeLine("type\n GException* = object of Exception")
output.writeLine("type\n GException* = object of CatchableError") output.writeLine("type\n GException* = object of CatchableError")
output.writeLine("type\n OptionEntry00Array* = pointer") #output.writeLine("type\n OptionEntry00Array* = pointer")
output.writeLine("type\n GArray00* = pointer") output.writeLine("type\n GArray00* = pointer")
output.writeLine("type\n int8Array* = pointer") #output.writeLine("type\n int8Array* = pointer")
output.writeLine("type\n uintArray* = pointer") #output.writeLine("type\n uintArray* = pointer")
output.writeLine("type\n gbooleanArray* = pointer") #output.writeLine("type\n gbooleanArray* = pointer")
output.writeLine("type\n cdoubleArray* = pointer") #output.writeLine("type\n cdoubleArray* = pointer")
output.writeLine("type\n int32Array* = pointer") #output.writeLine("type\n int32Array* = pointer")
output.writeLine("type\n PollFD00Array* = pointer") #output.writeLine("type\n PollFD00Array* = pointer")
output.writeLine("type\n Variant00Array* = pointer") #output.writeLine("type\n Variant00Array* = pointer")
output.writeLine("type\n Regex00Array* = pointer") #output.writeLine("type\n Regex00Array* = pointer")
output.writeLine("type\n LogField00Array* = pointer") #output.writeLine("type\n LogField00Array* = pointer")
output.writeLine("type\n VariantType00Array* = pointer") #output.writeLine("type\n VariantType00Array* = pointer")
output.writeLine("type\n DebugKey00Array* = pointer") #output.writeLine("type\n DebugKey00Array* = pointer")
output.writeLine("type\n utf8Array* = pointer") #output.writeLine("type\n utf8Array* = pointer")
output.writeLine("type\n uint8Array* = pointer") #output.writeLine("type\n uint8Array* = pointer")
output.writeLine("type\n ucstringArray* = pointer") #output.writeLine("type\n ucstringArray* = pointer")
output.writeLine("type\n ucstring* = distinct cstring") output.writeLine("type\n ucstring* = distinct cstring")
output.writeLine("type\n gboolean* = distinct cint") output.writeLine("type\n gboolean* = distinct cint")
output.writeLine("const\n GLIB_SIZEOF_VOID_P = sizeof(pointer)") output.writeLine("const\n GLIB_SIZEOF_VOID_P = sizeof(pointer)")
@ -2306,77 +2403,83 @@ proc uint8ArrayZT2seq*(p: pointer): seq[uint8] =
output.writeLine("proc safeStringToCString*(s: cstring): cstring = (if s.len == 0: nil else: s)") output.writeLine("proc safeStringToCString*(s: cstring): cstring = (if s.len == 0: nil else: s)")
output.writeLine(PRO) output.writeLine(PRO)
elif namespace == "Gdk": elif namespace == "Gdk":
output.writeLine("type\n ContentProvider00Array* = pointer") #output.writeLine("type\n ContentProvider00Array* = pointer")
output.writeLine("type\n Atom00Array* = pointer") #output.writeLine("type\n Atom00Array* = pointer")
output.writeLine("type\n KeymapKeyArray* = pointer") #output.writeLine("type\n KeymapKeyArray* = pointer")
output.writeLine("type\n VisualTypeArray* = pointer") # enums! #output.writeLine("type\n VisualTypeArray* = pointer") # enums!
output.writeLine("type\n RGBAArray* = pointer") output.writeLine("type\n RGBAArray* = pointer")
output.writeLine("type\n AxisUseArray* = pointer") output.writeLine("type\n AxisUseArray* = pointer")
output.writeLine("type\n ColorArray* = pointer") output.writeLine("type\n ColorArray* = pointer")
output.writeLine("type\n Point00Array* = pointer") output.writeLine("type\n Point00Array* = pointer")
output.writeLine("type\n TimeCoord00Array* = pointer") #output.writeLine("type\n TimeCoord00Array* = pointer")
elif namespace == "Gtk": elif namespace == "Gtk":
discard
#output.writeLine( #output.writeLine(
# "# https://developer.gnome.org/gtk3/stable/GtkWidget.html#GtkWidget-draw") # "# https://developer.gnome.org/gtk3/stable/GtkWidget.html#GtkWidget-draw")
#output.writeLine( #output.writeLine(
# "# TRUE to stop other handlers from being invoked for the event. FALSE to propagate the event further.") # "# TRUE to stop other handlers from being invoked for the event. FALSE to propagate the event further.")
#output.writeLine("const\n SignalEventStopPropagation* = true") #output.writeLine("const\n SignalEventStopPropagation* = true")
#output.writeLine("const\n SignalEventContinuePropagation* = false") #output.writeLine("const\n SignalEventContinuePropagation* = false")
output.writeLine("type\n TargetEntry00Array* = pointer") #output.writeLine("type\n TargetEntry00Array* = pointer")
output.writeLine("type\n AccelGroupEntry00Array* = pointer") #output.writeLine("type\n AccelGroupEntry00Array* = pointer")
output.writeLine("type\n BindingArg00Array* = pointer") #output.writeLine("type\n BindingArg00Array* = pointer")
output.writeLine("type\n StockItemArray* = pointer") #output.writeLine("type\n StockItemArray* = pointer")
output.writeLine("type\n PageRangeArray* = pointer") #output.writeLine("type\n PageRangeArray* = pointer")
output.writeLine("type\n PadActionEntry00Array* = pointer") #output.writeLine("type\n PadActionEntry00Array* = pointer")
output.writeLine("type\n Expression00Array* = pointer") #output.writeLine("type\n Expression00Array* = pointer")
output.writeLine("type\n Widget00Array* = pointer") #output.writeLine("type\n Widget00Array* = pointer")
output.writeLine("type\n Array* = pointer") #output.writeLine("type\n Array* = pointer")
elif namespace == "Atk": elif namespace == "Atk":
output.writeLine("type\n StateTypeArray* = pointer") # enums! discard
output.writeLine("type\n TextRange00Array* = pointer") #output.writeLine("type\n StateTypeArray* = pointer") # enums!
#output.writeLine("type\n TextRange00Array* = pointer")
elif namespace == "cairo": elif namespace == "cairo":
output.writeLine("\nfrom gobject import boxedFree") output.writeLine("\nfrom gobject import boxedFree")
output.writeLine("from glib import GType") output.writeLine("from glib import GType")
elif namespace == "Pango": elif namespace == "Pango":
output.writeLine("type\n GlyphInfo00Array* = pointer") output.writeLine("type\n GlyphInfo00Array* = pointer")
output.writeLine("type\n LogAttr00Array* = pointer") #output.writeLine("type\n LogAttr00Array* = pointer")
output.writeLine("type\n FontDescription00Array* = pointer") #output.writeLine("type\n FontDescription00Array* = pointer")
output.writeLine("type\n FontFamily00Array* = pointer") #output.writeLine("type\n FontFamily00Array* = pointer")
output.writeLine("type\n FontFace00Array* = pointer") #output.writeLine("type\n FontFace00Array* = pointer")
output.writeLine("type\n ScriptArray* = pointer") # array of enums! #output.writeLine("type\n ScriptArray* = pointer") # array of enums!
elif namespace == "Gio": elif namespace == "Gio":
output.writeLine("type\n ActionEntry00Array* = pointer") discard
output.writeLine("type\n DBusAnnotationInfo00Array* = pointer") #output.writeLine("type\n ActionEntry00Array* = pointer")
output.writeLine("type\n DBusArgInfo00Array* = pointer") #output.writeLine("type\n DBusAnnotationInfo00Array* = pointer")
output.writeLine("type\n DBusMethodInfo00Array* = pointer") #output.writeLine("type\n DBusArgInfo00Array* = pointer")
output.writeLine("type\n DBusSignalInfo00Array* = pointer") #output.writeLine("type\n DBusMethodInfo00Array* = pointer")
output.writeLine("type\n DBusPropertyInfo00Array* = pointer") #output.writeLine("type\n DBusSignalInfo00Array* = pointer")
output.writeLine("type\n DBusInterfaceInfo00Array* = pointer") #output.writeLine("type\n DBusPropertyInfo00Array* = pointer")
output.writeLine("type\n DBusNodeInfo00Array* = pointer") #output.writeLine("type\n DBusInterfaceInfo00Array* = pointer")
output.writeLine("type\n DBusErrorEntry00Array* = pointer") #output.writeLine("type\n DBusNodeInfo00Array* = pointer")
output.writeLine("type\n InputVector00Array* = pointer") #output.writeLine("type\n DBusErrorEntry00Array* = pointer")
output.writeLine("type\n SocketControlMessage00Array* = pointer") #output.writeLine("type\n InputVector00Array* = pointer")
output.writeLine("type\n InputMessage00Array* = pointer") #output.writeLine("type\n SocketControlMessage00Array* = pointer")
output.writeLine("type\n OutputMessage00Array* = pointer") #output.writeLine("type\n InputMessage00Array* = pointer")
output.writeLine("type\n utf8ArrayArray* = pointer") #output.writeLine("type\n OutputMessage00Array* = pointer")
output.writeLine("type\n cstringArrayArray* = pointer") #output.writeLine("type\n utf8ArrayArray* = pointer")
output.writeLine("type\n File00Array* = pointer") #output.writeLine("type\n cstringArrayArray* = pointer")
output.writeLine("type\n Array* = pointer") #output.writeLine("type\n File00Array* = pointer")
output.writeLine("type\n OutputVector00Array* = pointer") #output.writeLine("type\n Array* = pointer")
#output.writeLine("type\n OutputVector00Array* = pointer")
elif namespace == "Graphene": elif namespace == "Graphene":
output.writeLine("type\n Vec3Array* = pointer") discard
output.writeLine("type\n Point3DArray* = pointer") #output.writeLine("type\n Vec3Array* = pointer")
#output.writeLine("type\n Point3DArray* = pointer")
elif namespace == "Gsk": elif namespace == "Gsk":
output.writeLine("type\n Shadow00Array* = pointer") discard
output.writeLine("type\n RenderNode00Array* = pointer") #output.writeLine("type\n Shadow00Array* = pointer")
output.writeLine("type\n ColorStop00Array* = pointer") #output.writeLine("type\n RenderNode00Array* = pointer")
#output.writeLine("type\n ColorStop00Array* = pointer")
elif namespace == "GtkSource": elif namespace == "GtkSource":
output.writeLine("import glib") output.writeLine("import glib")
elif namespace == "Vte": elif namespace == "Vte":
output.writeLine("import glib\n") output.writeLine("import glib\n")
output.writeLine("type\n Regex00Array* = pointer") #output.writeLine("type\n Regex00Array* = pointer")
elif namespace == "Gst": elif namespace == "Gst":
output.writeLine("type\n FormatArray* = pointer") discard
#output.writeLine("type\n FormatArray* = pointer")
if namespace == "GObject": if namespace == "GObject":
output.writeLine("\nimport times") output.writeLine("\nimport times")
output.writeLine("var qt = \"NGIQ\" & $epochTime()") output.writeLine("var qt = \"NGIQ\" & $epochTime()")
@ -2637,6 +2740,9 @@ proc get$1*(builder: Builder; name: string): $1 =
if namespace == "Gio": if namespace == "Gio":
output.write(GIO_EPI) output.write(GIO_EPI)
if namespace == "GObject":
output.write(GObject_EPI)
if namespace == "cairo": if namespace == "cairo":
output.write("include cairoimpl\n") output.write("include cairoimpl\n")
@ -2665,6 +2771,19 @@ proc get$1*(builder: Builder; name: string): $1 =
#output.writeLine("\nproc g_type_get_type*(): GType = g_type_from_name(\"GType\")") #output.writeLine("\nproc g_type_get_type*(): GType = g_type_from_name(\"GType\")")
output.writeLine("\nproc g_variant_get_type*(): GType = g_type_from_name(\"GVariant\")") output.writeLine("\nproc g_variant_get_type*(): GType = g_type_from_name(\"GVariant\")")
var arrayTypes: string = "type\n"
arrayCollector.excl("cstringArray")
arrayCollector.excl("ValueArray")
for el in arrayCollector:
var el = el
el.add("* = pointer\n")
arrayTypes.add(" " & el)
if arrayCollector.len == 0:
arrayTypes = "\n"
output.data = output.data.replace("PutAllTheArrayTypesHere", arrayTypes)
output.setPosition(output.data.len)
if namespace == "Gdk": if namespace == "Gdk":
if ISGTK3: if ISGTK3:
output.write(GDK3_EPI.replace("SomeEvent", "Event")) output.write(GDK3_EPI.replace("SomeEvent", "Event"))
@ -2679,7 +2798,9 @@ proc get$1*(builder: Builder; name: string): $1 =
o.write(output.data) o.write(output.data)
o.close() o.close()
output.close output.close
stdout.write("Remaining delayed methods: ", delayedMethods.len) var hs = fixedModName(moduleNameSpace) & "............................"
hs.setLen(24)
stdout.write(hs, ": Remaining delayed methods: ", delayedMethods.len)
if delayedMethods.len == 0: if delayedMethods.len == 0:
echo " (Fine!)" echo " (Fine!)"
else: else:
@ -2724,6 +2845,7 @@ proc launch() =
main("PangoFT2") main("PangoFT2")
main("fontconfig") main("fontconfig")
main("freetype2") main("freetype2")
main("HarfBuzz")
main("Rsvg") main("Rsvg")
main("xlib") main("xlib")
main("Vte") main("Vte")
@ -2750,6 +2872,7 @@ proc launch() =
main("PangoFT2") main("PangoFT2")
main("fontconfig") main("fontconfig")
main("freetype2") main("freetype2")
main("HarfBuzz")
main("Rsvg") main("Rsvg")
main("xlib") main("xlib")
# main("Vte") # not yet available for GTK4 # main("Vte") # not yet available for GTK4
@ -2773,4 +2896,4 @@ proc launch() =
supmod4.close supmod4.close
launch() launch()
# 2776 lines # 2898 lines qdata