Slowly but surely...Publish date: June 25, 2007
Tags: mono winforms xulbrowser
… things end up working.
The last blog entry spoke of a successful embedding of xulrunner into a mono winforms app, on windows, and I had hoped that one or two days later I would be blogging about it working on linux as well. Unfortunately, it turned out not to be as simple as that. It actually turned out to be really complicated.
First, while on windows I only had to feed xulrunner with the windows hwnd handle and voilá, it worked, on linux xulrunner uses gtk by default. The xlib xulrunner would be quite nice to use, as it would hopefully be just like windows, feed it a winforms handle and that’s that. Unfortunately, the xlib xulrunner code has been bitrotting for quite some time, and would not work at all. :/
The Gtk adventure
Getting gtk to use a winforms handle to draw in was quite an interesting challenge in itself - it was essentially the same as getting gtk to draw in an x window (since winforms handles are essentially xid’s). There are a couple of different ways to go about the problem; either use the concept of socket/plug by calling gtk_plug_new on a xid and then adding widgets to that to later pass on to xulrunner to draw in, or using gdk_window_foreign_new to “import” the xid.
gtk_plug_new creates a new GtkWidget, while gdk_window_foreign_new gives you a GdkWindow. The first would seem to be easier to get into xulrunner, as it requires passing in a GtkWidget, but it also requires reparenting the window (because the plug doesn’t actually do that, it assumes the xid has a socket attached - which it hasn’t, since it comes from winforms).
The second gives you a GdkWindow, which doesn’t actually help much when you really want a GtkWidget and simple code. I ended up building a custom widget to wrap around an X handle, following the line of the gtkwin32embed widget that comes with gtk, so I went for the second option. The widget works wonderfully, no need for extra reparenting, no need for top level windows (since the widget is a window), just create it with the xid and you’re in business! :)
Winforms application calling the new xulbrowser library to display an
embedded xulrunner engine (mozilla)
Those pesky initializations
What really made me bang my head on the walls was the fact that no matter what I did, the browser seemed to stop in the middle of loading and just stay there indefinitely! I did everything to the code; debugged it, traced it, #ifdef’d it, went step by step checking every call, every event, everything, and nothing, it refused to work! That damned loading icon kept mocking me!
To cut a long story short, after spending hours and hours and days and days on it, I finally found out that the problem was, I wasn’t initializing a thing called AppShell. This AppShell (which is a frozen interface, but is not actually a part of the sdk - so you’d think it wasn’t all that important, hmm?) initializes gtk on the browser so the browser widget can receive events (you’d think one gtk initialization was enough, sheesh!…)
It also seems to be an absolutely useless interface on windows, since the original code works perfectly fine and it actually catches events without it. So it’s a linux only thing, as far as I can tell. Completely undocumented. Unless, of course, someone tells me that it was perfectly obvious that it needed to be there, since gtkmozembed uses it. Of course, gtkmozembed also uses a ton of private calls that are supposedly completely off-limits to us external embedding folks and that would probably earn me a ton of griefing if I actually thought of using them, but hey, I’m supposed to know the difference between an off-limits-never-use-or-we’ll-send-the-mob-after-you calls, and absolute-mandatory-linux-only-initialization-calls-on-non-sdk-interfaces… right?
It’s a good thing I’m a certified nutcase and I actually have fun solving these little problems. And it’s not like I don’t have solid walls or anything. :)
So, for your amusement, here’s a couple of shots (ok, ok, one here and one above) of a Mono Winforms application running a control with an embedded xulrunner-powered browser inside.
Gratuitous use of Xgl to show off my nice Suse desktop with a Mono Winforms
app embedding a mozilla browser (phew!)