2010-01-18

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 (gitorious 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)
{
QT_WIDGET_ASSERT(w)
w->setContentsMargins(spacing,spacing,spacing,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...

22 Comments:

At 12:24 PM, Blogger Il Lunatico said...

It seems a good job but (and I don't want this to sound critic) I don't understand why should someone use gtk over qt?

 
At 12:27 PM, Blogger Johan Thelin said...

legacy?

 
At 12:45 PM, Anonymous Anonymous said...

GTK+ does have action based menus as well:

http://library.gnome.org/devel/gtk/stable/Actions.html

 
At 12:46 PM, Blogger Johan Thelin said...

Cool, I wonder if that is where it'll all backfire. I've not used GTK since the 1.x days, so I'm not fully up to date. That is why I'm using the tutorial as starting point.

 
At 1:14 PM, Anonymous Anonymous said...

Sry, why should someone use this. I see no scenario to use this...
Mixing gui-apis is never a good idea.

Have you an problem that could solved by this?

 
At 1:18 PM, Anonymous Anonymous said...

Well, it's not as if GTK+ had not evolved since 1.x.

By looking at the reference I think your plan is an extremely huge effort:
http://library.gnome.org/devel/gtk/unstable/

Modern GTK+ apps usually use GtkBuilder to load their UI. So the important part is not the widget creation and layout, but their functionality.

And what about widgets or functionality that have no equivalent in Qt like GtkExpander?

Are you also planning to map GLib/GIO to QtCore?
http://library.gnome.org/devel/glib/stable/
http://library.gnome.org/devel/gio/stable/
GTK+ apps use them for their core functionality.

And what about widgets or functionality that have no equivalent in Qt like GtkExpander?

 
At 1:41 PM, Blogger Johan Thelin said...

As for purpose - the original one was just for fun, and to see if it can be done.

A possible purpose would be as a migration/integration kit. Perhaps for bringing old legacy GTK user interfaces up to date.

As for GtkBuilder, GIO and GLib. The focus, in these early stages, would be the GTK+ API, and the parts of GLib that are necessary.

As I've stated before, the aim is not to replace GTK or to discourage anyone from using it. It is more of an experiment.

 
At 1:56 PM, Anonymous Anonymous said...

Calling GTK+ code legacy code is a typical presumptuous Qt developer misconception. ;)

 
At 2:24 PM, Blogger Erwan said...

Maybe I have found a purpose to this project : as I am a KDE user, I am often disturbed by GTK applications which don't look like my Qt theme. Of course there are some GTK themes which may approch, but nothing perfect. If you can set Qt as GTK's rendering engine (or something like that), then all my applications would naturally fit my desktop.
Am I right ?

 
At 2:55 PM, Blogger Johan Thelin said...

Ok, legacy code depending on GTK+ :-)

As for looks, I don't think that this will make GTK applications fit better into a KDE environment, nor the other way around. I strive to replicate the layout engine of GTK, so lots of setContentsMargin(0,0,0,0), etc.

 
At 3:14 PM, Anonymous Anonymous said...

Well, if it's *real* legacy code it won't get better with Qt widgets. The code will still be the same.

However, I don't want do discourage you from your experiments. :) It's interesting.

 
At 3:16 PM, Blogger Johan Thelin said...

A rewrite might be man years. Migrating it gradually could mean that one could keep adding features during that period, thus making it at all feasable attempting to upgrade.

 
At 4:37 PM, OpenID The User said...

Well, why is there qt3to4?
This tool could help to port gtk-apps to Qt/KDE.
The User

 
At 4:54 PM, Anonymous David said...

If you're planning on doing something like this, it would probably be more useful to maintain the same ABI. This would no doubt be harder (you're not allowed to change public-facing structs or macros), but then you wouldn't need to recompile everything.

Also, widgets and code implemented in terms of other already ported code you might get for free.

 
At 5:27 PM, OpenID randomguy3 said...

For your QT_WIDGET_ASSERT:

http://qt.nokia.com/doc/4.6/qobject.html#isWidgetType

 
At 5:36 PM, Anonymous Anonymous said...

Interesting, however I don't understand why someone would use Qt over Gtk+

 
At 7:29 PM, Blogger andreas.huesgen said...

Hi Johan,

this project is for sure quiet ambitious, but it could be worth the effort. I think there is a lot of unseen potential in it.

 
At 7:54 PM, Blogger Johan Thelin said...

@randomguy3: I need a QWidget pointer, so it does not help much.

 
At 10:30 PM, Anonymous Tobias Klein said...

You're quite a hacker, I guess.... You have my respect for doing this stuff... do you plan to do a wrapper library combined a howto, which could be used to "port" gtk applications to use Qt?

 
At 1:00 AM, Blogger mariuz said...

Like i said on twitter I see a future where all #gtk apps are migrated to #QT

there are many good applications that i would love to be migrated to qt api

For example i love lxde and i would love an lxde based on qt and using more qt applications

I think revolutions are done in small invisible steps
and this will help many people who hate actual
gnome direction : mono ...

 
At 7:55 AM, Anonymous Anonymous said...

Have you considered providing a libgtk-x11.so implemented with Qt like this? Then it would actually be possible to run existing applications as more-or-less native Qt applications.

 
At 7:57 AM, Blogger Johan Thelin said...

Implementing the actual so, and maintaining ABI compatibility, would be down right impossible. At least with the current approach (one would have to attack lower in the API stack).

 

Post a Comment

<< Home