fixes for libnice and editDistance

This commit is contained in:
Stefan Salewski 2020-10-27 07:50:15 +01:00
commit dd51386030
7 changed files with 169 additions and 139 deletions

View file

@ -31,7 +31,12 @@ Array types. In the past we used that names to indicate array parameters, it was
it was ugly using names to indicates data types. So we fixed that. And we have added some better support for it was ugly using names to indicates data types. So we fixed that. And we have added some better support for
GList parameter. GLists are now converted to Nim seqs and vice versa. Not everywhere still, and this conversion GList parameter. GLists are now converted to Nim seqs and vice versa. Not everywhere still, and this conversion
is still untested, as GList parameters are used most of the time in exotic functions only. Another change is that is still untested, as GList parameters are used most of the time in exotic functions only. Another change is that
we have support for libnice by a request of a user from Japan. We added the sdp_example.nim converted from we have support for libnice by a request of a user from Japan now. As he intents to use libnice on Windows 8.1
with only glib and gobject installed, but with no gtk installed, we had to break module gimpl.nim
into two units called gimplgobj.nim and gimplgtk.nim, and we added a module called dummygtk.nim
which can be imported to make the connect() macro available while a real gtk module is not available.
Please let us know if these changes should break something for ordinary gtk users.
To test libnice we added the sdp_example.nim converted from
a C example, it seems to compile and run. And finally with v0.8.3 the examples from the GTK4 book should work. a C example, it seems to compile and run. And finally with v0.8.3 the examples from the GTK4 book should work.
For the GTK3 examples we had to do some minimal fixes, so you may have to do similar fixes for your own code as well. For the GTK3 examples we had to do some minimal fixes, so you may have to do similar fixes for your own code as well.
For gintro/examples/gtk3 this was For gintro/examples/gtk3 this was

View file

@ -9,12 +9,22 @@
# ./sdp-example 0 $(host -4 -t A stun.stunprotocol.org | awk '{ print $4 }') # ./sdp-example 0 $(host -4 -t A stun.stunprotocol.org | awk '{ print $4 }')
# ./sdp-example 1 $(host -4 -t A stun.stunprotocol.org | awk '{ print $4 }') # ./sdp-example 1 $(host -4 -t A stun.stunprotocol.org | awk '{ print $4 }')
import gintro/[gtk, glib, gobject, nice]
import gintro/gio except stdin # https://forum.nim-lang.org/t/3752
when (compiles do: import gintro/gtk):
import gintro/[gtk, glib, gobject, gio, nice]
else:
import gintro/[dummygtk, glib, gobject, gio, nice] # For windows with glib but no gtk
from strutils import `%` from strutils import `%`
from os import paramCount, paramStr from os import paramCount, paramStr
from strutils import parseInt from strutils import parseInt
when defined(windows):
import winlean
else:
discard # import posix
var var
gloop: glib.MainLoop gloop: glib.MainLoop
stunAddr: string stunAddr: string
@ -89,10 +99,13 @@ proc exampleThread(data: pointer): pointer {.cdecl.} =
line: string line: string
sdp: string sdp: string
sdp64: string sdp64: string
#when defined(G_OS_WIN32):
# io_stdin = g_io_channel_win32_new_fd(_fileno(stdin)) # https://gist.github.com/demotomohiro/c9d9ad7e17639c6acb9bd2be7c204f3f
#else: when hostOS == "windows":
ioStdin = unixNew(getFileHandle(stdin)) ioStdin = win32NewFd(system.stdin.getFileHandle)
else:
ioStdin = unixNew(system.stdin.getFileHandle)
discard setFlags(ioStdin, glib.IOFlags.nonBlock) discard setFlags(ioStdin, glib.IOFlags.nonBlock)
# Create the nice agent # Create the nice agent
agent = nice.newAgent(glib.getContext(gloop), nice.CompatibilityRfc5245) agent = nice.newAgent(glib.getContext(gloop), nice.CompatibilityRfc5245)
@ -141,8 +154,7 @@ proc exampleThread(data: pointer): pointer {.cdecl.} =
var s: IOStatus = readLine(ioStdin, line, length, terminatorPos) var s: IOStatus = readLine(ioStdin, line, length, terminatorPos)
if s == IOStatus.normal: if s == IOStatus.normal:
var sdpLen: uint64 var sdpLen: uint64
let sdpxxx = base64Decode(line, sdpLen) #seq[uint8] let sdp = cast[string](base64Decode(line, sdpLen)) #seq[uint8]
sdp = cast[string](sdpxxx)
# Parse remote candidate list and set it on the agent # Parse remote candidate list and set it on the agent
if sdp.len > 0 and parseRemoteSdp(agent, sdp) > 0: if sdp.len > 0 and parseRemoteSdp(agent, sdp) > 0:
break break
@ -183,9 +195,9 @@ proc exampleThread(data: pointer): pointer {.cdecl.} =
return nil return nil
proc main = proc main =
echo paramCount() #echo paramCount()
for i in 0 .. paramCount(): #for i in 0 .. paramCount():
echo paramStr(i) # echo paramStr(i)
let argc = paramCount() + 1 let argc = paramCount() + 1
var argv = newSeq[string](argc) var argv = newSeq[string](argc)
for i in 0 ..< argc: for i in 0 ..< argc:

