import gtk3, glib, gobject
type
NWindow = ref object
w: Window
proc finalizeNWindow(w: NWindow) =
g_object_unref(w.w)
proc newNWindow: NWindow =
let w = window_new()
discard g_object_ref_sink(w)
new(result, finalizeNWindow)
result.w = w
return result
converter NWindowtoGTKWindow(w: NWindow): Window =
w.w
converter NWindowtoGTKContainer(w: NWindow): gtk3.Container =
w.w
converter NWindowtoGTKWidget(w: NWindow): gtk3.Widget =
w.w
#converter NWindowtoG_Object(w: NWindow): GObject =
# w.w
proc destroy(widget: Widget, data: gpointer) {.cdecl.} = main_quit()
gtk3.init_with_argv()
#var window = window_new()
var window = newNWindow()
discard g_signal_connect(window.w, "destroy", g_callback(t.destroy), nil)
window.title = "Radio Buttons"
echo(window.title)
echo(window.get_title) # get_ is available also
window.border_width = 10
window.set_border_width(10) # set_ is available also
var
r1 = radio_button_new("Radio_Button 1")
r2: PRadioButton # old deprecated P prefix -- gives warning
r2 = new_with_label_from_widget(r1, "Radio_Button 2")
var
r3 = radio_button_new(r1, "Radio_Button 3")
var
box = box_new(Orientation.VERTICAL, 0)
box.pack_start(r1, GFALSE, GTRUE, 0) # maybe we should add default values
box.pack_start(r2, GFALSE, GTRUE, 0)
box.pack_start(r3, GFALSE, GTRUE, 0)
window.add(box)
window.show_all
gtk3.main()
So for each GTK type, we have to create a related Nim type, a new proc and a set of converters for all the parent classes of the GTK type. So it will result in a few hundred, maybe a few thousand converters -- is that bad? The code can be generated mostly automatically. Maybe we can add a constructor and destructor for objects on the stack. Once I suggested template like converters, that would reduce the total number, only one for each GTK class. But I think that would be more complicated. Without use of converters, we would have to replace most GTK procs with one accepting a Nim object and calling the GTK proc. Is that the better solution?
So it will result in a few hundred, maybe a few thousand converters -- is that bad?
Yes.
Without use of converters, we would have to replace most GTK procs with one accepting a Nim object and calling the GTK proc. Is that the better solution?
Yes, but I don't like it either. I have ideas for a better solution, but it's too early to post them here.
> I have ideas for a better solution, but it's too early to post them here.
Great!
Hi,
you might want to have a look at my wrapper-generator for GTK+/GObject, nim-smartgi. It follows a similar approach to your suggestion, with one wrapper or smart pointer type per GObject class. Note that it is still very experimental and not yet ready, but your post encouraged me to unbury it and put it on GitHub.
Currently, it uses ref types and finalizers to ensure objects are released, too. However, I want to move it to using plain types, and overloaded = and =destroy (assignment operators and destructors). The idea is that these types will have the same in-memory layout as a plain pointer, so you can just use them everywhere without the indirection that ref incurs. But the current scheme works quite well, after all in a GUI app you don't access your GtkButtons in tight loops, and the overhead is probably already lower as in Python+GTK.
The wrappers (will) have a few nifty features:
button.connect("clicket", (bttn: Button)=>echo "moo")
button.connect("clicked", (bttn: Entry)=>echo "woof")
and in the first case it will complain because the signal name is not known, in the second because the type of the callback argument is wrong.
It works with more complex callbacks (currently one extra argument):
proc windowConfigure(win: Gtk3.Widget, ea: Gdk3.TEventConfigure): bool =
echo ea.x, " ", ea.y
return true
window.connect("configure-event", windowConfigure)
And you can pass a custom argument (whose type will also be matched to the passed proc!):
proc buttonClicked(bttn: Button, extra: string) =
echo "Hello ",extra,"!"
button.connect("clicked", buttonClicked, "Jason")
Note that in the callbacks are all regular nim procs, no {.cdecl.} neccessary.
There are a bunch of areas that sill need work, in particular:
And of course it needs a lot more testing.
Feel free to poke around a bit and let me know what you think!
That is interesting.
As you may know I did a plain GTK3 wrapper for 3.15.xx one year ago with c2nim and a few bash and Ruby scripts, with most of the related modules like cairo and pango, ten modules total. But I have not worked on it since then, because nobody really intents to use GTK3 with Nim. (Was some work that time, now with Nim's bitfield support and use of noforward pragma that is much easier, main work is related to the strange macros, which are used in the new app style examples. I converted application 10 to Nim, see https://github.com/StefanSalewski/nim-gtk3/tree/master/test/application10)
I know that for Crystal a very basic experimental GObject-Introspection wrapper is available, but I do not know much about GObject-Introspection yet. I will try to understand your approach when I have some spare time. The GTK3 related wrappers for Ruby are using Introspection also, unfortunately they suffered from strange bugs for a long time. And my feeling is that GObject-Introspection generates some startup delay unfortunately.
[EDIT]
"> Currently, it uses ref types and finalizers to ensure objects are released, too. However, I want to move it to using plain types, and overloaded = and =destroy (assignment operators and destructors). The idea is that these types will have the same in-memory layout as a plain pointer, so you can just use them everywhere without the indirection that ref incurs."
That is interesting and would be great of course. But I had the feeling that Nims garbage collected objects had hidden additional fields, for instance for pointer to type descriptor and ref counter. So these GC objects can not be compatible with instances allocated by GObject? Maybe you have deep insight in GC and compiler internals? Or do you intent to patch GObject's memory allocation so that it allocates a larger block with fields for Nims GC?
For other compiled languages like Go or C++ the amount of glue code for high level GTK wrappers is very large unfortunately -- would be nice if we could avoid that bloat for Nim.
[EDIT2]
Maybe we should try to do it like Vala does? Handling ref count should be not too difficult, but I have no idea how subclassing is handled in Vala yet. How may they increase the amount of memory that is allocated for the GObject based objects?
Araq, when use of hundreds of converters is bad...
May it be possible that the compiler automatically replaces not matching proc parameters when the parameter is an object and has a matching member field like
type
CButton = ptr object
i : int
NimButton = ref object
w: CButton
# wrapped C library function
proc add(b: CButton) =
echo "adding button to ..."
var b: NimButton
# create and init object
add(b.w) # compiles fine of course
add(b) # may compiler expand this to expression above automatically?
That would save much glue code for high level wrappers -- I think that should be not too difficult for the compiler and should not take much time. And of course we could restrict that expansion in some way, maybe mark the proc and/or the object to allow this expansion, or maybe restrict it to special member fields.
And of course we could restrict that expansion in some way, maybe mark the proc and/or the object to allow this expansion, or maybe restrict it to special member fields.
Yeah, my current idea is a .delegate annotation for object fields that does exactly what you describe.