Well, I have a working solution. I can pass a string, an int, and object from 
the stack to the callback and it works. (Removing a button and reinserting does 
not work currently, but that is a different problem.) But I still wonder why I 
have to use the strange name(type(arg)) way to get the type of the callback 
parameter, and getType(arg) in macro does not work. Of course this code always 
makes a deep copy of the callback parameter, that wasted some ram.
    
    
    # plain test for high level gi based GTK3 Nim wrapper
    # https://github.com/StefanSalewski/nim-gi2
    import gtk, glib, gobject
    import macros
    import strutils
    import typetraits
    
    type
      ParObj = object
        x: float
    
    type
      XButton = ref object of Button
        x: int
    
    # TODO: will be moved to library module!
    let Quark = g_quark_from_static_string("NimGIQuark")
    
    # TODO: will be moved to library module!
    proc initWithArgv*() =
      var
        cmdLine{.importc.}: cstringArray
        cmdCount{.importc.}: cint
      gtk.gtk_init(cmdCount, cmdLine)
    
    proc clicked(button: XButton; arg: ParObj) =
      echo arg.x
      echo button.x
    
    proc clicked2(button: Button; arg: string) =
      echo arg
    
    proc clicked3(button: Button; arg: int) =
      echo arg
    
    proc bye(w: Window; arg: string) =
      mainQuit()
      echo arg
    
    var ProcID: int
    
    # TODO: this macro will be moved to library module!
    macro mconnect(widget: Widget; signal: string; p: untyped; arg: typed; rrt: 
string): typed =
      inc(ProcID)
      let wt = getType(widget) # widget type
      #let at = getType(arg) # argument type
      let signalName = ($signal).replace("-", "_") # maybe we should just use 
plain proc names
      let procNameCdecl = newIdentNode("connect_for_signal_cdecl_" & signalName 
& $ProcID)
      let procName = newIdentNode("connect_for_signal_" & signalName & $ProcID)
      let scName = newIdentNode("sc" & signalName)
      let at = newIdentNode($rrt)
      result = quote do:
        proc `procNameCdecl`(button: ptr Object00 , data: pointer) {.cdecl.} =
          var h: pointer = g_object_get_qdata(button, Quark)
          `p`(cast[`wt`](h), cast[`at`](data))
        
        proc `procName`(self:  `wt`;  p: proc (self: `wt`, arg: `at`); a: `at`) 
=
          var ar: ref `at`
          new(ar)
          deepCopy(ar[], a)
          GC_ref(ar)
          `scName`(self, `procNameCdecl`, cast[pointer](ar[]))
        `procName`(`widget`, `p`, `arg`)
    
    template connect(widget: Widget; signal: string; p: untyped; arg: typed) =
      mconnect(widget, signal, p, arg, name(type(arg)))
    
    proc work =
      var window: Window = newWindow(WindowType.topLevel)
      window.setTitle("First Test")
      window.setBorderWidth(10)
      var
        box = newBox(Orientation.vertical, 0)
        button1: XButton
        
        button2 = newButton("Wrapper")
        button3 = newButton("Int button")
        parObj: ParObj
      parObj.x = 3.1415
      
      initButton(button1)
      button1.setLabel("Nim GI")
      button1.x = 99
      
      connect(button1, "clicked", clicked, parObj)
      connect(button3, "clicked", clicked3, 1234567)
      connect(window, "destroy", bye, "Bye")
      
      button2.connect("clicked", (proc(button: Button; arg: string) = echo 
arg), "Bye")
      
      box.add(button1)
      box.add(button2)
      box.add(button3)
      #box.remove(button2) # this does not work currently
      #box.add(button2)
      window.add(box)
      window.showAll
      let p = button1.getParent
      assert(p == box)
    
    proc main() =
      initWithArgv()
      work()
      GC_fullCollect()
      gtk.gtkMain()
    
    main()
    
    

Reply via email to