View file

6
gintro/dummygtk.nim Normal file
View file

@ -0,0 +1,6 @@
import gobject
import macros, strutils
include gisup3
include gimplgobj

View file

@ -1,5 +1,6 @@
#from sequtils import keepItIf #from sequtils import keepItIf
import sequtils import macros, sequtils
from strutils import startsWith, replace
const RecSep = "!" # Record separator for entries in gisup.nim, also defined in gen.nim const RecSep = "!" # Record separator for entries in gisup.nim, also defined in gen.nim
# caution: $$ due to string interpolation # caution: $$ due to string interpolation
@ -359,122 +360,6 @@ $1($4)
""" % [$procName, ats, $procNameCdecl, $arg] """ % [$procName, ats, $procNameCdecl, $arg]
result = parseStmt(r1s & r2s) result = parseStmt(r1s & r2s)
################################################### # 362 lines
### CellDataFunc,
# see https://developer.gnome.org/gtk3/stable/GtkTreeViewColumn.html#gtk-tree-view-column-set-cell-data-func
# the low level GTK interface:
# proc cellDataFunc(column00: ptr TreeViewColumn00; renderer00: ptr CellRenderer00;
# model00: ptr TreeModel00; iter: TreeIter; data: pointer) {.cdecl.}
# unset -- the macro can do this already
proc unsetCellDataFunc*(column: TreeViewColumn; renderer: CellRenderer) =
setCellDataFunc(column, renderer, nil, nil, nil)
# set a function with this parameter list and one more optional argument
# proc cellDataFunc(column: TreeViewColumn; renderer: CellRenderer; model: TreeModel; iter: TreeIter)
# if there is no optional arg, then we make it a pointer with nil value.
# if arg is a ref, then we apply GC_ref() and pass it
# if arg is a ptr, then we pass it. (but we never free that object)
# if arg is a value type, then we replace it with a copy of a ref type to guaranty lifetime
macro setCellDataFunc*(column: TreeViewColumn; renderer: CellRenderer; fn: untyped = nil; arg: typed = nil): untyped =
if fn == nil: # unset
result = parseStmt("setCellDataFunc($1, $2, nil, nil, nil)" % [$column, $renderer])
return
var CdfID {.compileTime, global.}: int # unique id for our generated cell data functions
inc(CdfID)
var ats: string # the type of optional argument as string (arg type string)
var argStr: string # the value of optional argument as string
var atsfix: string # we have to prefix with "ref " if arg is avalue type
if arg == nil: # no optional argument, so fake a nil pointer
argStr = "nil"
ats = "pointer"
else:
argStr = $(arg.toStrLit)
ats = $getTypeInst(arg).toStrLit
if getTypeInst(arg).typeKind != ntyRef and getTypeInst(arg).typeKind != ntyPtr:
atsFix = "ref "
let procName = "celldatafunc_" & $CdfID # our init code
let procNameCdecl = "celldatafunc_cdecl_" & $CdfID # the proc that is called from GTK
var procNameDestroy: string # the proc that GTK calls when we unset the cellDataFunc
# first we generate the destroy proc
var r0s: string
# GTK should unref the optional argument later, so we generate a destroy proc which GTK can call
if arg != nil and getTypeInst(arg).typeKind != ntyPtr:
procNameDestroy = "celldatafunc_destroy" & $CdfID
r0s ="""
proc $1(p: pointer) {.cdecl.} =
# echo "GC_Unref(arg)"
GC_Unref(cast[$2](p))
""" % [$procNameDestroy, atsFix & ats]
else:
procNameDestroy = "nil"
r0s = ""
# now we generate the proc which GTK will call for each cell of the treeview. g_object_get_qdata() is
# the GTK function which retrieves the Nim proxy objects from the plain GTK data objects.
var r1s = """
proc $1(column00: ptr TreeViewColumn00; renderer00: ptr CellRenderer00;
model00: ptr TreeModel00; iter: TreeIter; pdata: pointer) {.cdecl.} =
let column = cast[TreeViewColumn](g_object_get_qdata(column00, Quark))
let renderer = cast[CellRenderer](g_object_get_qdata(renderer00, Quark))
let model = cast[TreeModel](g_object_get_qdata(model00, Quark))
""" % [$procNameCdecl]
if arg == nil:
r1s.add """
$1(column, renderer, model, iter) # call the user provided Nim proc
""" % [$fn]
elif getTypeInst(arg).typeKind == ntyRef or getTypeInst(arg).typeKind == ntyPtr:
r1s.add """
let a = cast[$2](pdata)
$1(column, renderer, model, iter, a) # call the user provided Nim proc
""" % [$fn, ats]
else: # arg was a value type, but we pass a copy of ref type
r1s.add """
let a = cast[ref $2](pdata)[]
$1(column, renderer, model, iter, a) # call the user provided Nim proc
""" % [$fn, ats]
# this is basically only a code block which is called for initialization, mostly
# making a deep copy of optional argument when argumant is not a ref
var r2s: string
if arg == nil:
r2s ="""
proc $1(column: TreeViewColumn; renderer: CellRenderer; pdata: $2) =
setCellDataFunc($3, $4, $5, nil, nil)
$1(column, renderer, $6)
""" % [$procName, ats, $column, $renderer, $procNameCdecl, argStr, $procNameDestroy]
elif getTypeInst(arg).typeKind == ntyPtr:
r2s ="""
proc $1(column: TreeViewColumn; renderer: CellRenderer; pdata: $2) =
setCellDataFunc($3, $4, $5, cast[pointer](pdata), $7)
$1(column, renderer, $6)
""" % [$procName, ats, $column, $renderer, $procNameCdecl, argStr, $procNameDestroy]
elif getTypeInst(arg).typeKind == ntyRef:
r2s ="""
proc $1(column: TreeViewColumn; renderer: CellRenderer; pdata: $2) =
if not pdata.isNil: # or pdata is pointer):
GC_ref(pdata)
setCellDataFunc($3, $4, $5, cast[pointer](pdata), $7)
$1(column, renderer, $6)
""" % [$procName, ats, $column, $renderer, $procNameCdecl, argStr, $procNameDestroy]
else: # arg is value object
r2s ="""
proc $1(column: TreeViewColumn; renderer: CellRenderer; pdata: $2) =
var ar: ref $2
new(ar)
#deepCopy(ar[], pdata)
ar[] = pdata
GC_ref(ar)
setCellDataFunc($3, $4, $5, cast[pointer](ar), $7)
$1(column, renderer, $6)
""" % [$procName, ats, $column, $renderer, $procNameCdecl, argStr, $procNameDestroy]
result = parseStmt(r0s & r1s & r2s)
# 429 lines echo

