lets see how it looks
This commit is contained in:
parent
02abf4f70a
commit
b6c508015f
1 changed files with 65 additions and 63 deletions
128
README.adoc
128
README.adoc
|
|
@ -1,6 +1,6 @@
|
|||
= High level GTK3 bindings for the Nim programming language
|
||||
(c) Stefan Salewski
|
||||
Version 0.1 2017
|
||||
//Version 0.1 2017
|
||||
:experimental:
|
||||
:imagesdir: http://ssalewski.de/tmp
|
||||
:source-highlighter: pygments
|
||||
|
|
@ -10,8 +10,10 @@ Version 0.1 2017
|
|||
:GIR: GObject-Introspection
|
||||
:MAC: MacOSX
|
||||
|
||||
(c) Stefan Salewski +
|
||||
2017
|
||||
//(c) Stefan Salewski +
|
||||
//2017
|
||||
|
||||
TIP: A more fancy copy of this document with dark source code background is available at http://ssalewski.de/gintroreadme.html[GIntro README]
|
||||
|
||||
NOTE: This work is partly based on earlier works of J. Mansour and has been supported by A. Rumpf and other _Nim_ and _GTK/Gnome_ developers.
|
||||
The `combinatorics` module was kindly provided by R. Behrends.
|
||||
|
|
@ -37,33 +39,33 @@ are Windows and {MAC} and you desire a real native look and feel there, then you
|
|||
Also, when you only need a minimal restricted GUI which is very easy to install on Windows and {MAC}, then you may find better suited packages
|
||||
in the Nim package repository. _Android OS_ is currently not supported by GTK at all.
|
||||
|
||||
While low level _Nim_ bindings for _GTK3_ are already available since a few years, this one is an attempt to
|
||||
While low level Nim bindings for GTK3 are already available since a few years, this one is an attempt to
|
||||
provide real high level bindings with full type safety, full _Garbage Collector_ (_GC_) support and an idiomatic
|
||||
_application interface_ (_API_).
|
||||
_Application Programming Interface_ (_API_)
|
||||
|
||||
The low level bindings available at https://github.com/ngtk3 where generated with the _Nim_ tool `c2nim` directly from the _C_ header files, are already tested
|
||||
The low level bindings available at https://github.com/ngtk3 where generated with the Nim tool `c2nim` directly from the _C_ header files, are already tested
|
||||
with some applications (https://github.com/ngtk3/NEd[NEd Nim Editor], https://github.com/StefanSalewski/nim-chess3[Chess Game])
|
||||
and generally work fine. Indeed missing _Garbage Collector_ support is generally not really a problem, as widgets are generally
|
||||
put into containers and were automatically deleted together with its parents due to _GTK_'s reference counting.
|
||||
and generally work fine. Indeed missing Garbage Collector support is generally not really a problem, as widgets are generally
|
||||
put into containers and were automatically deleted together with its parents due to GTK's reference counting.
|
||||
|
||||
Still there can be some demand for really high level bindings -- so this repository tries to provide them.
|
||||
|
||||
High level _GTK3_ bindings, as available for many other programming languages like _Python_, _Ruby_ or _D_ already,
|
||||
High level GTK3 bindings, as available for many other programming languages like _Python_, _Ruby_ or _D_ already,
|
||||
would have these advantages:
|
||||
|
||||
* full _Garbage Collector_ support -- you should never have to free resources manually
|
||||
* Widgets are _Nim_ objects, so inheritance and sub-classing can be used
|
||||
* full Garbage Collector support -- you should never have to free resources manually
|
||||
* Widgets are Nim objects, so inheritance and sub-classing can be used
|
||||
* full type safety -- no needs for casts or other unsafe and dangerous operations
|
||||
|
||||
These high level bindings are based on _{GIR}_, an _XML_ based database like interface description. Compared to the _C_ header
|
||||
files this description gives us more and deeper information about data types and function calls, for example ownership transfer of objects and
|
||||
in or out direction of procedure variables, which makes writing the glue code much easier.
|
||||
And it should work with no or minimal
|
||||
modifications also for the upcoming _GTK4_.
|
||||
modifications also for the upcoming GTK4.
|
||||
|
||||
Unfortunately there are also some drawbacks:
|
||||
|
||||
* The _Application Programmer Interface_ (API) will be different from what is known from _C API_, so using _C_ examples or _C_ tutorials is not really straight forward
|
||||
* The Application Programming Interface (API) will be different from what is known from _C_ API, so using _C_ examples or _C_ tutorials is not really straight forward
|
||||
* The high level source code will differ from available _C_ examples, so there would be a big demand for tutorials
|
||||
* We need a lot of glue code, which has much room for bugs. So much testing is necessary.
|
||||
* There is some overhead due to indirect calls, leading to some code size increase and minimal
|
||||
|
|
@ -74,19 +76,19 @@ nim prefix.
|
|||
|
||||
== Current state of these bindings
|
||||
|
||||
We are still in an early stage, but it is already more than a proof of concept. _GTK_ and related libraries have many thousand of
|
||||
We are still in an early stage, but it is already more than a proof of concept. GTK and related libraries have many thousand of
|
||||
callable functions and nearly as many data types. Testing all that is nearly impossible for a small team with limited resources.
|
||||
The initial approach was to generate low level
|
||||
bindings, which looked similar to the ones generated by the `c2nim` tool from the _C_ headers. After that was done, we have associated all
|
||||
the _C_ structs and _GObject_ data types with _Nim_ proxy objects. A well defined relation between these proxy object and the low level _C_ data types
|
||||
the _C_ structs and _GObject_ data types with Nim proxy objects. A well defined relation between these proxy object and the low level _C_ data types
|
||||
should ensure fully automatic garbage collection. This is supported by smart type conversion, for example _C_ strings returned by `glib` library
|
||||
are assigned to newly created _Nim_ strings, while the memory of the _C_ strings is automatically freed. For most cases this seems to work. But there
|
||||
are assigned to newly created Nim strings, while the memory of the _C_ strings is automatically freed. For most cases this seems to work. But there
|
||||
exists a few more complicated cases, for example functions may return whole arrays of _C_ strings or other non elementary data types,
|
||||
or function arguments or results may be so called _glists_,
|
||||
list structures of `glib` library. These cases can not be processed automatically but needs carefully manual investigations. And there may be still functions and data
|
||||
types missing: _{GIR}_ query gives us many thousand lines of _Nim_ interface code, and it is not really obvious if and what is missing.
|
||||
types missing: {GIR} query gives us many thousand lines of Nim interface code, and it is not really obvious if and what is missing.
|
||||
Some functions and data types are missing for sure -- at least some low level ones, which are considered unneeded for high level bindings by _{GIR}_.
|
||||
But maybe more is missing, we have to investigate that. Until now these bindings have been tested only for 64 bit _Linux_ systems with _GTK 3.22_.
|
||||
But maybe more is missing, we have to investigate that. Until now these bindings have been tested only for 64 bit Linux systems with GTK 3.22.
|
||||
|
||||
These basic libraries are already partly tested:
|
||||
|
||||
|
|
@ -103,16 +105,16 @@ These basic libraries are already partly tested:
|
|||
* Gdk
|
||||
* Gtk
|
||||
|
||||
In best case it should be possible to add more _GObject_ based libraries to this list without larger modifications of the generator source code.
|
||||
Unfortunately the _cairo_ bindings provided by _{GIR}_ are only a minimal stub -- later we will have to extend it manually.
|
||||
In best case it should be possible to add more GObject based libraries to this list without larger modifications of the generator source code.
|
||||
Unfortunately the bindings for the _cairo_ drawing library provided by {GIR} are only a minimal stub -- later we will have to extend it manually.
|
||||
|
||||
== How to try it out
|
||||
|
||||
Of course you will need a working _Nim_ installation with a recent compiler version and you have to ensure that _GTK_ and related libraries are installed on your system. For some _Linux_
|
||||
distributions which provide mainly pre-compiled software you may have to also install some _GTK_ related developer files.
|
||||
Of course you will need a working Nim installation with a recent compiler version and you have to ensure that GTK and related libraries are installed on your system. For some Linux
|
||||
distributions which provide mainly pre-compiled software you may have to also install some GTK related developer files.
|
||||
|
||||
This package now supports the _nimble package manager_, so ideally a plain `nimble install gintro` should do. But as this package does not
|
||||
only provide some plain text files, but uses _{GIR}_ database query on your local computer to generate
|
||||
This package now supports the _Nimble Package Manager_, so ideally a plain `nimble install gintro` should do. But as this package does not
|
||||
only provide some plain text files, but uses {GIR} database query on your local computer to generate
|
||||
binding files exactly matching your system, that does not work currently. We have to download the files, compile and execute
|
||||
the `gen.nim` generator program and finally to install the generated bindings modules on your computer as a _nimble package_.
|
||||
|
||||
|
|
@ -128,12 +130,12 @@ nimble install
|
|||
|
||||
NOTE: Nimble prepare should run for about 20 seconds, it compiles and executes the generator program `gen.nim`.
|
||||
Unfortunately we can not guarantee that the generator command will be able to really build all the
|
||||
desired modules. The built process highly depends on your _OS_ and installed _GTK_ version. For 64 bit _Linux_ systems
|
||||
with _GTK 3.22_ and all required dependencies installed it should work. For never _GTK_ versions it may fail, when that _GTK_
|
||||
desired modules. The built process highly depends on your OS and installed GTK version. For 64 bit Linux systems
|
||||
with GTK 3.22 and all required dependencies installed it should work. For never GTK versions it may fail, when that GTK
|
||||
release introduces for example new unknown data types like array containers. In that case manual fixes may be necessary.
|
||||
The _{GIR}_ based built process generates bindings customized to the _OS_ where the generator is executed,
|
||||
so for older _GTK_ releases or a 32 bit system different files are created. Later we may also provide pre-generated
|
||||
files for various _OS_ and _GTK_ versions, but building locally is preferred when possible.
|
||||
The {GIR} based built process generates bindings customized to the OS where the generator is executed,
|
||||
so for older GTK releases or a 32 bit system different files are created. Later we may also provide pre-generated
|
||||
files for various OS and GTK versions, but building locally is preferred when possible.
|
||||
|
||||
Now you can built `app0.nim` and launch it:
|
||||
|
||||
|
|
@ -145,11 +147,11 @@ nim c app0.nim
|
|||
|
||||
== A few basic examples
|
||||
|
||||
_GTK3_ programs can use still the old _GTK2_ design, where you first initialize the _GTK_ library, create your widgets and finally enter the _GTK_ main loop.
|
||||
This style is still used in many tutorials as in http://zetcode.com/gui/gtk2/[Zetcode tutorial] or in the _GTK_ book of _A. Krause_.
|
||||
Or you can use the new _GTK3 App style_, this is generally recommended by newer original _GTK_ documentation.
|
||||
Unfortunately the _GTK3_ original documentation is mostly restricted to the _GTK3 API_ documentation, which is generally very good, but makes
|
||||
it not really easy for beginners to start with _GTK_. _API_ docs and some basic introduction is available here:
|
||||
GTK3 programs can use still the old GTK2 design, where you first initialize the GTK library, create your widgets and finally enter the GTK main loop.
|
||||
This style is still used in many tutorials as in http://zetcode.com/gui/gtk2/[Zetcode tutorial] or in the GTK book of A. Krause.
|
||||
Or you can use the new _GTK3 App style_, this is generally recommended by newer original GTK documentation.
|
||||
Unfortunately the GTK3 original documentation is mostly restricted to the GTK3 API documentation, which is generally very good, but makes
|
||||
it not really easy for beginners to start with GTK. API docs and some basic introduction is available here:
|
||||
|
||||
* https://www.gnome.org/
|
||||
* https://www.gtk.org/
|
||||
|
|
@ -158,9 +160,9 @@ it not really easy for beginners to start with _GTK_. _API_ docs and some basic
|
|||
* https://developer.gnome.org/gtk3/stable/ch01s04.html#id-1.2.3.12.5
|
||||
* https://developer.gnome.org/gnome-devel-demos/stable/c.html.en
|
||||
|
||||
TIP: If you should decide to continue developing software with _GTK_, then you may consider installing the so called
|
||||
`devhelp` tool. It gives you easy and fast access to the _GTK API_ docs. For example, if you want to use a _Button Widget_ in your
|
||||
_GUI_ and wants to learn more about related functions and signals, you just enter _Button_ in that tool and are guided to
|
||||
TIP: If you should decide to continue developing software with GTK, then you may consider installing the so called
|
||||
`devhelp` tool. It gives you easy and fast access to the GTK API docs. For example, if you want to use a _Button Widget_ in your
|
||||
GUI and wants to learn more about related functions and signals, you just enter _Button_ in that tool and are guided to
|
||||
all the relevant information.
|
||||
|
||||
We start with a minimal traditional old style example, which should be familiar to most of us:
|
||||
|
|
@ -187,12 +189,12 @@ proc main =
|
|||
main()
|
||||
----
|
||||
|
||||
This is the traditional layout of _GTK2_ programs. When using this style then it is important to initialize the _GTK_ library by calling `gtk.init()`
|
||||
at the very beginning. Then we create the desired widgets, connect signals, show all widgets and finally enter the _GTK_ main loop
|
||||
This is the traditional layout of GTK2 programs. When using this style then it is important to initialize the GTK library by calling `gtk.init()`
|
||||
at the very beginning. Then we create the desired widgets, connect signals, show all widgets and finally enter the GTK main loop
|
||||
by calling `gtk.main`. About connecting signals we will learn more soon, for now it is only important that we have to connect to
|
||||
the destroy signal here to enable the user to terminate program execution by clicking the window close button.
|
||||
|
||||
Now a really minimal but complete _App style_ example, which displays an empty window.
|
||||
Now a really minimal but complete App style example, which displays an empty window.
|
||||
|
||||
NOTE: The source text of all these examples is contained in the examples directory. Unfortunately _github_
|
||||
seems to not allow to include that sources directly into this document, so there may be minimal
|
||||
|
|
@ -252,11 +254,11 @@ window.defaultSize = (width: 200, height: 200) # <6>
|
|||
<5> tupel assignment
|
||||
<6> tupel assignment with named members
|
||||
|
||||
Well, that empty window is really not very interesting. The _GTK_ and _Gnome_ team provides some _GTK_ examples
|
||||
Well, that empty window is really not very interesting. The GTK and Gnome team provides some GTK examples
|
||||
at https://developer.gnome.org/gnome-devel-demos/.
|
||||
The https://developer.gnome.org/gnome-devel-demos/3.22/c.html.en[C demos] seems to be most actual and complete,
|
||||
and are easy to port to _Nim_. So we start with these,
|
||||
but if you are familiar with the other listed languages, then you can try to port them to _Nim_ as well.
|
||||
and are easy to port to Nim. So we start with these,
|
||||
but if you are familiar with the other listed languages, then you can try to port them to Nim as well.
|
||||
Let us start with https://developer.gnome.org/gnome-devel-demos/3.22/button.c.html.en as it is
|
||||
still short and easy to understand, but shows already some interesting topics.
|
||||
|
||||
|
|
@ -328,13 +330,13 @@ main (int argc, char **argv)
|
|||
|
||||
----
|
||||
|
||||
Converting it to _Nim_ is straight forward with some basic _C_ and _Nim_ knowledge, and _Nim_ does not force us
|
||||
Converting it to Nim is straight forward with some basic _C_ and Nim knowledge, and Nim does not force us
|
||||
to convert its shape into all the classes known from pure _Object Orientated_ (_OO_) languages. We can either use the
|
||||
_Nim_ tool `c2nim` to help us with the conversion, or do it manually. Indeed `c2nim` can be very helpful by
|
||||
converting _C_ sources to _Nim_. Most of the time it works well. Personally I generally pre-process _C_ files, for example
|
||||
Nim tool `c2nim` to help us with the conversion, or do it manually. Indeed `c2nim` can be very helpful by
|
||||
converting _C_ sources to Nim. Most of the time it works well. Personally I generally pre-process _C_ files, for example
|
||||
by removing too strange `macros` and `defines, or by replacing strange constructs, like _C_ `for loops`, to simpler
|
||||
ones like `while loops`. Then I apply `c2nim` to the _C_ file and finally manually compare the result line by line and
|
||||
fine tune the _Nim_ code. But for this short source text we may do all that manually and finally get something like
|
||||
fine tune the Nim code. But for this short source text we may do all that manually and finally get something like
|
||||
this:
|
||||
|
||||
[[button.nim]]
|
||||
|
|
@ -366,15 +368,15 @@ main()
|
|||
----
|
||||
|
||||
Again we have the basic shape already known from <<app0.nim>> example: `Main proc` creates the application, connect
|
||||
to the activate signal and finally runs the application. When _GTK_ launches the application and emits the `activate` signal, then
|
||||
to the activate signal and finally runs the application. When GTK launches the application and emits the `activate` signal, then
|
||||
our activate proc is called, which creates a main window containing a button widget. That button is again connected with a
|
||||
signal, in this case named `clicked`. That signal is emitted by _GTK_ whenever that button is clicked with the mouse and results
|
||||
signal, in this case named `clicked`. That signal is emitted by GTK whenever that button is clicked with the mouse and results
|
||||
in a call of our provided `buttonClicked()` proc. The procs connected to signals are called _callbacks_ and generally got the widget
|
||||
on which the signal was emitted as first parameter. They can also get a second optional parameter of arbitrary type -- we will
|
||||
see that in a later example. This callback here gets only the button itself as parameter, and it's task is to reverse the
|
||||
text displayed by the button. Not very interesting basically, but we are indeed using the _glib_ function `utf8Strreverse()`
|
||||
for this task. While that function internally works with `cstrings`, and in _C_ we have to free the memory of the returned `cstring`,
|
||||
in our _Nim_ example that is done automatically by _Nim_'s _Garbage Collector_. When you compare our example carefully with the _C_ code,
|
||||
in our Nim example that is done automatically by Nim's Garbage Collector. When you compare our example carefully with the _C_ code,
|
||||
then you may notice a difference. The _C_ code passes the window containing the button as an additional parameter to the
|
||||
callback function, but that parameter is not really used. We simple ignore it here, as it is not used at all.
|
||||
//and I assume that passing a widget in this way in our nim code
|
||||
|
|
@ -382,12 +384,12 @@ callback function, but that parameter is not really used. We simple ignore it he
|
|||
//working soon...
|
||||
In one of the following examples you will learn how passing (nearly) arbitrary parameters in a type safe way is done.
|
||||
Another difference is, that the _C_ code returns an `integer` status value returned by `g_application_run()` to the _OS_. We
|
||||
could do the same by using the `quit() proc` of _Nim_'s _OS_ module, but as that would give us no additional benefit, we simply ignore it.
|
||||
could do the same by using the `quit() proc` of Nim's _OS_ module, but as that would give us no additional benefit, we simply ignore it.
|
||||
|
||||
TIP: The command `nim c sourcetext.nim` generates an executable which contains code for runtime checks and debugging,
|
||||
which increases executable size and decreases performance.
|
||||
After you have tested your software carefully, you may give the additional parameter `-d:release` to avoid this. For the `gcc` backend
|
||||
you may additional enable _link time optimization_ (_LTO_), which reduces executable size further. To enable _LTO_ you may put
|
||||
you may additional enable _Link Time Optimization_ (_LTO_), which reduces executable size further. To enable LTO you may put
|
||||
a `nim.cfg` file in your sources directory with content like
|
||||
|
||||
----
|
||||
|
|
@ -396,14 +398,14 @@ nimcache:"/tmp/$projectdir"
|
|||
gcc.options.speed = "-march=native -O3 -flto -fstrict-aliasing"
|
||||
----
|
||||
|
||||
With that optimization, your executable sizes should be in the range of about 50 _kB_ only!
|
||||
With that optimization, your executable sizes should be in the range of about 50 kB only!
|
||||
|
||||
=== Optional, type safe parameters for callbacks
|
||||
|
||||
The next example shows, how we can pass (nearly) arbitrary parameters to our connect procs.
|
||||
We pass a string, an object from the stack, a reference to an object allocated on the heap
|
||||
and finally a widget (in this case the application window itself, you may also try passing
|
||||
another button). As the main window itself is a so called _GTK_ `bin` and can contain only one
|
||||
another button). As the main window itself is a so called GTK `bin` and can contain only one
|
||||
single child widget, we create a container widget, a vertical box in this case, fill that box with
|
||||
some buttons, and add that box to the window.
|
||||
|
||||
|
|
@ -487,7 +489,7 @@ proc b1Callback(button: Button; str: int)
|
|||
It may be not always really obvious what the compiler wants to tell us, but at least we
|
||||
are told that it got a string and expected an int.
|
||||
|
||||
Currently the connect function is realized by a _Nim_ type safe `macro`. Connect accepts two or three
|
||||
Currently the connect function is realized by a Nim type safe `macro`. Connect accepts two or three
|
||||
arguments -- the widget, the signal name and the optional argument. When the optional argument
|
||||
is a ref (reference to objects on the heap) then it is passed as a reference, otherwise a deep copy
|
||||
of the argument is passed. For the above code this means, that `r` and the `window` variables are passed
|
||||
|
|
@ -495,22 +497,22 @@ as references, while the string and the stack object are deep copied. Currently
|
|||
to release the memory of passed arguments again. This should be no real problem, as in most
|
||||
cases no arguments are passed at all, and when arguments are passed, then they are general
|
||||
small in size like plain numbers or strings, or maybe references to widgets which could not be freed
|
||||
at all, as they are part of the _GUI_. Later we may add more variants of that connect macro.
|
||||
at all, as they are part of the GUI. Later we may add more variants of that connect macro.
|
||||
|
||||
NOTE: Navigation can be hard for beginners. You may have basic knowledge of _GTK_ and want
|
||||
to build a _GUI_ for your application. But how to find what you need. Well, we offer no separate
|
||||
automatically generated _API_ documentation currently, as that is not really helpful. In most cases
|
||||
it is easy to just guess _Nim_ symbol names, proc parameters and all that. Using a smart editor
|
||||
NOTE: Navigation can be hard for beginners. You may have basic knowledge of GTK and want
|
||||
to build a GUI for your application. But how to find what you need. Well, we offer no separate
|
||||
automatically generated API documentation currently, as that is not really helpful. In most cases
|
||||
it is easy to just guess Nim symbol names, proc parameters and all that. Using a smart editor
|
||||
with good `nimsuggest` support further supports navigation -- for example `NEd` shows us
|
||||
all the needed proc parameters when we move the cursor on a proc name, or we press kbd:[Ctrl+W] and jump
|
||||
to the definition of that symbol. For unknown stuff the original _C_ function name is often a good starting point.
|
||||
Assume you don't know much about _GTK_'s buttons, but you know that you want to have a button in
|
||||
your _GUI_ application. _GTK_ generally offers generator functions containing the string `new` in their name.
|
||||
Assume you don't know much about GTK's buttons, but you know that you want to have a button in
|
||||
your GUI application. GTK generally offers generator functions containing the string `new` in their name.
|
||||
So it is easy to guess that there exists a _C_ function named `gtk_button_new`. That name is also
|
||||
contained in the bindings files, in this case in `gtk.nim`. So we open that file in a text editor and search for
|
||||
that term. So it is really easy to find first starting points for related procs and data types. Most data types
|
||||
are located near by their related functions, so you should be able to find all relevant information fast.
|
||||
Remember the _GTK_ `devhelp` tool, and use also `grep` or the `nimgrep` variant.
|
||||
Remember the GTK `devhelp` tool, and use also `grep` or the `nimgrep` variant.
|
||||
|
||||
NOTE: Related work: https://github.com/jdmansour/nim-smartgi
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue