I just tried my initial idea, and indeed it seems to work not bad.
    
    
    proc gtk_button_new*(): ptr Button00 {.
        importc: "gtk_button_new", libprag.}
    
    proc newButton*(): Button =
      new(result, finalizeGObject)
      result.impl = gtk_button_new()
      GC_ref(result)
      g_object_add_toggle_ref(result.impl, toggleNotify, addr(result[]))
      assert(g_object_get_qdata(result.impl, Quark) == nil)
      g_object_set_qdata(result.impl, Quark, addr(result[]))
    
    proc initButton*[T](result: var T) =
      assert(result is Button)
      new(result, finalizeGObject)
      result.impl = gtk_button_new()
      GC_ref(result)
      g_object_add_toggle_ref(result.impl, toggleNotify, addr(result[]))
      assert(g_object_get_qdata(result.impl, Quark) == nil)
      g_object_set_qdata(result.impl, Quark, addr(result[]))
    

I have supported the automatically generated proc newButton() with a manually 
created initButton(), and indeed the test program below works.
    
    
    # plain test for high level gi based GTK3 Nim wrapper
    # https://github.com/StefanSalewski/nim-gi2
    import gtk, glib, gobject
    import macros
    import strutils
    
    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 clickd(button: XButton; arg: string) =
      echo arg
      echo button.x
    
    proc bye(w: Window; arg: string) =
      mainQuit()
      echo arg
    
    var ProcID: int
    
    # TODO: this macro will be moved to library module!
    macro connect(widget: Widget; signal: string; p: typed; arg: typed): 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)
      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`) 
=
          `scName`(self, `procNameCdecl`, cast[pointer](a))
        `procName`(`widget`, `p`, `arg`)
    
    proc main() =
      initWithArgv()
      var window: Window = newWindow(WindowType.topLevel)
      window.setTitle("First Test")
      window.setBorderWidth(10)
      var
        box = newBox(Orientation.vertical, 0)
        button1: XButton
        
        button2 = newButtonWithLabel("Wrapper")
      
      initButton(button1)
      button1.setLabel("Nim GI")
      button1.x = 99
      
      connect(button1, "clicked", clickd, "Hello")
      connect(window, "destroy", bye, "Bye")
      #button2.newconnect("clicked", (proc(button: Button; arg: string) = echo 
arg), "Bye")
      
      box.add(button1)
      box.add(button2)
      window.add(box)
      window.showAll
      let p = button1.getParent
      assert(p == box)
      gtk.gtkMain()
    
    main()
    
    

The connect makro is type safe, allows to pass arbitrary arguments and works 
with extended objects like XButton from above.

Reply via email to