117
gintro/gimplgtk.nim Normal file
View file

@ -0,0 +1,117 @@
### CellDataFunc,
# see https://developer.gnome.org/gtk3/stable/GtkTreeViewColumn.html#gtk-tree-view-column-set-cell-data-func
# the low level GTK interface:
# proc cellDataFunc(column00: ptr TreeViewColumn00; renderer00: ptr CellRenderer00;
# model00: ptr TreeModel00; iter: TreeIter; data: pointer) {.cdecl.}
# unset -- the macro can do this already
proc unsetCellDataFunc*(column: TreeViewColumn; renderer: CellRenderer) =
setCellDataFunc(column, renderer, nil, nil, nil)
# set a function with this parameter list and one more optional argument
# proc cellDataFunc(column: TreeViewColumn; renderer: CellRenderer; model: TreeModel; iter: TreeIter)
# if there is no optional arg, then we make it a pointer with nil value.
# if arg is a ref, then we apply GC_ref() and pass it
# if arg is a ptr, then we pass it. (but we never free that object)
# if arg is a value type, then we replace it with a copy of a ref type to guaranty lifetime
macro setCellDataFunc*(column: TreeViewColumn; renderer: CellRenderer; fn: untyped = nil; arg: typed = nil): untyped =
if fn == nil: # unset
result = parseStmt("setCellDataFunc($1, $2, nil, nil, nil)" % [$column, $renderer])
return
var CdfID {.compileTime, global.}: int # unique id for our generated cell data functions
inc(CdfID)
var ats: string # the type of optional argument as string (arg type string)
var argStr: string # the value of optional argument as string
var atsfix: string # we have to prefix with "ref " if arg is avalue type
if arg == nil: # no optional argument, so fake a nil pointer
argStr = "nil"
ats = "pointer"
else:
argStr = $(arg.toStrLit)
ats = $getTypeInst(arg).toStrLit
if getTypeInst(arg).typeKind != ntyRef and getTypeInst(arg).typeKind != ntyPtr:
atsFix = "ref "
let procName = "celldatafunc_" & $CdfID # our init code
let procNameCdecl = "celldatafunc_cdecl_" & $CdfID # the proc that is called from GTK
var procNameDestroy: string # the proc that GTK calls when we unset the cellDataFunc
# first we generate the destroy proc
var r0s: string
# GTK should unref the optional argument later, so we generate a destroy proc which GTK can call
if arg != nil and getTypeInst(arg).typeKind != ntyPtr:
procNameDestroy = "celldatafunc_destroy" & $CdfID
r0s ="""
proc $1(p: pointer) {.cdecl.} =
# echo "GC_Unref(arg)"
GC_Unref(cast[$2](p))
""" % [$procNameDestroy, atsFix & ats]
else:
procNameDestroy = "nil"
r0s = ""
# now we generate the proc which GTK will call for each cell of the treeview. g_object_get_qdata() is
# the GTK function which retrieves the Nim proxy objects from the plain GTK data objects.
var r1s = """
proc $1(column00: ptr TreeViewColumn00; renderer00: ptr CellRenderer00;
model00: ptr TreeModel00; iter: TreeIter; pdata: pointer) {.cdecl.} =
let column = cast[TreeViewColumn](g_object_get_qdata(column00, Quark))
let renderer = cast[CellRenderer](g_object_get_qdata(renderer00, Quark))
let model = cast[TreeModel](g_object_get_qdata(model00, Quark))
""" % [$procNameCdecl]
if arg == nil:
r1s.add """
$1(column, renderer, model, iter) # call the user provided Nim proc
""" % [$fn]
elif getTypeInst(arg).typeKind == ntyRef or getTypeInst(arg).typeKind == ntyPtr:
r1s.add """
let a = cast[$2](pdata)
$1(column, renderer, model, iter, a) # call the user provided Nim proc
""" % [$fn, ats]
else: # arg was a value type, but we pass a copy of ref type
r1s.add """
let a = cast[ref $2](pdata)[]
$1(column, renderer, model, iter, a) # call the user provided Nim proc
""" % [$fn, ats]
# this is basically only a code block which is called for initialization, mostly
# making a deep copy of optional argument when argumant is not a ref
var r2s: string
if arg == nil:
r2s ="""
proc $1(column: TreeViewColumn; renderer: CellRenderer; pdata: $2) =
setCellDataFunc($3, $4, $5, nil, nil)
$1(column, renderer, $6)
""" % [$procName, ats, $column, $renderer, $procNameCdecl, argStr, $procNameDestroy]
elif getTypeInst(arg).typeKind == ntyPtr:
r2s ="""
proc $1(column: TreeViewColumn; renderer: CellRenderer; pdata: $2) =
setCellDataFunc($3, $4, $5, cast[pointer](pdata), $7)
$1(column, renderer, $6)
""" % [$procName, ats, $column, $renderer, $procNameCdecl, argStr, $procNameDestroy]
elif getTypeInst(arg).typeKind == ntyRef:
r2s ="""
proc $1(column: TreeViewColumn; renderer: CellRenderer; pdata: $2) =
if not pdata.isNil: # or pdata is pointer):
GC_ref(pdata)
setCellDataFunc($3, $4, $5, cast[pointer](pdata), $7)
$1(column, renderer, $6)
""" % [$procName, ats, $column, $renderer, $procNameCdecl, argStr, $procNameDestroy]
else: # arg is value object
r2s ="""
proc $1(column: TreeViewColumn; renderer: CellRenderer; pdata: $2) =
var ar: ref $2
new(ar)
#deepCopy(ar[], pdata)
ar[] = pdata
GC_ref(ar)
setCellDataFunc($3, $4, $5, cast[pointer](ar), $7)
$1(column, renderer, $6)
""" % [$procName, ats, $column, $renderer, $procNameCdecl, argStr, $procNameDestroy]
result = parseStmt(r0s & r1s & r2s)
# 117 lines

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.8.3 2020-OCT-21 # v 0.8.3 2020-OCT-26
# (c) S. Salewski 2018 # (c) S. Salewski 2018
# usefull for finding death code: # usefull for finding death code:
@ -2678,6 +2678,8 @@ proc seq2GList*[T](s: seq[T]): ptr glib.List =
discard # make it compile for these cases, of course will not work discard # make it compile for these cases, of course will not work
return l return l
#include gimplgobj
""" """
# for v0.8.2 we create this manually, as gst_structure_from_string() is a constructor # for v0.8.2 we create this manually, as gst_structure_from_string() is a constructor
@ -2711,11 +2713,12 @@ proc attachRecv*(self: Agent; streamID: int; componentID: int; ctx: MainContext;
const GLib_EPI = """ const GLib_EPI = """
proc g_thread_new(name: cstring; fn: ThreadFunc; data:pointer): ptr Thread00 {.importc, libprag.} when not defined(g_thread_new):
proc g_thread_new(name: cstring; fn: ThreadFunc; data:pointer): ptr Thread00 {.importc, libprag.}
proc newThread*(name: string; fn: ThreadFunc; data:pointer): Thread = proc newThread*(name: string; fn: ThreadFunc; data:pointer): Thread =
fnew(result, finalizerunref) fnew(result, finalizerunref)
result.impl = g_thread_new(name, fn, data) result.impl = g_thread_new(name, fn, data)
""" """
@ -3244,10 +3247,12 @@ proc init* =
output.write(GTK_EPI % fixedModName("gtk")) output.write(GTK_EPI % fixedModName("gtk"))
if ISGTK3: if ISGTK3:
output.write("include gisup3\n") output.write("include gisup3\n")
output.write("include gimpl\n") output.write("include gimplgobj\n")
output.write("include gimplgtk\n")
else: else:
output.write("include gisup4\n") output.write("include gisup4\n")
output.write("include gimpl\n") output.write("include gimplgobj\n")
output.write("include gimplgtk\n")
buildableList.add("MenuModel") buildableList.add("MenuModel")
for i in buildableList: for i in buildableList:
var prefix = "gtk" var prefix = "gtk"
@ -3450,7 +3455,7 @@ launch()
# if not xcallerAlloc.contains(el): # if not xcallerAlloc.contains(el):
# echo el # echo el
# 3453 lines # 3453 lines include
# troubles: gTypeFundamental(gRegisteredTypeInfoGetGType(info)) == G_TYPE_BOXED: # troubles: gTypeFundamental(gRegisteredTypeInfoGetGType(info)) == G_TYPE_BOXED:
#[ #[