/nim-smartgi

Generates smart wrappers for GLib modules using GObject-Introspection.

Primary LanguageNim

nim-smartgi

Generates smart wrappers for GLib modules using GObject-Introspection.

⚠️ This is very much work in progress, and not yet ready for use. However, contributions are very welcome.

Features of the wrappers:

  • Using smart pointers
  • Type safe signals
  • Information generated by GObject-Introspection, not from the C headers
  • Syntactic sugar, for example static methods: Instead of gdk_display_get_default, you can use Display.getDefault
  • Idiomatic "new" methods: newLabel instead of labelNew for gtk_label_new

Todo / planned

  • Handle GError, convert to exceptions
  • Make it easier to inherit from types and interfaces (e.g. important for CellRenderers, TreeModels)

Usage

Make sure nim and the Gtk+-3 libraries are on the search paths. Then call it like smartgi GObject-2.0 to generate bindings for GObject version 2.0. To quickly generate all bindings for the Gtk+/GLib suite, call rebuild_all.cmd or rebuild_all.sh.

On Windows, it is recommended to us the GObject all-in-one installer from http://sourceforge.net/projects/pygobjectwin32/ (which is actually for Python, but the DLLs work fine with Nim).

Smart pointers

Smart pointers are wrappers for objects that automatically free the object when it is no longer used. There are two ways to implement smart pointers, one is ref based, and one is based on RAII and reference counting. The current smart pointers are based on ref:

type
  GSmartPtr*[T] = object
    pointer*: ptr T

  TObject* = object of TRoot
  Object* = ref GSmartPtr[TObject]

The smart pointer object GSmartPtr[T] is essentially just a pointer to the object. The object struct uses the naming convention TObject. The C API uses pointers to these objects (ptr TObject), but in the Nim interface we use the wrapped objects Object everywhere.

Wrapped objects are not castable to unwrapped objects, as wrapped objects contain another level of indirection (via ref). However, it is possible to use implicit and explicit conversion to get a dumb pointer out of a wrapped object.

The other way to implement smart objects would be to use the structs-containing-pointers directly, and to put copy constructors and destructors on these structs (sorry for not using the correct Nim terminology). In this case, you could cast these smart pointers directly to dumb pointers, as there would be no extra level of indirection.

Type safe signals

You can use Gtk3.Object.connect to connect callbacks to signals:

let button = buttonNew()
button.setLabel(u"Hello")

proc buttonClicked(bttn: Button) =
  echo "Hello World!"
button.connect("clicked", buttonClicked)

Using some template magic, the callback is checked for the correct argument types. You can pass additional parameters:

proc buttonClicked(bttn: Button, name: string) =
  echo "Hello ", name, "!"
button.connect("clicked", buttonClicked, "Nim")
# this will not compile:
# button.connect("clicked", buttonClicked, 10)

(Todo: add some details about how this is implemented.)