18 Jan 2010 e8johan   » (Journeyer)

Qt as GTK, again

Another set of night hours spent hacking on making the GTK API wrap Qt. I focused on adding functionality and not on cleaning up, so no code this time either. I just want to show the progress.

Wrapping Qt in GTK might seem like an impossible task, but the fact is that both toolkits, in turn, wrap the same APIs themselves. So, how does the progress look this far?

Upgraded Hello World (link)

The first example, upgraded hello world, works like a charm and does what is expected. There is only one change that has to be made to the example, and the need for it will go away when I've started cleaning the code.

Changes made to the example:
  • Replaced the gtk/gtk.h headerfile with my substitute.
Table Packing Example (link)

The next example, table packing, simply demonstrates the grid layout abilities of GTK. There seems to be a couple of pixels between the rows for some reason (I will investigate at a later point), but apart from that, everything works. The changes made are the same as for the first example.

Changes made to the example:
  • Replaced the gtk/gtk.h header with my substitute.
Manual Menu Example (link)

Robin Burchell (w00t) has attempted something similar in the gqt project (gitorius link). We will discuss how we can join forces ASAP (I've been sort of unavailable this weekend). The gqt project has clean code - look great. It employs a different approach than I when it comes to mapping signals/slots/events and for handling the construction of menus.

Robin mentioned that one of the major hurdles when mapping the APIs is that GTK uses a widget based structure for menus, while Qt uses QActions for menu items. To have a swing at this, I decided to attack the manual menu example next. It took some changes to the main approach of the wrapping effort, but now I think I have it sorted out.

Changes made to the example:
  • Replaces the gtk/gtk.h header file with my substitute.
  • The popup is always shown at (100, 100) as the GdkEvent structure cannot be cast to a GdkEventButton structure.
Manual Menu Example

Another benefit of doing the manual menu example was that I had to have a better look at the events mechanism. As it seems, the "event" signal hooks into all events (like a Qt event filter). This means that there has to be a general event filter, as well as specific event filters (for when connecting to a specific event such as "delete_event"). This kind of breaks my idea of splitting out the code for creating a specific GdkEvent for each type of event in a separate class, so I need to think a bit about that (shouldn't really be a major issue - I just don't want code duplication).

Back to the menu widget versus action approach. As it seems, the QAction and QWidget classes' common base is the QObject class. Thus all pointers to GtkWidget, GtkWindow, etc. needs to be pointers to QObject. That way, the menu object can be made to match quite nicely. The downside is that the code already contained quite a lot of casts. Now it has even more. For instance, a trivial function such as gtk_container_set_border_width needs casting:

void gtk_container_set_border_width(QObject *o_w, int spacing)

The QT_WIDGET_ASSERT macro creates a QWidget pointer named w, by casting o_w using qobject_cast and then asserts that the pointer isn't null. I'm not sure of the performance penalty of this, but I guess there is one. However, to compensate, all of GTK's GTK_WINDOW, GTK_BOX, etc. are instead defined as simple pass-through macros. This means that performance wise it is a race between GTK_CHECK_CAST and qobject_cast.

I did consider putting the qobject_cast calls in the GTK_xxx macros, but that would not work. For instance, gtk_menu_shell_append can place a QAction in either a QMenu, or in a QMenuBar. As the function is given a QObject pointer, it can now determine (by casting) if the container is a QMenu or QMenuBar and act accordingly.

So, where to next? I belive in fixing the known bugs before continuing. Especially when working on a project such as this, which I suspect will backfire anytime soon (it has been too easy this far). This means that the next step is to do something about the GdkEvent structures to get the popup of the manual menu example to work properly (now it appears at a static location). After that? Cleaning and merging with gqt...

Syndicated 2010-01-18 08:19:00 from Life of a Developer

Latest blog entries     Older blog entries

New Advogato Features

New HTML Parser: The long-awaited libxml2 based HTML parser code is live. It needs further work but already handles most markup better than the original parser.

Keep up with the latest Advogato features by reading the Advogato status blog.

If you're a C programmer with some spare time, take a look at the mod_virgule project page and help us with one of the tasks on the ToDo list!