Cross-Platform GTK+ Applications: A Newcomers Perspective
In this article John D. Ramsdell describes cross-platform GTK+ application development from a newcomer’s perspective.
In an effort to sharpen my programming skills, I wrote a game using a GUI framework with which I was not previously familiar and ported it to several platforms. The framework selected was The GIMP Toolkit, and the application was a puzzle solving game called GTK Sudoku. In this article, I will describe the path that I took to make use of this fine toolkit.
GUI Framework Criterion
I used four criteria for selecting a GUI framework: (1) The framework had to support cross-platform development. (2) The framework had to be one that I had never used, otherwise I feared that I wouldn’t learn as much. This eliminated FLTK and wxWidgets. (3) For my tastes, C is preferred over C++. (4) I wanted GTK Sudoku to be scalable in the sense that the size of the default font, not the resolution of the display, determines the size of each window and widget. The Cairo vector graphics library was of great help to meet this criterion.
A Sudoku logic puzzle is solved by filling each cell in a board so that every row, column, and 3×3 square contains the digits one through nine. GTK Sudoku eliminates much of the drudgery of solving a puzzle and provides educational tips should the path to the solution be obscure. It is different from most other programs in this category because users specify the rule that justifies each change to the Sudoku board. The program will fail to apply a rule if its preconditions are not met, thus detecting mistakes early.
Lua, GTK+, Import/Export…Oh my!
Before I list the lessons learned from this project, let me set the context. GTK Sudoku was constructed by wrapping a GUI around a formerly text-based application written as a Lua script. Lua is a lightweight and easily embeddable scripting language that is popular with game developers. The Lua interpreter is also available as a stand-alone program, and users can interact with scripts using a read-eval-print loop. I’ve been using and tinkering with my Lua Sudoku script for over a year, but there aren’t too many other people who are willing to type Lua function calls into a command-line interpreter for each game interaction. The addition of a GUI was required if I wanted to share my spin on this popular game.
Embedding the Lua script was quick and easy. It was naturally encapsulated in a C module that exports four functions and imports three. The major change to the Lua script was the addition of a help system, which was unnecessary when I was the only user.
The only tricky section of the GUI was the part that displays the board. A Sudoku board is a 9×9 array of cells grouped into 3×3 squares. The preferred way of presenting a board is to draw a line on each edge of each cell and then draw the boundaries of the 3×3 squares with thicker lines to distinguish them from the other cell boundaries.
The board is implemented as a widget that extends a GtkTable, and provides a 9×9 table of cells. Each cell is a widget that extends a GtkDrawingArea. The board widget ensures that there is no space between the cell widgets and that each cell has the same size. Cairo is used to make each cell dynamically resizable and to draw the boundary lines. The boundary lines of each cell depend on the position. Several alternatives had to be explored before this solution was found.
The first major challenge was finding documentation on versions of GTK+ that include Cairo. There were three steps that resolved this issue. First, I found and carefully studied Davyd Madeley’s article on writing widgets using Cairo. Next, I bookmarked and frequently referred to the HTML documents in /usr/share/gtk-doc/html on my GNU/Linux development machine. Finally, the key step was to expand the three source tarballs that make up GTK+ and create an Emacs TAGS file for all the C source and header files. I found the sources extremely helpful, and they adhere to a consistent style, which aids navigating them.
Porting GTK Sudoku
GTK Sudoku is built using the GNU Build Tools (also known as Autotools). Almost all that you have to do to make your system aware of GTK+ is add the following to your configure.ac file
AM_PATH_GTK_2_0(2.8.0,, [AC_MSG_ERROR([Cannot find GTK+])])
and also add
to your Makefile.am.
The use of the GNU Build Tools made it trivial to move GTK Sudoku to different GNU/Linux distributions, including one that runs on an Intel Mac. On the Mac I installed the version of X11 that came with the machine and used DarwinPorts to install GTK2. GTK Sudoku then builds as it does on GNU/Linux. Writing one’s own portfile is also quite easy. In addition to filling in the required fields one only need add:
Porting GTK Sudoku to Windows was challenging. Creating a GTK+ development environment on top of MinGW and MSYS is quite different than doing so for the other GUI frameworks that I have used. For example, with FLTK one can download the sources and easily build and install the framework. Being able to build from the sources allows you to statically link your application, easing deployment. In constrast, GTK+ depends on a number of packages that are not part of the standard MinGW or MSYS runtime environment. Assembling a development environment from precompiled binaries is painful enough to cause one to avoid using the sources. Additionally, there are technical reasons that make it very difficult to build an environment that allows static linking of GTK+ applications. As a result many developers simply download the collection of archives made available by Tor Lillqvist. This distribution is of great use to newcomers, and is something that I am thankful for. There are, however, difficulties to be overcome when using this distribution.
When moving to Windows, it is more difficult to port a GTK+ application than it is to port an FLTK or wxWindows application. If you follow the recommendations in the FLTK and wxWidgets documentation, your build system will work unmodified on all systems, including MSYS. On MSYS the link command requires the -mwindows option, which is added by the GUI framework’s configure script; however, the GTK+ configure script omits the -mwindows option on MSYS. I dealt with this problem by simply adding the flag to my local copy of /usr/local/lib/pkgconfig/gdk-2.0.pc.
Packaging GTK Sudoku for Windows presented the greatest challenge. For Windows, there is an installer for GTK+ version 2.8.18, which places a collection of DLLs and support files in C:Program FilesCommon FilesGTK2.0. The current Windows development environment provides version 2.8.20. It turns out you can run a GTK Sudoku binary created with GTK+ 2.8.20 using a GTK+ 2.8.18 runtime if you add to your source file a definition of the function g_type_register_static_simple, a function added to GTK+ after version 2.8.18. What a hack, no?
The GTK Sudoku Windows installer is close to the LuaForge 10MB limit in file size. This is because I had to include all the files in the GTK+ 2.8.18 installer into the GTK Sudoku installer. If you install GTK+ 2.8.18 into the Common File area, some other GTK applications, for example Gaim, stop working.
Once you place the runtime in your installer you can change its components. Tor Lillqvist tells me that the better solution to my runtime linking problem would have been to update its version of GLib to 2.12.
In summary I was very impressed with GTK+ and especially with Cairo; however, porting the GTK+ application to Windows proved challenging, but not insurmountable. It just takes perseverance.